diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..a7184f71b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,9 @@ +# These are supported funding model platforms + +# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: lakritzator +patreon: # Replace with a single Patreon username +open_collective: greenshot +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://getgreenshot.org/support/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..1f5ca2f11 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to report a bug for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/BUGS/issues/filter=allopenissues + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Example steps to reproduce the behavior: +1. Capture '....' +2. Open Editor +3. Add a line +4. Resize + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - Greenshot version + - Windows version + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/developer-bug-report.md b/.github/ISSUE_TEMPLATE/developer-bug-report.md new file mode 100644 index 000000000..1ffa7da1e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/developer-bug-report.md @@ -0,0 +1,33 @@ +--- +name: Developer Bug report +about: Create a bug report to help us improve our code +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to report a bug for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/BUGS/issues/filter=allopenissues + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Example steps to reproduce the behavior: +1. Capture '....' +2. Open Editor +3. Add a line +4. Resize + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - Greenshot version + - Windows version + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/developer-feature-request.md b/.github/ISSUE_TEMPLATE/developer-feature-request.md new file mode 100644 index 000000000..883534a57 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/developer-feature-request.md @@ -0,0 +1,22 @@ +--- +name: Developer feature request +about: Suggest an technical idea for this project +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to request a feature for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/FEATURE/issues/filter=allopenissues + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..64323a13d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to request a feature for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/FEATURE/issues/filter=allopenissues + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/purge-cloudflare-cache.yml b/.github/workflows/purge-cloudflare-cache.yml new file mode 100644 index 000000000..a2d288faf --- /dev/null +++ b/.github/workflows/purge-cloudflare-cache.yml @@ -0,0 +1,14 @@ +name: Purge CloudFlare Cache + +on: + page_build: + +jobs: + purge_cache: + runs-on: ubuntu-latest + steps: + - name: purge + uses: jakejarvis/cloudflare-purge-action@master + env: + CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }} + CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..9a92223ed --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,163 @@ +env: + IS_RELEASE_BRANCH: ${{ startsWith(github.ref, 'refs/heads/release/') }} + BRANCH_NAME: ${{ github.ref_name }} + +name: Build and Deploy + +on: + workflow_dispatch: + push: + branches: + - 'release/1.*' + paths-ignore: + - '.github/**' + - '.gitignore' + - '*.md' + - 'LICENSE' + - 'build-and-deploy.ps1' + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '7.x' + + - name: Restore NuGet packages + run: msbuild src/Greenshot.sln /p:Configuration=Release /restore /t:PrepareForBuild + env: + Box13_ClientId: ${{ secrets.Box13_ClientId }} + Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }} + DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }} + DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }} + Flickr_ClientId: ${{ secrets.Flickr_ClientId }} + Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }} + Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }} + Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }} + Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }} + Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }} + Picasa_ClientId: ${{ secrets.Picasa_ClientId }} + Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }} + + - name: Build and package + run: msbuild src/Greenshot.sln /p:Configuration=Release /t:Rebuild /v:normal + env: + Box13_ClientId: ${{ secrets.Box13_ClientId }} + Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }} + DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }} + DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }} + Flickr_ClientId: ${{ secrets.Flickr_ClientId }} + Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }} + Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }} + Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }} + Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }} + Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }} + Picasa_ClientId: ${{ secrets.Picasa_ClientId }} + Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }} + + - name: Copy Files + run: | + mkdir -p ${{ github.workspace }}/artifacts + cp installer/Greenshot-INSTALLER-*.exe ${{ github.workspace }}/artifacts/ + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: drop + path: ${{ github.workspace }}/artifacts + + deploy: + runs-on: windows-latest + needs: build + + steps: + + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: drop # Name of the artifact uploaded in previous steps + path: drop # Local folder where artifacts are downloaded + + - name: Extract version from file name + if: env.IS_RELEASE_BRANCH == 'true' + id: version_from_filename + run: | + $file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1 + if (-not $file) { + throw "No matching file found in 'drop' directory." + } + if ($file.Name -match "Greenshot-INSTALLER-([\d\.]+)(.*)\.exe") { + echo "version=$($matches[1])" >> $Env:GITHUB_OUTPUT + } else { + throw "Version number could not be extracted from file name: $($file.Name)" + } + shell: pwsh + + - name: Set version from sanitized branch name + if: env.IS_RELEASE_BRANCH != 'true' + id: version_from_branchname + run: | + $branch = "${{ github.ref }}" -replace '^refs/heads/', '' + $sanitized = $branch -replace '[^a-zA-Z0-9._-]', '_' + echo "version=$sanitized" >> $Env:GITHUB_OUTPUT + shell: pwsh + + - name: Set version info + id: version_info + run: | + echo "version=${{ steps.version_from_filename.outputs.version || steps.version_from_branchname.outputs.version }}" >> $GITHUB_OUTPUT + shell: bash + + + - name: Create tag + if: env.IS_RELEASE_BRANCH == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ steps.version_info.outputs.version }}" -m "v${{ steps.version_info.outputs.version }}" + git push origin "v${{ steps.version_info.outputs.version }}" + + - name: Rename installer for non-release branch + if: env.IS_RELEASE_BRANCH != 'true' + run: | + branch="${BRANCH_NAME:-${GITHUB_REF#refs/heads/}}" + sanitized=$(echo "$branch" | sed 's/[^a-zA-Z0-9._-]/_/g') + mv drop/Greenshot-INSTALLER-*.exe "drop/Greenshot-INSTALLER-${sanitized}.exe" + shell: bash + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: "Greenshot ${{ steps.version_info.outputs.version }} (continuous build)" + tag_name: ${{ env.IS_RELEASE_BRANCH == 'true' && format('v{0}', steps.version_info.outputs.version) || env.BRANCH_NAME }} + files: drop/*.exe + generate_release_notes: true + draft: ${{ env.IS_RELEASE_BRANCH != 'true' }} + prerelease: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Trigger GitHub Pages rebuild + shell: bash + run: | + curl -X POST \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pages/builds + diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml new file mode 100644 index 000000000..ba45b70d1 --- /dev/null +++ b/.github/workflows/update-gh-pages.yml @@ -0,0 +1,18 @@ +name: Update GitHub Pages + +on: + workflow_dispatch: + release: + types: [published, unpublished, created, edited, deleted, prereleased, released] + +jobs: + update-gh-pages: + runs-on: ubuntu-latest + steps: + - name: Trigger GitHub Pages rebuild + shell: bash + run: | + curl -X POST \ + -H "Authorization: Bearer ${{ secrets.GH_PAGES_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pages/builds diff --git a/.gitignore b/.gitignore index 2f5969501..7e96d5501 100644 --- a/.gitignore +++ b/.gitignore @@ -211,4 +211,9 @@ _Pvt_Extensions/ ModelManifest.xml # Greenshot credentials files -*.credentials.cs \ No newline at end of file +*.credentials.cs + +# Rider files +.idea + +/installer/Greenshot-INSTALLER-*.exe diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..638637e24 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at getgreenshot@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..abf5e0f03 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +The general rule we follow is "use Visual Studio defaults". + +1. We use [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style) braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and it must not be nested in other statement blocks that use braces (See issue [381](https://github.com/dotnet/corefx/issues/381) for examples). +2. We use four spaces of indentation (no tabs). +3. We use `_camelCase` for internal and private fields and use `readonly` where possible. Prefix instance fields with `_`, static fields with `s_` and thread static fields with `t_`. When used on static fields, `readonly` should come after `static` (e.g. `static readonly` not `readonly static`). +4. We avoid `this.` unless absolutely necessary. +5. We always specify the visibility, even if it's the default (e.g. `private string _foo` not `string _foo`). Visibility should be the first modifier (e.g. `public abstract` not `abstract public`). +6. Namespace imports should be specified at the top of the file, *outside* of `namespace` declarations and should be sorted alphabetically. +7. Avoid more than one empty line at any time. For example, do not have two blank lines between members of a type. +8. Avoid spurious free spaces. For example avoid `if (someVar == 0)...`, where the dots mark the spurious free spaces. Consider enabling "View White Space (Ctrl+E, S)" if using Visual Studio, to aid detection. +9. If a file happens to differ in style from these guidelines (e.g. private members are named `m_member` rather than `_member`), the existing style in that file takes precedence. +10. We only use `var` when it's obvious what the variable type is (e.g. `var stream = new FileStream(...)` not `var stream = OpenStandardInput()`). +11. We use language keywords instead of BCL types (e.g. `int, string, float` instead of `Int32, String, Single`, etc) for both type references as well as method calls (e.g. `int.Parse` instead of `Int32.Parse`). See issue [391](https://github.com/dotnet/corefx/issues/391) for examples. +12. We use PascalCasing to name all our constant local variables and fields. The only exception is for interop code where the constant value should exactly match the name and value of the code you are calling via interop. +13. We use ```nameof(...)``` instead of ```"..."``` whenever possible and relevant. +14. Fields should be specified at the top within type declarations. +15. When including non-ASCII characters in the source code use Unicode escape sequences (\uXXXX) instead of literal characters. Literal non-ASCII characters occasionally get garbled by a tool or editor. +16. Do not use labels (e.g. for goto). diff --git a/Greenshot/App.config b/Greenshot/App.config deleted file mode 100644 index 61ebd6224..000000000 --- a/Greenshot/App.config +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs deleted file mode 100644 index 61bdc0733..000000000 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace Greenshot.Configuration { - /// - /// Description of CoreConfiguration. - /// - [IniSection("Editor", Description="Greenshot editor configuration")] - public class EditorConfiguration : IniSection { - [IniProperty("RecentColors", Separator="|", Description="Last used colors")] - public List RecentColors { get; set; } - - [IniProperty("LastFieldValue", Separator="|", Description="Field values, make sure the last used settings are re-used")] - public Dictionary LastUsedFieldValues { get; set; } - - [IniProperty("MatchSizeToCapture", Description="Match the editor window size to the capture", DefaultValue="True")] - public bool MatchSizeToCapture { get; set; } - [IniProperty("WindowPlacementFlags", Description="Placement flags", DefaultValue="0")] - public WindowPlacementFlags WindowPlacementFlags { get; set; } - [IniProperty("WindowShowCommand", Description="Show command", DefaultValue="Normal")] - public ShowWindowCommand ShowWindowCommand { get; set; } - [IniProperty("WindowMinPosition", Description="Position of minimized window", DefaultValue="-1,-1")] - public Point WindowMinPosition { get; set; } - [IniProperty("WindowMaxPosition", Description="Position of maximized window", DefaultValue="-1,-1")] - public Point WindowMaxPosition { get; set; } - [IniProperty("WindowNormalPosition", Description="Position of normal window", DefaultValue="100,100,400,400")] - public Rectangle WindowNormalPosition { get; set; } - [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] - public bool ReuseEditor { get; set; } - [IniProperty("FreehandSensitivity", Description = "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", DefaultValue = "3")] - public int FreehandSensitivity { get; set; } - [IniProperty("SuppressSaveDialogAtClose", Description="Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue="False")] - public bool SuppressSaveDialogAtClose { get; set; } - - [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")] - public DropShadowEffect DropShadowEffectSettings { get; set; } - - [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] - public TornEdgeEffect TornEdgeEffectSettings { get; set; } - - public override void AfterLoad() { - base.AfterLoad(); - if (RecentColors == null) { - RecentColors = new List(); - } - } - - /// Type of the class for which to create the field - /// FieldType of the field to construct - /// - /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope - public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) - { - string requestingTypeName = requestingType.Name; - string requestedField = requestingTypeName + "." + fieldType.Name; - object fieldValue = preferredDefaultValue; - - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - - // Check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - // Check if a value is set (not null)! - if (LastUsedFieldValues[requestedField] != null) { - fieldValue = LastUsedFieldValues[requestedField]; - } else { - // Overwrite null value - LastUsedFieldValues[requestedField] = fieldValue; - } - } else { - LastUsedFieldValues.Add(requestedField, fieldValue); - } - return new Field(fieldType, requestingType) - { - Value = fieldValue - }; - } - - public void UpdateLastFieldValue(IField field) - { - string requestedField = field.Scope + "." + field.FieldType.Name; - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - // check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - LastUsedFieldValues[requestedField] = field.Value; - } else { - LastUsedFieldValues.Add(requestedField, field.Value); - } - } - - public void ResetEditorPlacement() - { - WindowNormalPosition = new Rectangle(100, 100, 400, 400); - WindowMaxPosition = new Point(-1,-1); - WindowMinPosition = new Point(-1, -1); - WindowPlacementFlags = 0; - ShowWindowCommand = ShowWindowCommand.Normal; - } - - public WindowPlacement GetEditorPlacement() { - WindowPlacement placement = WindowPlacement.Default; - placement.NormalPosition = new RECT(WindowNormalPosition); - placement.MaxPosition = new POINT(WindowMaxPosition); - placement.MinPosition = new POINT(WindowMinPosition); - placement.ShowCmd = ShowWindowCommand; - placement.Flags = WindowPlacementFlags; - return placement; - } - - public void SetEditorPlacement(WindowPlacement placement) { - WindowNormalPosition = placement.NormalPosition.ToRectangle(); - WindowMaxPosition = placement.MaxPosition.ToPoint(); - WindowMinPosition = placement.MinPosition.ToPoint(); - ShowWindowCommand = placement.ShowCmd; - WindowPlacementFlags = placement.Flags; - } - } -} diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs deleted file mode 100644 index 08f982374..000000000 --- a/Greenshot/Configuration/LanguageKeys.cs +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.CodeAnalysis; - -namespace Greenshot.Configuration { - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum LangKey { - none, - about_bugs, - about_donations, - about_host, - about_icons, - about_license, - about_title, - about_translation, - application_title, - bugreport_cancel, - bugreport_info, - bugreport_title, - clipboard_error, - clipboard_inuse, - colorpicker_alpha, - colorpicker_apply, - colorpicker_blue, - colorpicker_green, - colorpicker_htmlcolor, - colorpicker_recentcolors, - colorpicker_red, - colorpicker_title, - colorpicker_transparent, - config_unauthorizedaccess_write, - contextmenu_about, - contextmenu_capturearea, - contextmenu_captureclipboard, - contextmenu_capturefullscreen, - contextmenu_capturefullscreen_all, - contextmenu_capturefullscreen_left, - contextmenu_capturefullscreen_top, - contextmenu_capturefullscreen_right, - contextmenu_capturefullscreen_bottom, - contextmenu_capturelastregion, - contextmenu_capturewindow, - contextmenu_donate, - contextmenu_exit, - contextmenu_help, - contextmenu_openfile, - contextmenu_quicksettings, - contextmenu_settings, - contextmenu_captureie, - contextmenu_openrecentcapture, - editor_align_bottom, - editor_align_center, - editor_align_horizontal, - editor_align_middle, - editor_align_left, - editor_align_right, - editor_align_top, - editor_align_vertical, - editor_arrange, - editor_arrowheads, - editor_arrowheads_both, - editor_arrowheads_end, - editor_arrowheads_none, - editor_arrowheads_start, - editor_backcolor, - editor_blur_radius, - editor_bold, - editor_brightness, - editor_cancel, - editor_clipboardfailed, - editor_close, - editor_close_on_save, - editor_close_on_save_title, - editor_confirm, - editor_copyimagetoclipboard, - editor_copypathtoclipboard, - editor_copytoclipboard, - editor_crop, - editor_cursortool, - editor_cuttoclipboard, - editor_deleteelement, - editor_downonelevel, - editor_downtobottom, - editor_drawarrow, - editor_drawellipse, - editor_drawhighlighter, - editor_drawline, - editor_drawfreehand, - editor_drawrectangle, - editor_drawtextbox, - editor_duplicate, - editor_edit, - editor_email, - editor_file, - editor_fontsize, - editor_forecolor, - editor_highlight_area, - editor_highlight_grayscale, - editor_highlight_mode, - editor_highlight_text, - editor_highlight_magnify, - editor_pixel_size, - editor_imagesaved, - editor_italic, - editor_load_objects, - editor_magnification_factor, - editor_match_capture_size, - editor_obfuscate, - editor_obfuscate_blur, - editor_obfuscate_mode, - editor_obfuscate_pixelize, - editor_object, - editor_opendirinexplorer, - editor_pastefromclipboard, - editor_preview_quality, - editor_print, - editor_save, - editor_save_objects, - editor_saveas, - editor_selectall, - editor_senttoprinter, - editor_shadow, - editor_torn_edge, - editor_border, - editor_grayscale, - editor_effects, - editor_storedtoclipboard, - editor_thickness, - editor_title, - editor_uponelevel, - editor_uptotop, - editor_autocrop, - editor_undo, - editor_redo, - editor_insertwindow, - editor_resetsize, - error, - error_multipleinstances, - error_nowriteaccess, - error_openfile, - error_openlink, - error_save, - error_save_invalid_chars, - help_title, - jpegqualitydialog_choosejpegquality, - qualitydialog_dontaskagain, - qualitydialog_title, - settings_reducecolors, - print_error, - printoptions_allowcenter, - printoptions_allowenlarge, - printoptions_allowrotate, - printoptions_allowshrink, - printoptions_colors, - printoptions_dontaskagain, - printoptions_pagelayout, - printoptions_printcolor, - printoptions_printgrayscale, - printoptions_printmonochrome, - printoptions_timestamp, - printoptions_inverted, - printoptions_title, - quicksettings_destination_file, - settings_alwaysshowqualitydialog, - settings_alwaysshowprintoptionsdialog, - settings_applicationsettings, - settings_autostartshortcut, - settings_capture, - settings_capture_mousepointer, - settings_capture_windows_interactive, - settings_copypathtoclipboard, - settings_destination, - settings_destination_clipboard, - settings_destination_editor, - settings_destination_email, - settings_destination_file, - settings_destination_fileas, - settings_destination_printer, - settings_destination_picker, - settings_editor, - settings_filenamepattern, - settings_general, - settings_iecapture, - settings_jpegquality, - settings_qualitysettings, - settings_language, - settings_message_filenamepattern, - settings_output, - settings_playsound, - settings_plugins, - settings_plugins_name, - settings_plugins_version, - settings_plugins_createdby, - settings_plugins_dllpath, - settings_preferredfilesettings, - settings_primaryimageformat, - settings_printer, - settings_printoptions, - settings_registerhotkeys, - settings_showflashlight, - settings_storagelocation, - settings_title, - settings_tooltip_filenamepattern, - settings_tooltip_language, - settings_tooltip_primaryimageformat, - settings_tooltip_registerhotkeys, - settings_tooltip_storagelocation, - settings_visualization, - settings_shownotify, - settings_waittime, - settings_windowscapture, - settings_window_capture_mode, - settings_network, - settings_checkperiod, - settings_usedefaultproxy, - tooltip_firststart, - warning, - warning_hotkeys, - hotkeys, - wait_ie_capture, - update_found, - exported_to - } -} diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/Greenshot/Controls/BindableToolStripButton.cs deleted file mode 100644 index 893264403..000000000 --- a/Greenshot/Controls/BindableToolStripButton.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - /// - /// Description of BindableToolStripButton. - /// - public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public BindableToolStripButton() - { - CheckedChanged += BindableToolStripButton_CheckedChanged; - } - - private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked")); - } - } -} diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/Greenshot/Controls/BindableToolStripComboBox.cs deleted file mode 100644 index e6e8ad105..000000000 --- a/Greenshot/Controls/BindableToolStripComboBox.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - /// - /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding - /// - public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public BindableToolStripComboBox() - { - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - } - - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem")); - } - } -} diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs deleted file mode 100644 index 4a04e1f23..000000000 --- a/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - /// - /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. - /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image. - /// The selected tag can be accessed via SelectedTag property. - /// - public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public object SelectedTag { - get { if(Tag==null && DropDownItems.Count>0) Tag=DropDownItems[0].Tag; return Tag; } - set { AdoptFromTag(value); } - } - - protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e) { - ToolStripItem clickedItem = e.ClickedItem; - if(Tag == null || !Tag.Equals(clickedItem.Tag)) { - Tag = clickedItem.Tag; - Image = clickedItem.Image; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - base.OnDropDownItemClicked(e); - } - - private void AdoptFromTag(object tag) { - if(Tag == null || !Tag.Equals(tag)) { - Tag = tag; - foreach(ToolStripItem item in DropDownItems) { - if(item.Tag != null && item.Tag.Equals(tag)) { - Image = item.Image; - break; - } - } - Tag = tag; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - } - } -} diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs deleted file mode 100644 index 935729732..000000000 --- a/Greenshot/Controls/ColorButton.cs +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - /// - /// Description of ColorButton. - /// - public class ColorButton : Button, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - private Color _selectedColor = Color.White; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public ColorButton() { - Click += ColorButtonClick; - } - - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; - - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } - - if (Image != null) - { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(4,17,16,3)); - } - - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } - - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} diff --git a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs deleted file mode 100644 index 5031f82bb..000000000 --- a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Core; -using System.Drawing; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace Greenshot.Controls { - /// - /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger - /// - public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static Image _scaledCheckbox; - - protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) { - if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) { - _scaledCheckbox?.Dispose(); - _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); - } - Rectangle old = e.ImageRectangle; - ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); - base.OnRenderItemCheck(clone); - } - } -} diff --git a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs deleted file mode 100644 index cb851ea2f..000000000 --- a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// Prevent having a gradient background in the toolstrip, and the overflow button - /// See: http://stackoverflow.com/a/16926979 - /// - internal class CustomProfessionalColorTable : ProfessionalColorTable { - public override Color ToolStripGradientBegin { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientMiddle { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientEnd { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientBegin { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientMiddle { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientEnd { - get { return SystemColors.Control; } - } - } - - /// - /// ToolStripProfessionalRenderer without having a visual artifact - /// See: http://stackoverflow.com/a/16926979 and http://stackoverflow.com/a/13418840 - /// - public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable()) { - RoundedEdges = false; - } - /// - /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border - /// - /// - protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) { - // Don't draw a border - } - } -} diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs deleted file mode 100644 index dc5975be3..000000000 --- a/Greenshot/Controls/FontFamilyComboBox.cs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; -using System.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// ToolStripComboBox containing installed font families, - /// implementing INotifyPropertyChanged for data binding - /// - public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; - - public FontFamily FontFamily { - get { return (FontFamily)SelectedItem; } - set { - if (!SelectedItem.Equals(value)) { - SelectedItem = value; - } - } - } - - public FontFamilyComboBox() - { - if (ComboBox != null) - { - ComboBox.DataSource = FontFamily.Families; - ComboBox.DisplayMember = "Name"; - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - ComboBox.DrawMode = DrawMode.OwnerDrawFixed; - ComboBox.DrawItem += ComboBox_DrawItem; - } - } - - private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) { - // DrawBackground handles drawing the background (i.e,. hot-tracked v. not) - // It uses the system colors (Bluish, and and white, by default) - // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds ); - e.DrawBackground(); - - if (e.Index > -1) { - FontFamily fontFamily = Items[e.Index] as FontFamily; - FontStyle fontStyle = FontStyle.Regular; - if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular)) { - if (fontFamily.IsStyleAvailable(FontStyle.Bold)) { - fontStyle = FontStyle.Bold; - } else if (fontFamily.IsStyleAvailable(FontStyle.Italic)) { - fontStyle = FontStyle.Italic; - } else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout)) { - fontStyle = FontStyle.Strikeout; - } else if (fontFamily.IsStyleAvailable(FontStyle.Underline)) { - fontStyle = FontStyle.Underline; - } - } - try { - if (fontFamily != null) - { - DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name); - } - } catch { - // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular' - if (fontFamily != null) - { - DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name); - } - } - } - // Uncomment this if you actually like the way the focus rectangle looks - //e.DrawFocusRectangle (); - } - - /// - /// Helper method to draw the string - /// - /// - /// - /// - /// - /// - private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) - { - using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); - // Make sure the text is visible by centering it in the line - using StringFormat stringFormat = new StringFormat - { - LineAlignment = StringAlignment.Center - }; - graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat); - } - - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) { - if (PropertyChanged == null) return; - PropertyChanged(this, new PropertyChangedEventArgs("Text")); - PropertyChanged(this, new PropertyChangedEventArgs("FontFamily")); - PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex")); - PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); - } - } -} diff --git a/Greenshot/Controls/MenuStripEx.cs b/Greenshot/Controls/MenuStripEx.cs deleted file mode 100644 index ea973a791..000000000 --- a/Greenshot/Controls/MenuStripEx.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace Greenshot.Controls { - /// - /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - public class MenuStripEx : MenuStrip { - private const int WM_MOUSEACTIVATE = 0x21; - - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } - - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// - public bool ClickThrough { - get { - return _clickThrough; - } - - set { - _clickThrough = value; - } - } - - protected override void WndProc(ref Message m) { - base.WndProc(ref m); - var windowsMessage = (WindowsMessages) m.Msg; - if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) - { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/Greenshot/Controls/NonJumpingPanel.cs deleted file mode 100644 index 51658a105..000000000 --- a/Greenshot/Controls/NonJumpingPanel.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -namespace GreenshotPlugin.Controls { - /// - /// See: http://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/ - /// - public class NonJumpingPanel : Panel { - protected override Point ScrollToControl(Control activeControl) { - // Returning the current location prevents the panel from - // scrolling to the active control when the panel loses and regains focus - return DisplayRectangle.Location; - } - - /// - /// Add horizontal scrolling to the panel, when using the wheel and the shift key is pressed - /// - /// MouseEventArgs - protected override void OnMouseWheel(MouseEventArgs e) - { - if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift) - { - VScroll = false; - base.OnMouseWheel(e); - VScroll = true; - } - else - { - base.OnMouseWheel(e); - } - } - } -} diff --git a/Greenshot/Controls/Pipette.cs b/Greenshot/Controls/Pipette.cs deleted file mode 100644 index bbe2b5686..000000000 --- a/Greenshot/Controls/Pipette.cs +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; -using System.Windows.Forms; -using Greenshot.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace Greenshot.Controls { - /// - /// This code was supplied by Hi-Coder as a patch for Greenshot - /// Needed some modifications to be stable. - /// - public sealed class Pipette : Label, IMessageFilter, IDisposable { - private MovableShowColorForm _movableShowColorForm; - private bool _dragging; - private Cursor _cursor; - private readonly Bitmap _image; - private const int VkEsc = 27; - - public event EventHandler PipetteUsed; - - public Pipette() { - BorderStyle = BorderStyle.FixedSingle; - _dragging = false; - _image = (Bitmap)new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image"); - Image = _image; - _cursor = CreateCursor(_image, 1, 14); - _movableShowColorForm = new MovableShowColorForm(); - Application.AddMessageFilter(this); - } - - /// - /// Create a cursor from the supplied bitmap & hotspot coordinates - /// - /// Bitmap to create an icon from - /// Hotspot X coordinate - /// Hotspot Y coordinate - /// Cursor - private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) - { - using SafeIconHandle iconHandle = new SafeIconHandle( bitmap.GetHicon()); - User32.GetIconInfo(iconHandle, out var iconInfo); - iconInfo.xHotspot = hotspotX; - iconInfo.yHotspot = hotspotY; - iconInfo.fIcon = false; - var icon = User32.CreateIconIndirect(ref iconInfo); - return new Cursor(icon); - } - - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// - public new void Dispose() { - Dispose(true); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - if (disposing) { - if (_cursor != null) { - _cursor.Dispose(); - } - _movableShowColorForm?.Dispose(); - } - _movableShowColorForm = null; - _cursor = null; - base.Dispose(disposing); - } - - /// - /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location - /// - /// MouseEventArgs - protected override void OnMouseDown(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - User32.SetCapture(Handle); - _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); - } - base.OnMouseDown(e); - } - - /// - /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event - /// - /// MouseEventArgs - protected override void OnMouseUp(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) - { - //Release Capture should consume MouseUp when canceled with the escape key - User32.ReleaseCapture(); - PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); - } - base.OnMouseUp(e); - } - - /// - /// Handle the mouse Move event, we move the ColorUnderCursor to the current location. - /// - /// MouseEventArgs - protected override void OnMouseMove(MouseEventArgs e) { - if (_dragging) { - //display the form on the right side of the cursor by default; - Point zp = PointToScreen(new Point(e.X, e.Y)); - _movableShowColorForm.MoveTo(zp); - } - base.OnMouseMove(e); - } - - /// - /// Handle the MouseCaptureChanged event - /// - /// - protected override void OnMouseCaptureChanged(EventArgs e) { - if (Capture) { - _dragging = true; - Image = null; - Cursor c = _cursor; - Cursor = c; - _movableShowColorForm.Visible = true; - } else { - _dragging = false; - Image = _image; - Cursor = Cursors.Arrow; - _movableShowColorForm.Visible = false; - } - Update(); - base.OnMouseCaptureChanged(e); - } - - public bool PreFilterMessage(ref Message m) { - if (_dragging) { - if (m.Msg == (int)WindowsMessages.WM_CHAR) { - if ((int)m.WParam == VkEsc) { - User32.ReleaseCapture(); - } - } - } - return false; - } - } - - public class PipetteUsedArgs : EventArgs { - public Color Color; - - public PipetteUsedArgs(Color c) { - Color = c; - } - } -} diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs deleted file mode 100644 index 706a54cf3..000000000 --- a/Greenshot/Controls/ToolStripColorButton.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - private Color _selectedColor = Color.Transparent; - - public ToolStripColorButton() { - Click+= ColorButtonClick; - } - - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; - - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } - - if (Image != null) - { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(0,13,16,3)); - } - - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } - - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} diff --git a/Greenshot/Controls/ToolStripEx.cs b/Greenshot/Controls/ToolStripEx.cs deleted file mode 100644 index b3f669fdd..000000000 --- a/Greenshot/Controls/ToolStripEx.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - internal class ToolStripEx : ToolStrip { - private const int WM_MOUSEACTIVATE = 0x21; - - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } - - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// - - public bool ClickThrough { - get { - return _clickThrough; - } - - set { - _clickThrough = value; - } - } - - protected override void WndProc(ref Message m) { - base.WndProc(ref m); - if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/Greenshot/Controls/ToolStripNumericUpDown.cs deleted file mode 100644 index 2cb53314b..000000000 --- a/Greenshot/Controls/ToolStripNumericUpDown.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Windows.Forms; -using System.Windows.Forms.Design; - -namespace Greenshot.Controls { - - [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] - public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - public ToolStripNumericUpDown() : base(new NumericUpDown()) - { - } - - public NumericUpDown NumericUpDown => Control as NumericUpDown; - - public decimal Value - { - get { return NumericUpDown.Value; } - set { NumericUpDown.Value = value;} - } - public decimal Minimum { - get { return NumericUpDown.Minimum; } - set { NumericUpDown.Minimum = value; } - } - - public decimal Maximum { - get { return NumericUpDown.Maximum; } - set { NumericUpDown.Maximum = value; } - } - - public decimal Increment { - get { return NumericUpDown.Increment; } - set { NumericUpDown.Increment = value; } - } - - public int DecimalPlaces { - get { return NumericUpDown.DecimalPlaces; } - set { NumericUpDown.DecimalPlaces = value; } - } - - - protected override void OnSubscribeControlEvents(Control control) { - base.OnSubscribeControlEvents(control); - NumericUpDown.ValueChanged += _valueChanged; - } - protected override void OnUnsubscribeControlEvents(Control control) { - base.OnUnsubscribeControlEvents(control); - NumericUpDown.ValueChanged -= _valueChanged; - } - - private void _valueChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } -} diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs deleted file mode 100644 index 9cfb0aec5..000000000 --- a/Greenshot/Destinations/ClipboardDestination.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of ClipboardDestination. - /// - public class ClipboardDestination : AbstractDestination { - public const string DESIGNATION = "Clipboard"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_clipboard); - } - } - public override int Priority { - get { - return 2; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.C; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Clipboard.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - try { - ClipboardHelper.SetClipboardData(surface); - exportInformation.ExportMade = true; - } catch (Exception) { - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs deleted file mode 100644 index 09cce0f56..000000000 --- a/Greenshot/Destinations/EditorDestination.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Forms; -using log4net; - -namespace Greenshot.Destinations { - /// - /// Description of EditorDestination. - /// - public class EditorDestination : AbstractDestination { - private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination)); - private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); - public const string DESIGNATION = "Editor"; - private readonly IImageEditor editor; - private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); - - public EditorDestination() { - } - - public EditorDestination(IImageEditor editor) { - this.editor = editor; - } - - public override string Designation => DESIGNATION; - - public override string Description { - get { - if (editor == null) { - return Language.GetString(LangKey.settings_destination_editor); - } - return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; - } - } - - public override int Priority => 1; - - public override bool IsDynamic => true; - - public override Image DisplayIcon => greenshotIcon; - - public override IEnumerable DynamicDestinations() { - foreach (IImageEditor someEditor in ImageEditorForm.Editors) { - yield return new EditorDestination(someEditor); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Make sure we collect the garbage before opening the screenshot - GC.Collect(); - GC.WaitForPendingFinalizers(); - - bool modified = surface.Modified; - if (editor == null) { - if (editorConfiguration.ReuseEditor) { - foreach(IImageEditor openedEditor in ImageEditorForm.Editors) { - if (openedEditor.Surface.Modified) continue; - - openedEditor.Surface = surface; - exportInformation.ExportMade = true; - break; - } - } - if (!exportInformation.ExportMade) { - try { - ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made?? - - if (!string.IsNullOrEmpty(captureDetails.Filename)) { - editorForm.SetImagePath(captureDetails.Filename); - } - editorForm.Show(); - editorForm.Activate(); - LOG.Debug("Finished opening Editor"); - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - } else { - try { - using (Image image = surface.GetImageForExport()) { - editor.Surface.AddImageContainer(image, 10, 10); - } - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - ProcessExport(exportInformation, surface); - // Workaround for the modified flag when using the editor. - surface.Modified = modified; - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs deleted file mode 100644 index abda77c7c..000000000 --- a/Greenshot/Destinations/EmailDestination.cs +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of EmailDestination. - /// - public class EmailDestination : AbstractDestination { - private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); - private static bool _isActiveFlag; - private static string _mapiClient; - public const string DESIGNATION = "EMail"; - - static EmailDestination() { - // Logic to decide what email implementation we use - if (!EmailConfigHelper.HasMapi()) return; - - _isActiveFlag = false; - _mapiClient = EmailConfigHelper.GetMapiClient(); - if (!string.IsNullOrEmpty(_mapiClient)) { - // Active as we have a mapi client, can be disabled later - _isActiveFlag = true; - } - } - - public override string Designation => DESIGNATION; - - public override string Description { - get - { - // Make sure there is some kind of "mail" name - return _mapiClient ??= Language.GetString(LangKey.editor_email); - } - } - - public override int Priority => 3; - - public override bool IsActive { - get { - if (_isActiveFlag) { - // Disable if the office plugin is installed and the client is outlook - // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( - Type outlookdestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin"); - if (outlookdestination != null) { - if (_mapiClient.ToLower().Contains("microsoft outlook")) { - _isActiveFlag = false; - } - } - } - return base.IsActive && _isActiveFlag; - } - } - - public override Keys EditorShortcutKeys => Keys.Control | Keys.E; - - public override Image DisplayIcon => MailIcon; - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - MapiMailMessage.SendImage(surface, captureDetails); - exportInformation.ExportMade = true; - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} \ No newline at end of file diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs deleted file mode 100644 index 559d28135..000000000 --- a/Greenshot/Destinations/FileDestination.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.IO; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Controls; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using log4net; - -namespace Greenshot.Destinations { - /// - /// Description of FileSaveAsDestination. - /// - public class FileDestination : AbstractDestination { - private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileNoDialog"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.quicksettings_destination_file); - - public override int Priority => 0; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.S; - - public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool outputMade; - bool overwrite; - string fullPath; - // Get output settings from the configuration - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); - - if (captureDetails?.Filename != null) { - // As we save a pre-selected file, allow to overwrite. - overwrite = true; - Log.InfoFormat("Using previous filename"); - fullPath = captureDetails.Filename; - outputSettings.Format = ImageOutput.FormatForFilename(fullPath); - } else { - fullPath = CreateNewFilename(captureDetails); - // As we generate a file, the configuration tells us if we allow to overwrite - overwrite = CoreConfig.OutputFileAllowOverwrite; - } - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - try { - ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - outputMade = true; - } catch (ArgumentException ex1) { - // Our generated filename exists, display 'save-as' - Log.InfoFormat("Not overwriting: {0}", ex1.Message); - // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } catch (Exception ex2) { - Log.Error("Error saving screenshot!", ex2); - // Show the problem - MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } - // Don't overwrite filename if no output is made - if (outputMade) { - exportInformation.ExportMade = true; - exportInformation.Filepath = fullPath; - if (captureDetails != null) - { - captureDetails.Filename = fullPath; - } - CoreConfig.OutputFileAsFullpath = fullPath; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - - private static string CreateNewFilename(ICaptureDetails captureDetails) { - string fullPath; - Log.InfoFormat("Creating new filename"); - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern)) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); - CoreConfig.ValidateAndCorrectOutputFilePath(); - string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); - try { - fullPath = Path.Combine(filepath, filename); - } catch (ArgumentException) { - // configured filename or path not valid, show error message... - Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); - - MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); - // ... lets get the pattern fixed.... - var dialogResult = new SettingsForm().ShowDialog(); - if (dialogResult == DialogResult.OK) { - // ... OK -> then try again: - fullPath = CreateNewFilename(captureDetails); - } else { - // ... cancelled. - fullPath = null; - } - - } - return fullPath; - } - } -} diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs deleted file mode 100644 index e211d14f7..000000000 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of FileWithDialog. - /// - public class FileWithDialogDestination : AbstractDestination { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileDialog"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_fileas); - } - } - - public override int Priority { - get { - return 0; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.S; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Save.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); - if (savedTo != null) { - exportInformation.ExportMade = true; - exportInformation.Filepath = savedTo; - captureDetails.Filename = savedTo; - conf.OutputFileAsFullpath = savedTo; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/PickerDestination.cs b/Greenshot/Destinations/PickerDestination.cs deleted file mode 100644 index 26f8fbfb5..000000000 --- a/Greenshot/Destinations/PickerDestination.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one - /// - public class PickerDestination : AbstractDestination { - public const string DESIGNATION = "Picker"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.settings_destination_picker); - - public override int Priority => 1; - - - /// - /// Export the capture with the destination picker - /// - /// Did the user select this destination? - /// Surface to export - /// Details of the capture - /// true if export was made - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - List destinations = new List(); - - foreach(var destination in SimpleServiceProvider.Current.GetAllInstances()) { - if ("Picker".Equals(destination.Designation)) { - continue; - } - if (!destination.IsActive) { - continue; - } - destinations.Add(destination); - } - - // No Processing, this is done in the selected destination (if anything was selected) - return ShowPickerMenu(true, surface, captureDetails, destinations); - } - } -} diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs deleted file mode 100644 index e2156256b..000000000 --- a/Greenshot/Destinations/PrinterDestination.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing.Printing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of PrinterDestination. - /// - public class PrinterDestination : AbstractDestination { - public const string DESIGNATION = "Printer"; - private readonly string _printerName; - - public PrinterDestination() { - } - - public PrinterDestination(string printerName) { - _printerName = printerName; - } - public override string Designation => DESIGNATION; - - public override string Description { - get { - if (_printerName != null) { - return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; - } - return Language.GetString(LangKey.settings_destination_printer); - } - } - - public override int Priority => 2; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.P; - - public override Image DisplayIcon => GreenshotResources.GetImage("Printer.Image"); - - public override bool IsDynamic => true; - - /// - /// Create destinations for all the installed printers - /// - /// IEnumerable of IDestination - public override IEnumerable DynamicDestinations() { - PrinterSettings settings = new PrinterSettings(); - string defaultPrinter = settings.PrinterName; - List printers = new List(); - - foreach (string printer in PrinterSettings.InstalledPrinters) { - printers.Add(printer); - } - printers.Sort(delegate(string p1, string p2) { - if(defaultPrinter.Equals(p1)) { - return -1; - } - if(defaultPrinter.Equals(p2)) { - return 1; - } - return string.Compare(p1, p2, StringComparison.Ordinal); - }); - foreach(string printer in printers) { - yield return new PrinterDestination(printer); - } - } - - /// - /// Export the capture to the printer - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - PrinterSettings printerSettings; - if (!string.IsNullOrEmpty(_printerName)) - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(_printerName); - } else if (!manuallyInitiated) { - PrinterSettings settings = new PrinterSettings(); - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(settings.PrinterName); - } else - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintWithDialog(); - } - if (printerSettings != null) { - exportInformation.ExportMade = true; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs deleted file mode 100644 index 0612753aa..000000000 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * 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 1 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.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing.Adorners -{ - public class AbstractAdorner : IAdorner - { - public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - - protected Size _size = new Size(4, 4); - - public AbstractAdorner(IDrawableContainer owner) - { - Owner = owner; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public virtual Cursor Cursor - { - get - { - return Cursors.SizeAll; - } - } - - public virtual IDrawableContainer Owner - { - get; - set; - } - - /// - /// Test if the point is inside the adorner - /// - /// - /// - public virtual bool HitTest(Point point) - { - Rectangle hitBounds = Bounds; - hitBounds.Inflate(3, 3); - return hitBounds.Contains(point); - } - - /// - /// Handle the mouse down - /// - /// - /// - public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - } - - /// - /// Handle the mouse move - /// - /// - /// - public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - } - - /// - /// Handle the mouse up - /// - /// - /// - public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.IDLE; - } - - /// - /// Return the location of the adorner - /// - public virtual Point Location - { - get; - set; - } - - /// - /// Return the bounds of the Adorner - /// - public virtual Rectangle Bounds - { - get - { - Point location = Location; - return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); - } - } - - /// - /// The adorner is active if the edit status is not idle or undrawn - /// - public virtual bool IsActive - { - get - { - return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; - } - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public virtual void Paint(PaintEventArgs paintEventArgs) - { - } - - /// - /// We ignore the Transform, as the coordinates are directly bound to those of the owner - /// - /// - public virtual void Transform(Matrix matrix) - { - } - } -} diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs deleted file mode 100644 index ec3dcf2d3..000000000 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * 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 1 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 Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This is the adorner for the line based containers - /// - public class MoveAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; - - public Positions Position { get; private set; } - - public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor => Cursors.SizeAll; - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); - - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; - - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); - - Owner.Invalidate(); - } - - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = Bounds; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.SmoothingMode = SmoothingMode.None; - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - targetGraphics.PixelOffsetMode = PixelOffsetMode.Half; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - - try - { - targetGraphics.FillRectangle(Brushes.Black, bounds.X, bounds.Y, bounds.Width, bounds.Height); - } - catch - { - // Ignore, BUG-2065 - } - targetGraphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs deleted file mode 100644 index e75126f10..000000000 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * 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 1 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 Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble - /// - public class ResizeAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; - - public Positions Position { get; private set; } - - public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor - { - get - { - bool isNotSwitched = Owner.Width >= 0; - if (Owner.Height < 0) - { - isNotSwitched = !isNotSwitched; - } - switch (Position) - { - case Positions.TopLeft: - case Positions.BottomRight: - return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; - case Positions.TopRight: - case Positions.BottomLeft: - return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; - case Positions.MiddleLeft: - case Positions.MiddleRight: - return Cursors.SizeWE; - case Positions.TopCenter: - case Positions.BottomCenter: - return Cursors.SizeNS; - default: - return Cursors.SizeAll; - } - } - } - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); - - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; - - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); - - Owner.Invalidate(); - } - - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = Bounds; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.SmoothingMode = SmoothingMode.None; - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - targetGraphics.PixelOffsetMode = PixelOffsetMode.Half; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - - targetGraphics.FillRectangle(Brushes.Black, bounds.X, bounds.Y, bounds.Width , bounds.Height); - targetGraphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs deleted file mode 100644 index 8ca0a91ef..000000000 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * 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 1 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.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This implements the special "gripper" for the Speech-Bubble tail - /// - public class TargetAdorner : AbstractAdorner - { - - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) - { - Location = location; - } - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.MOVING; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.MOVING) - { - return; - } - - Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle surfaceBounds = new Rectangle(0, 0, Owner.Parent.Width, Owner.Parent.Height); - // Check if gripper inside the parent (surface), if not we need to move it inside - // This was made for BUG-1682 - if (!surfaceBounds.Contains(newGripperLocation)) - { - if (newGripperLocation.X > surfaceBounds.Right) - { - newGripperLocation.X = surfaceBounds.Right - 5; - } - if (newGripperLocation.X < surfaceBounds.Left) - { - newGripperLocation.X = surfaceBounds.Left; - } - if (newGripperLocation.Y > surfaceBounds.Bottom) - { - newGripperLocation.Y = surfaceBounds.Bottom - 5; - } - if (newGripperLocation.Y < surfaceBounds.Top) - { - newGripperLocation.Y = surfaceBounds.Top; - } - } - - Location = newGripperLocation; - Owner.Invalidate(); - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = Bounds; - targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); - } - - /// - /// Made sure this adorner is transformed - /// - /// Matrix - public override void Transform(Matrix matrix) - { - if (matrix == null) - { - return; - } - Point[] points = new[] { Location }; - matrix.TransformPoints(points); - Location = points[0]; - } - } -} diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs deleted file mode 100644 index 739f9d430..000000000 --- a/Greenshot/Drawing/ArrowContainer.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing2D; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class ArrowContainer : LineContainer { - public enum ArrowHeadCombination { NONE, START_POINT, END_POINT, BOTH }; - - private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); - - public ArrowContainer(Surface parent) : base(parent) { - } - - /// - /// Do not use the base, just override so we have our own defaults - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.ARROWHEADS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - - if (lineThickness > 0 ) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - SetArrowHeads(heads, shadowCapPen); - - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); - - currentStep++; - alpha -= basealpha / steps; - } - - } - - using Pen pen = new Pen(lineColor, lineThickness); - SetArrowHeads(heads, pen); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); - } - } - } - - private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) { - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) { - pen.CustomStartCap = ARROW_CAP; - } - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) { - pen.CustomEndCap = ARROW_CAP; - } - } - - public override Rectangle DrawingBounds { - get { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - using Matrix matrix = new Matrix(); - Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen)); - drawingBounds.Inflate(2, 2); - return drawingBounds; - } - return Rectangle.Empty; - } - } - - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs deleted file mode 100644 index 2dc9761c0..000000000 --- a/Greenshot/Drawing/CropContainer.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Runtime.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of CropContainer. - /// - public class CropContainer : DrawableContainer { - public CropContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - protected override void InitializeFields() { - AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); - } - - public override void Invalidate() { - _parent?.Invalidate(); - } - - /// - /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw - /// (we create a transparent brown over the complete picture) - /// - public override Rectangle DrawingBounds => new Rectangle(0,0,_parent?.Width??0, _parent?.Height ?? 0); - - public override void Draw(Graphics g, RenderMode rm) { - if (_parent == null) - { - return; - } - - using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); - Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); - - DrawSelectionBorder(g, selectionRect); - - // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, _parent.Width, cropRectangle.Top)); - // left - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); - // right - g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); - // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height))); - } - - public override bool HasContextMenu { - get { - // No context menu for the CropContainer - return false; - } - } - } -} diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs deleted file mode 100644 index 5558508a8..000000000 --- a/Greenshot/Drawing/CursorContainer.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.IO; -using System.Windows.Forms; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of CursorContainer. - /// - [Serializable] - public class CursorContainer : DrawableContainer, ICursorContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer)); - - protected Cursor cursor; - - public CursorContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - public CursorContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } - - public Cursor Cursor { - set { - if (cursor != null) { - cursor.Dispose(); - } - // Clone cursor (is this correct??) - cursor = new Cursor(value.CopyHandle()); - Width = value.Size.Width; - Height = value.Size.Height; - } - get { return cursor; } - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - if (cursor != null) { - cursor.Dispose(); - } - } - cursor = null; - base.Dispose(disposing); - } - - public void Load(string filename) { - if (!File.Exists(filename)) { - return; - } - - using Cursor fileCursor = new Cursor(filename); - Cursor = fileCursor; - LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - if (cursor == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.None; - cursor.DrawStretched(graphics, Bounds); - } - - public override Size DefaultSize { - get { - return cursor.Size; - } - } - } -} diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs deleted file mode 100644 index 8d805b1f0..000000000 --- a/Greenshot/Drawing/DrawableContainer.cs +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using Greenshot.Drawing.Adorners; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Interfaces.Drawing; -using log4net; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing -{ - /// - /// represents a rectangle, ellipse, label or whatever. Can contain filters, too. - /// serializable for clipboard support - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); - protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private const int M11 = 0; - private const int M22 = 3; - - [OnDeserialized] - private void OnDeserializedInit(StreamingContext context) - { - _adorners = new List(); - OnDeserialized(context); - } - - /// - /// Override to implement your own deserialization logic, like initializing properties which are not serialized - /// - /// - protected virtual void OnDeserialized(StreamingContext streamingContext) - { - } - - protected EditStatus _defaultEditMode = EditStatus.DRAWING; - public EditStatus DefaultEditMode { - get { - return _defaultEditMode; - } - } - - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - if (!disposing) { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); - } - - ~DrawableContainer() { - Dispose(false); - } - - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add { _propertyChanged += value; } - remove{ _propertyChanged -= value; } - } - - public IList Filters { - get { - List ret = new List(); - foreach(IFieldHolder c in Children) { - if (c is IFilter) { - ret.Add(c as IFilter); - } - } - return ret; - } - } - - [NonSerialized] - internal Surface _parent; - public ISurface Parent { - get { return _parent; } - set { SwitchParent((Surface)value); } - } - - [NonSerialized] - private TargetAdorner _targetAdorner; - public TargetAdorner TargetAdorner { - get { - return _targetAdorner; - } - } - - [NonSerialized] - private bool _selected; - public bool Selected { - get {return _selected;} - set { - _selected = value; - OnPropertyChanged("Selected"); - } - } - - [NonSerialized] - private EditStatus _status = EditStatus.UNDRAWN; - public EditStatus Status { - get { - return _status; - } - set { - _status = value; - } - } - - - private int left; - public int Left { - get { return left; } - set { - if (value == left) { - return; - } - left = value; - } - } - - private int top; - public int Top { - get { return top; } - set { - if (value == top) { - return; - } - top = value; - } - } - - private int width; - public int Width { - get { return width; } - set { - if (value == width) { - return; - } - width = value; - } - } - - private int height; - public int Height { - get { return height; } - set { - if (value == height) { - return; - } - height = value; - } - } - - public Point Location { - get { - return new Point(left, top); - } - set { - left = value.X; - top = value.Y; - } - } - - public Size Size { - get { - return new Size(width, height); - } - set { - width = value.Width; - height = value.Height; - } - } - - /// - /// List of available Adorners - /// - [NonSerialized] - private IList _adorners = new List(); - public IList Adorners - { - get - { - return _adorners; - } - } - - [NonSerialized] - // will store current bounds of this DrawableContainer before starting a resize - protected Rectangle _boundsBeforeResize = Rectangle.Empty; - - [NonSerialized] - // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) - protected RectangleF _boundsAfterResize = RectangleF.Empty; - - public Rectangle Bounds { - get { return GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); } - set { - Left = Round(value.Left); - Top = Round(value.Top); - Width = Round(value.Width); - Height = Round(value.Height); - } - } - - public virtual void ApplyBounds(RectangleF newBounds) { - Left = Round(newBounds.Left); - Top = Round(newBounds.Top); - Width = Round(newBounds.Width); - Height = Round(newBounds.Height); - } - - public DrawableContainer(Surface parent) { - InitializeFields(); - _parent = parent; - } - - public void Add(IFilter filter) { - AddChild(filter); - } - - public void Remove(IFilter filter) { - RemoveChild(filter); - } - - private static int Round(float f) { - if(float.IsPositiveInfinity(f) || f>int.MaxValue/2) return int.MaxValue/2; - if (float.IsNegativeInfinity(f) || f - /// Initialize a target gripper - /// - protected void InitAdorner(Color gripperColor, Point location) { - _targetAdorner = new TargetAdorner(this, location); - Adorners.Add(_targetAdorner); - } - - /// - /// Create the default adorners for a rectangle based container - /// - - protected void CreateDefaultAdorners() { - if (Adorners.Count > 0) - { - LOG.Warn("Adorners are already defined!"); - } - // Create the GripperAdorners - Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); - } - - public bool hasFilters { - get { - return Filters.Count > 0; - } - } - - public abstract void Draw(Graphics graphics, RenderMode renderMode); - - public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) { - if (Children.Count > 0) { - if (Status != EditStatus.IDLE) { - DrawSelectionBorder(graphics, Bounds); - } else { - if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { - foreach(IFilter filter in Filters) { - if (filter.Invert) { - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); - drawingRect.Intersect(clipRectangle); - if(filter is MagnifierFilter) { - // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially - // what we should actually do to resolve this is add a better magnifier which is not that special - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - filter.Apply(graphics, bmp, drawingRect, renderMode); - } - } - } - } - - } - } - Draw(graphics, renderMode); - } - - public virtual bool Contains(int x, int y) { - return Bounds.Contains(x , y); - } - - public virtual bool ClickableAt(int x, int y) { - Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - r.Inflate(5, 5); - return r.Contains(x, y); - } - - protected void DrawSelectionBorder(Graphics g, Rectangle rect) - { - using Pen pen = new Pen(Color.MediumSeaGreen) - { - DashPattern = new float[] { 1, 2 }, - Width = 1 - }; - g.DrawRectangle(pen, rect); - } - - - public void ResizeTo(int width, int height, int anchorPosition) { - Width = width; - Height = height; - } - - /// - /// Make a following bounds change on this drawablecontainer undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); - } - - public void MoveBy(int dx, int dy) { - Left += dx; - Top += dy; - } - - /// - /// A handler for the MouseDown, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseDown(int x, int y) { - Left = _boundsBeforeResize.X = x; - Top = _boundsBeforeResize.Y = y; - return true; - } - - /// - /// A handler for the MouseMove, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseMove(int x, int y) { - Invalidate(); - - // reset "workrbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; - - ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); - - // apply scaled bounds to this DrawableContainer - ApplyBounds(_boundsAfterResize); - - Invalidate(); - return true; - } - - /// - /// A handler for the MouseUp - /// - /// current mouse x - /// current mouse y - public virtual void HandleMouseUp(int x, int y) { - } - - protected virtual void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); - - _parent = newParent; - foreach(IFilter filter in Filters) { - filter.Parent = this; - } - } - - protected void OnPropertyChanged(string propertyName) { - if (_propertyChanged != null) { - _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - Invalidate(); - } - } - - /// - /// This method will be called before a field is changes. - /// Using this makes it possible to invalidate the object as is before changing. - /// - /// The field to be changed - /// The new value - public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) { - _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); - Invalidate(); - } - - /// - /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) - /// - /// - /// - public void HandleFieldChanged(object sender, FieldChangedEventArgs e) { - LOG.DebugFormat("Field {0} changed", e.Field.FieldType); - if (Equals(e.Field.FieldType, FieldType.SHADOW)) { - accountForShadowChange = true; - } - } - - /// - /// Retrieve the Y scale from the matrix - /// - /// - /// - public static float CalculateScaleY(Matrix matrix) { - return matrix.Elements[M22]; - } - - /// - /// Retrieve the X scale from the matrix - /// - /// - /// - public static float CalculateScaleX(Matrix matrix) { - return matrix.Elements[M11]; - } - - /// - /// Retrieve the rotation angle from the matrix - /// - /// - /// - public static int CalculateAngle(Matrix matrix) { - const int M11 = 0; - const int M21 = 2; - var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]); - return (int)-Math.Round(radians * 180 / Math.PI); - } - - /// - /// This method is called on a DrawableContainers when: - /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly. - /// 2) Currently not implemented: an element needs to be moved, scaled or rotated. - /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated. - /// But this implementation doesn't take care of any changes to the content!! - /// - /// - public virtual void Transform(Matrix matrix) { - if (matrix == null) { - return; - } - Point topLeft = new Point(Left, Top); - Point bottomRight = new Point(Left + Width, Top + Height); - Point[] points = new[] { topLeft, bottomRight }; - matrix.TransformPoints(points); - - Left = points[0].X; - Top = points[0].Y; - Width = points[1].X - points[0].X; - Height = points[1].Y - points[0].Y; - - } - - protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.ShapeAngleRoundBehavior.Instance; - } - - public virtual bool HasContextMenu { - get { - return true; - } - } - - public virtual bool HasDefaultSize { - get { - return false; - } - } - - public virtual Size DefaultSize { - get { - throw new NotSupportedException("Object doesn't have a default size"); - } - } - - /// - /// Allows to override the initializing of the fields, so we can actually have our own defaults - /// - protected virtual void InitializeFields() { - } - } -} \ No newline at end of file diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs deleted file mode 100644 index d3c325f5b..000000000 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Threading; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Drawing { - /// - /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. - /// - [Serializable] - public class DrawableContainerList : List, IDrawableContainerList - { - private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); - - public Guid ParentID { - get; - private set; - } - - public DrawableContainerList() { - } - - public DrawableContainerList(Guid parentId) { - ParentID = parentId; - } - - public EditStatus Status { - get { - return this[Count-1].Status; - } - set { - foreach (var dc in this) { - dc.Status = value; - } - } - } - - public List AsIDrawableContainerList() { - List interfaceList = new List(); - foreach(IDrawableContainer container in this) { - interfaceList.Add(container); - } - return interfaceList; - } - - /// - /// Gets or sets the selection status of the elements. - /// If several elements are in the list, true is only returned when all elements are selected. - /// - public bool Selected { - get { - bool ret = true; - foreach(var dc in this) { - ret &= dc.Selected; - } - return ret; - } - set { - foreach(var dc in this) { - dc.Selected = value; - } - } - } - - /// - /// Gets or sets the parent control of the elements in the list. - /// If there are several elements, the parent control of the last added is returned. - /// - public ISurface Parent { - get { - if (Count > 0) { - return this[Count-1].Parent; - } - return null; - } - set { - ParentID = value?.ID ?? Guid.NewGuid(); - foreach (var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.Parent = value; - } - } - } - - /// - /// Make a following bounds change on this containerlist undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - if (Count > 0 && Parent != null) - { - var clone = new DrawableContainerList(); - clone.AddRange(this); - Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); - } - } - - /// - /// Apply matrix to all elements - /// - public void Transform(Matrix matrix) { - // Track modifications - bool modified = false; - Invalidate(); - foreach (var dc in this) { - dc.Transform(matrix); - modified = true; - } - // Invalidate after - Invalidate(); - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } - - /// - /// Moves all elements in the list by the given amount of pixels. - /// - /// pixels to move horizontally - /// pixels to move vertically - public void MoveBy(int dx, int dy) { - // Track modifications - bool modified = false; - - // Invalidate before moving, otherwise the old locations aren't refreshed - Invalidate(); - foreach(var dc in this) { - dc.Left += dx; - dc.Top += dy; - modified = true; - } - // Invalidate after - Invalidate(); - - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } - - /// - /// Indicates whether on of the elements is clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// true if one of the elements in the list is clickable at the given location, false otherwise - public bool ClickableAt(int x, int y) { - bool ret = false; - foreach(var dc in this) { - ret |= dc.ClickableAt(x, y); - } - return ret; - } - - /// - /// retrieves the topmost element being clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// the topmost element from the list being clickable at the given location, null if there is no clickable element - public IDrawableContainer ClickableElementAt(int x, int y) { - for (int i=Count-1; i>=0; i--) { - if (this[i].ClickableAt(x,y)) { - return this[i]; - } - } - return null; - } - - /// - /// Dispatches OnDoubleClick to all elements in the list. - /// - public void OnDoubleClick() { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.OnDoubleClick(); - } - } - - /// - /// Check if there are any intersecting filters, if so we need to redraw more - /// - /// - /// true if an filter intersects - public bool HasIntersectingFilters(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) { - return true; - } - } - return false; - } - - /// - /// Check if any of the drawableContainers are inside the rectangle - /// - /// - /// - public bool IntersectsWith(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) { - return true; - } - } - return false; - } - - /// - /// Triggers all elements in the list ot be redrawn. - /// - /// the to the bitmap related Graphics object - /// Bitmap to draw - /// the rendermode in which the element is to be drawn - /// - public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) { - if (Parent == null) - { - return; - } - foreach (var drawableContainer in this) - { - var dc = (DrawableContainer)drawableContainer; - if (dc.Parent == null) - { - continue; - } - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) - { - dc.DrawContent(g, bitmap, renderMode, clipRectangle); - } - } - } - - /// - /// Pass the field changed event to all elements in the list - /// - /// - /// - public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e) { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.HandleFieldChanged(sender, e); - } - } - - /// - /// Invalidate the bounds of all the DC's in this list - /// - public void Invalidate() { - if (Parent == null) - { - return; - } - Rectangle region = Rectangle.Empty; - foreach (var dc in this) - { - region = Rectangle.Union(region, dc.DrawingBounds); - } - Parent.Invalidate(region); - } - /// - /// Indicates whether the given list of elements can be pulled up, - /// i.e. whether there is at least one unselected element higher in hierarchy - /// - /// list of elements to pull up - /// true if the elements could be pulled up - public bool CanPullUp(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) < Count - elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pulls one or several elements up one level in hierarchy (z-index). - /// - /// list of elements to pull up - public void PullElementsUp(IDrawableContainerList elements) { - for(int i=Count-1; i>=0; i--) { - var dc = this[i]; - if (!elements.Contains(dc)) { - continue; - } - if (Count > i+1 && !elements.Contains(this[i+1])) { - SwapElements(i,i+1); - } - } - } - - /// - /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index). - /// - /// of elements to pull to top - public void PullElementsToTop(IDrawableContainerList elements) - { - var dcs = ToArray(); - foreach (var dc in dcs) - { - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Add(dc); - Parent.Modified = true; - } - } - - /// - /// Indicates whether the given list of elements can be pushed down, - /// i.e. whether there is at least one unselected element lower in hierarchy - /// - /// list of elements to push down - /// true if the elements could be pushed down - public bool CanPushDown(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) >= elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pushes one or several elements down one level in hierarchy (z-index). - /// - /// list of elements to push down - public void PushElementsDown(IDrawableContainerList elements) { - for(int i=0; i0) && !elements.Contains(this[i-1])) { - SwapElements(i,i-1); - } - } - } - - /// - /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index). - /// - /// of elements to push to bottom - public void PushElementsToBottom(IDrawableContainerList elements) { - var dcs = ToArray(); - for(int i=dcs.Length-1; i>=0; i--) { - var dc = dcs[i]; - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Insert(0, dc); - Parent.Modified = true; - } - } - - /// - /// swaps two elements in hierarchy (z-index), - /// checks both indices to be in range - /// - /// index of the 1st element - /// index of the 2nd element - private void SwapElements(int index1, int index2) { - if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2) { - return; - } - var dc = this[index1]; - this[index1] = this[index2]; - this[index2] = dc; - Parent.Modified = true; - } - - /// - /// Add items to a context menu for the selected item - /// - /// - /// - public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) { - bool push = surface.Elements.CanPushDown(this); - bool pull = surface.Elements.CanPullUp(this); - - ToolStripMenuItem item; - - // Pull "up" - if (pull) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop)); - item.Click += delegate { - surface.Elements.PullElementsToTop(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel)); - item.Click += delegate { - surface.Elements.PullElementsUp(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } - // Push "down" - if (push) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom)); - item.Click += delegate { - surface.Elements.PushElementsToBottom(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel)); - item.Click += delegate { - surface.Elements.PushElementsDown(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } - - // Duplicate - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate)); - item.Click += delegate { - IDrawableContainerList dcs = this.Clone(); - dcs.Parent = surface; - dcs.MoveBy(10, 10); - surface.AddElements(dcs); - surface.DeselectAllElements(); - surface.SelectElements(dcs); - }; - menu.Items.Add(item); - - // Copy - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - }; - menu.Items.Add(item); - - // Cut - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("btnCut.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - surface.RemoveElements(this); - }; - menu.Items.Add(item); - - // Delete - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement)) - { - Image = (Image)EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image") - }; - item.Click += delegate { - surface.RemoveElements(this); - }; - menu.Items.Add(item); - - // Reset - bool canReset = false; - foreach (var drawableContainer in this) - { - var container = (DrawableContainer)drawableContainer; - if (container.HasDefaultSize) - { - canReset = true; - } - } - if (canReset) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize)); - //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); - item.Click += delegate { - MakeBoundsChangeUndoable(false); - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasDefaultSize) { - continue; - } - Size defaultSize = container.DefaultSize; - container.MakeBoundsChangeUndoable(false); - container.Width = defaultSize.Width; - container.Height = defaultSize.Height; - } - surface.Invalidate(); - }; - menu.Items.Add(item); - } - } - - public virtual void ShowContextMenu(MouseEventArgs e, ISurface surface) - { - if (!(surface is Surface)) - { - return; - } - bool hasMenu = false; - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasContextMenu) { - continue; - } - hasMenu = true; - break; - } - if (hasMenu) { - ContextMenuStrip menu = new ContextMenuStrip(); - AddContextMenuItems(menu, surface); - if (menu.Items.Count > 0) { - // TODO: cast should be somehow avoided - menu.Show((Surface)surface, e.Location); - while (true) { - if (menu.Visible) { - Application.DoEvents(); - Thread.Sleep(100); - } else { - menu.Dispose(); - break; - } - } - } - } - } - - private bool _disposedValue; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - foreach (var drawableContainer in this) - { - drawableContainer.Dispose(); - } - } - - _disposedValue = true; - } - } - - // This code added to correctly implement the disposable pattern. - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - } - } -} diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs deleted file mode 100644 index c7a3985d6..000000000 --- a/Greenshot/Drawing/EllipseContainer.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing2D; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of EllipseContainer. - /// - [Serializable()] - public class EllipseContainer : DrawableContainer { - public EllipseContainer(Surface parent) : base(parent) { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } - - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); - } - - /// - /// This allows another container to draw an ellipse - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - // draw shadow before anything else - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) - { - Width = lineVisible ? lineThickness : 1 - }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height); - graphics.DrawEllipse(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - //draw the original shape - if (Colors.IsVisible(fillColor)) - { - using Brush brush = new SolidBrush(fillColor); - graphics.FillEllipse(brush, rect); - } - if (lineVisible) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawEllipse(pen, rect); - } - } - - public override bool Contains(int x, int y) { - return EllipseContains(this, x, y); - } - - /// - /// Allow the code to be used externally - /// - /// - /// - /// - /// - public static bool EllipseContains(DrawableContainer caller, int x, int y) { - double xDistanceFromCenter = x - (caller.Left + caller.Width / 2); - double yDistanceFromCenter = y - (caller.Top + caller.Height / 2); - // ellipse: x^2/a^2 + y^2/b^2 = 1 - return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1; - } - - public override bool ClickableAt(int x, int y) { - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - return EllipseClickableAt(rect, lineThickness, fillColor, x, y); - } - - public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x, y)) { - return true; - } - } - - // check the rest of the lines - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White, lineThickness); - using GraphicsPath path = new GraphicsPath(); - path.AddEllipse(rect); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs deleted file mode 100644 index 561501634..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; -using System.Runtime.Serialization; - -using Greenshot.Configuration; -using GreenshotPlugin.IniFile; -using log4net; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Basic IFieldHolder implementation, providing access to a set of fields - /// - [Serializable] - public abstract class AbstractFieldHolder : IFieldHolder - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder)); - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - [NonSerialized] - private readonly IDictionary _handlers = new Dictionary(); - - /// - /// called when a field's value has changed - /// - [NonSerialized] - private FieldChangedEventHandler _fieldChanged; - - public event FieldChangedEventHandler FieldChanged - { - add { _fieldChanged += value; } - remove { _fieldChanged -= value; } - } - - // we keep two Collections of our fields, dictionary for quick access, list for serialization - // this allows us to use default serialization - [NonSerialized] - private IDictionary _fieldsByType = new Dictionary(); - private readonly IList fields = new List(); - - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - _fieldsByType = new Dictionary(); - // listen to changing properties - foreach (var field in fields) - { - field.PropertyChanged += delegate { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - _fieldsByType[field.FieldType] = field; - } - } - - public void AddField(Type requestingType, IFieldType fieldType, object fieldValue) - { - AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue)); - } - - public virtual void AddField(IField field) - { - fields.Add(field); - if (_fieldsByType == null) - { - return; - } - - if (_fieldsByType.ContainsKey(field.FieldType)) - { - if (LOG.IsDebugEnabled) - { - LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); - } - } - - _fieldsByType[field.FieldType] = field; - - _handlers[field] = (sender, args) => - { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - field.PropertyChanged += _handlers[field]; - } - - public void RemoveField(IField field) - { - fields.Remove(field); - _fieldsByType.Remove(field.FieldType); - field.PropertyChanged -= _handlers[field]; - _handlers.Remove(field); - } - - public IList GetFields() - { - return fields; - } - - - public IField GetField(IFieldType fieldType) - { - try - { - return _fieldsByType[fieldType]; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } - - public object GetFieldValue(IFieldType fieldType) - { - return GetField(fieldType)?.Value; - } - - public string GetFieldValueAsString(IFieldType fieldType) - { - return Convert.ToString(GetFieldValue(fieldType)); - } - - public int GetFieldValueAsInt(IFieldType fieldType) - { - return Convert.ToInt32(GetFieldValue(fieldType)); - } - - public decimal GetFieldValueAsDecimal(IFieldType fieldType) - { - return Convert.ToDecimal(GetFieldValue(fieldType)); - } - - public double GetFieldValueAsDouble(IFieldType fieldType) - { - return Convert.ToDouble(GetFieldValue(fieldType)); - } - - public float GetFieldValueAsFloat(IFieldType fieldType) - { - return Convert.ToSingle(GetFieldValue(fieldType)); - } - - public bool GetFieldValueAsBool(IFieldType fieldType) - { - return Convert.ToBoolean(GetFieldValue(fieldType)); - } - - public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default) - { - return (Color)(GetFieldValue(fieldType) ?? defaultColor); - } - - public bool HasField(IFieldType fieldType) - { - return _fieldsByType.ContainsKey(fieldType); - } - - public bool HasFieldValue(IFieldType fieldType) - { - return HasField(fieldType) && _fieldsByType[fieldType].HasValue; - } - - public void SetFieldValue(IFieldType fieldType, object value) - { - try - { - _fieldsByType[fieldType].Value = value; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } - - protected void OnFieldChanged(object sender, FieldChangedEventArgs e) - { - _fieldChanged?.Invoke(sender, e); - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs deleted file mode 100644 index 636e708e4..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Interfaces.Drawing; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, - /// but has a List of IFieldHolder for children. - /// Field values are passed to and from children as well. - /// - [Serializable] - public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder - { - [NonSerialized] - private readonly FieldChangedEventHandler _fieldChangedEventHandler; - - [NonSerialized] - private EventHandler childrenChanged; - public event EventHandler ChildrenChanged - { - add { childrenChanged += value; } - remove { childrenChanged -= value; } - } - - public IList Children = new List(); - - public AbstractFieldHolderWithChildren() - { - _fieldChangedEventHandler = OnFieldChanged; - } - - [OnDeserialized()] - private void OnDeserialized(StreamingContext context) - { - // listen to changing properties - foreach (IFieldHolder fieldHolder in Children) - { - fieldHolder.FieldChanged += _fieldChangedEventHandler; - } - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public void AddChild(IFieldHolder fieldHolder) - { - Children.Add(fieldHolder); - fieldHolder.FieldChanged += _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public void RemoveChild(IFieldHolder fieldHolder) - { - Children.Remove(fieldHolder); - fieldHolder.FieldChanged -= _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public new IList GetFields() - { - var ret = new List(); - ret.AddRange(base.GetFields()); - foreach (IFieldHolder fh in Children) - { - ret.AddRange(fh.GetFields()); - } - return ret; - } - - public new IField GetField(IFieldType fieldType) - { - IField ret = null; - if (base.HasField(fieldType)) - { - ret = base.GetField(fieldType); - } - else - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = fh.GetField(fieldType); - break; - } - } - } - if (ret == null) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType()); - } - return ret; - } - - public new bool HasField(IFieldType fieldType) - { - bool ret = base.HasField(fieldType); - if (!ret) - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = true; - break; - } - } - } - return ret; - } - - public new bool HasFieldValue(IFieldType fieldType) - { - IField f = GetField(fieldType); - return f != null && f.HasValue; - } - - public new void SetFieldValue(IFieldType fieldType, object value) - { - IField f = GetField(fieldType); - if (f != null) f.Value = value; - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs deleted file mode 100644 index ff3232d2f..000000000 --- a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields.Binding { - /// - /// Basic IBindingConverter implementation - /// - public abstract class AbstractBindingConverter : IBindingConverter - { - public object convert(object o) { - if(o == null) { - return null; - } - if(o is T1) { - return convert((T1)o); - } - if(o is T2) { - return convert((T2)o); - } - throw new ArgumentException("Cannot handle argument of type "+o.GetType()); - } - - protected abstract T2 convert(T1 o); - protected abstract T1 convert(T2 o); - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs deleted file mode 100644 index 28a4bddf0..000000000 --- a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Reflection; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Bidirectional binding of properties of two INotifyPropertyChanged instances. - /// This implementation synchronizes null values, too. If you do not want this - /// behavior (e.g. when binding to a - /// - public class BidirectionalBinding { - private readonly INotifyPropertyChanged _controlObject; - private readonly INotifyPropertyChanged _fieldObject; - private readonly string _controlPropertyName; - private readonly string _fieldPropertyName; - private bool _updatingControl; - private bool _updatingField; - private IBindingConverter _converter; - private readonly IBindingValidator _validator; - - /// - /// Whether or not null values are passed on to the other object. - /// - protected bool AllowSynchronizeNull = true; - - /// - /// Bind properties of two objects bidirectionally - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) { - _controlObject = controlObject; - _fieldObject = fieldObject; - _controlPropertyName = controlPropertyName; - _fieldPropertyName = fieldPropertyName; - - _controlObject.PropertyChanged += ControlPropertyChanged; - _fieldObject.PropertyChanged += FieldPropertyChanged; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _converter = converter; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _validator = validator; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) { - _validator = validator; - } - - public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) { - _updatingField = true; - Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName); - _updatingField = false; - } - } - - public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) { - _updatingControl = true; - Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName); - _updatingControl = false; - } - } - - private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) { - PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty); - PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty); - - if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) { - object bValue = sourcePropertyInfo.GetValue(sourceObject, null); - if (_converter != null && bValue != null) { - bValue = _converter.convert(bValue); - } - try { - if (_validator == null || _validator.validate(bValue)) { - targetPropertyInfo.SetValue(targetObject, bValue, null); - } - } catch (Exception e) { - throw new MemberAccessException("Could not set property '"+targetProperty+"' to '"+bValue+"' ["+(bValue?.GetType().Name ?? string.Empty)+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e); - } - - } - } - - private static PropertyInfo ResolvePropertyInfo(object obj, string property) { - PropertyInfo ret = null; - string[] properties = property.Split(".".ToCharArray()); - for(int i=0; i. - */ -using System; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d - /// - public class DecimalDoublePercentageConverter : AbstractBindingConverter - { - private static DecimalDoublePercentageConverter _uniqueInstance; - - private DecimalDoublePercentageConverter() {} - - protected override decimal convert(double o) { - return Convert.ToDecimal(o)*100; - } - - protected override double convert(decimal o) { - return Convert.ToDouble(o)/100; - } - - public static DecimalDoublePercentageConverter GetInstance() - { - return _uniqueInstance ??= new DecimalDoublePercentageConverter(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs deleted file mode 100644 index b4a4283e4..000000000 --- a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to float and vice versa. - /// - public class DecimalFloatConverter : AbstractBindingConverter - { - private static DecimalFloatConverter _uniqueInstance; - - private DecimalFloatConverter() {} - - protected override decimal convert(float o) { - return Convert.ToDecimal(o); - } - - protected override float convert(decimal o) { - return Convert.ToInt16(o); - } - - public static DecimalFloatConverter GetInstance() - { - return _uniqueInstance ??= new DecimalFloatConverter(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs deleted file mode 100644 index 1a8fcefc3..000000000 --- a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional converter, for use with BidirectionalBinding. - /// convert(object) implementation must deal with both directions. - /// see DecimalIntConverter - /// - public interface IBindingConverter { - object convert(object o); - } - -} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs deleted file mode 100644 index 146b91afb..000000000 --- a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional validator, for use with BidirectionalBinding. - /// Useful if you do not want to synchronize values which would be illegal on - /// one of the bound objects (e.g. null value on some form components) - /// see NotNullValidator - /// - public interface IBindingValidator { - bool validate(object o); - } - -} diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs deleted file mode 100644 index 798444625..000000000 --- a/Greenshot/Drawing/Fields/Field.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Interfaces.Drawing; -using System; -using System.ComponentModel; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Represents a single field of a drawable element, i.e. - /// line thickness of a rectangle. - /// - [Serializable] - public class Field : IField - { - [field: NonSerialized] - public event PropertyChangedEventHandler PropertyChanged; - - private object _myValue; - public object Value - { - get - { - return _myValue; - } - set - { - if (!Equals(_myValue, value)) - { - _myValue = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } - } - public IFieldType FieldType - { - get; - set; - } - public string Scope - { - get; - set; - } - - /// - /// Constructs a new Field instance, usually you should be using FieldFactory - /// to create Fields. - /// - /// FieldType of the Field to be created - /// The scope to which the value of this Field is relevant. - /// Depending on the scope the Field's value may be shared for other elements - /// containing the same FieldType for defaulting to the last used value. - /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value - /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer)) - /// - public Field(IFieldType fieldType, Type scope) - { - FieldType = fieldType; - Scope = scope.Name; - } - public Field(IFieldType fieldType, string scope) - { - FieldType = fieldType; - Scope = scope; - } - public Field(IFieldType fieldType) - { - FieldType = fieldType; - } - /// - /// Returns true if this field holds a value other than null. - /// - public bool HasValue => Value != null; - - /// - /// Creates a flat clone of this Field. The fields value itself is not cloned. - /// - /// - public Field Clone() - { - return new Field(FieldType, Scope) {Value = Value}; - } - - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - hashCode += 1000000009 * FieldType.GetHashCode(); - if (Scope != null) - hashCode += 1000000021 * Scope.GetHashCode(); - } - return hashCode; - } - - public override bool Equals(object obj) - { - if (!(obj is Field other)) - { - return false; - } - return FieldType == other.FieldType && Equals(Scope, other.Scope); - } - - public override string ToString() - { - return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope); - } - } -} diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs deleted file mode 100644 index c22268091..000000000 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using GreenshotPlugin.Interfaces.Drawing; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Represents the current set of properties for the editor. - /// When one of EditorProperties' properties is updated, the change will be promoted - /// to all bound elements. - /// * If an element is selected: - /// This class represents the element's properties - /// * I n>1 elements are selected: - /// This class represents the properties of all elements. - /// Properties that do not apply for ALL selected elements are null (or 0 respectively) - /// If the property values of the selected elements differ, the value of the last bound element wins. - /// - [Serializable] - public sealed class FieldAggregator : AbstractFieldHolder - { - - private readonly IDrawableContainerList _boundContainers; - private bool _internalUpdateRunning; - - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - - public FieldAggregator(ISurface parent) - { - foreach (var fieldType in FieldType.Values) - { - var field = new Field(fieldType, GetType()); - AddField(field); - } - _boundContainers = new DrawableContainerList - { - Parent = parent - }; - } - - public override void AddField(IField field) - { - base.AddField(field); - field.PropertyChanged += OwnPropertyChanged; - } - - public void BindElements(IDrawableContainerList dcs) - { - foreach (var dc in dcs) - { - BindElement(dc); - } - } - - public void BindElement(IDrawableContainer dc) - { - if (!(dc is DrawableContainer container) || _boundContainers.Contains(container)) - { - return; - } - _boundContainers.Add(container); - container.ChildrenChanged += delegate { - UpdateFromBoundElements(); - }; - UpdateFromBoundElements(); - } - - public void BindAndUpdateElement(IDrawableContainer dc) - { - UpdateElement(dc); - BindElement(dc); - } - - public void UpdateElement(IDrawableContainer dc) - { - if (!(dc is DrawableContainer container)) - { - return; - } - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - if (container.HasField(field.FieldType) && field.HasValue) - { - //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); - container.SetFieldValue(field.FieldType, field.Value); - } - } - _internalUpdateRunning = false; - } - - public void UnbindElement(IDrawableContainer dc) - { - if (_boundContainers.Contains(dc)) - { - _boundContainers.Remove(dc); - UpdateFromBoundElements(); - } - } - - public void Clear() - { - ClearFields(); - _boundContainers.Clear(); - UpdateFromBoundElements(); - } - - /// - /// sets all field values to null, however does not remove fields - /// - private void ClearFields() - { - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - field.Value = null; - } - _internalUpdateRunning = false; - } - - /// - /// Updates this instance using the respective fields from the bound elements. - /// Fields that do not apply to every bound element are set to null, or 0 respectively. - /// All other fields will be set to the field value of the least bound element. - /// - private void UpdateFromBoundElements() - { - ClearFields(); - _internalUpdateRunning = true; - foreach (var field in FindCommonFields()) - { - SetFieldValue(field.FieldType, field.Value); - } - _internalUpdateRunning = false; - } - - private IList FindCommonFields() - { - IList returnFields = null; - if (_boundContainers.Count > 0) - { - // take all fields from the least selected container... - if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer) - { - returnFields = leastSelectedContainer.GetFields(); - for (int i = 0; i < _boundContainers.Count - 1; i++) - { - if (!(_boundContainers[i] is DrawableContainer dc)) continue; - IList fieldsToRemove = new List(); - foreach (IField field in returnFields) - { - // ... throw out those that do not apply to one of the other containers - if (!dc.HasField(field.FieldType)) - { - fieldsToRemove.Add(field); - } - } - foreach (var field in fieldsToRemove) - { - returnFields.Remove(field); - } - } - } - } - return returnFields ?? new List(); - } - - public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) - { - IField field = (IField)sender; - if (_internalUpdateRunning || field.Value == null) - { - return; - } - foreach (var drawableContainer1 in _boundContainers.ToList()) - { - var drawableContainer = (DrawableContainer) drawableContainer1; - if (!drawableContainer.HasField(field.FieldType)) - { - continue; - } - IField drawableContainerField = drawableContainer.GetField(field.FieldType); - // Notify before change, so we can e.g. invalidate the area - drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); - - drawableContainerField.Value = field.Value; - // update last used from DC field, so that scope is honored - EditorConfig.UpdateLastFieldValue(drawableContainerField); - } - } - - } -} diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs deleted file mode 100644 index 9976d24af..000000000 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Interfaces.Drawing; -using System; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Defines all FieldTypes + their default value. - /// (The additional value is why this is not an enum) - /// - [Serializable] - public class FieldType : IFieldType - { - - public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); - public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); - public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); - public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); - public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); - public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); - public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); - public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); - public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); - public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); - public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); - public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); - public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); - public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); - public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); - public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); - public static readonly IFieldType SHADOW = new FieldType("SHADOW"); - public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); - public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); - public static readonly IFieldType FLAGS = new FieldType("FLAGS"); - - public static IFieldType[] Values = { - ARROWHEADS, - BLUR_RADIUS, - BRIGHTNESS, - FILL_COLOR, - FONT_BOLD, - FONT_FAMILY, - FONT_ITALIC, - FONT_SIZE, - TEXT_HORIZONTAL_ALIGNMENT, - TEXT_VERTICAL_ALIGNMENT, - HIGHLIGHT_COLOR, - LINE_COLOR, - LINE_THICKNESS, - MAGNIFICATION_FACTOR, - PIXEL_SIZE, - PREVIEW_QUALITY, - SHADOW, - PREPARED_FILTER_OBFUSCATE, - PREPARED_FILTER_HIGHLIGHT, - FLAGS - }; - - public string Name - { - get; - set; - } - - private FieldType(string name) - { - Name = name; - } - public override string ToString() - { - return Name; - } - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - if (Name != null) - hashCode += 1000000009 * Name.GetHashCode(); - } - return hashCode; - } - - public override bool Equals(object obj) - { - FieldType other = obj as FieldType; - if (other == null) - { - return false; - } - return Equals(Name, other.Name); - } - - public static bool operator ==(FieldType a, FieldType b) - { - return Equals(a, b); - } - - public static bool operator !=(FieldType a, FieldType b) - { - return !Equals(a, b); - } - } -} diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs deleted file mode 100644 index 489e8e357..000000000 --- a/Greenshot/Drawing/FilterContainer.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// empty container for filter-only elements - /// - [Serializable()] - public abstract class FilterContainer : DrawableContainer { - - public enum PreparedFilterMode {OBFUSCATE, HIGHLIGHT}; - public enum PreparedFilter {BLUR, PIXELIZE, TEXT_HIGHTLIGHT, AREA_HIGHLIGHT, GRAYSCALE, MAGNIFICATION}; - - public PreparedFilter Filter { - get { return (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } - } - - public FilterContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 0); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (lineVisible) { - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - //draw shadow first - if (shadow) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); - graphics.DrawRectangle(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - if (lineThickness > 0) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawRectangle(pen, rect); - } - } - } - } -} diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs deleted file mode 100644 index 7c54545bd..000000000 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.ComponentModel; -using System.Drawing; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - /// - /// Graphical filter which can be added to DrawableContainer. - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class AbstractFilter : AbstractFieldHolder, IFilter { - - [NonSerialized] - private PropertyChangedEventHandler propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add { propertyChanged += value; } - remove{ propertyChanged -= value; } - } - - private bool invert; - public bool Invert { - get { - return invert; - } - set { - invert = value; - OnPropertyChanged("Invert"); - } - } - - protected DrawableContainer parent; - public DrawableContainer Parent { - get { - return parent; - } - set { - parent = value; - } - } - - public AbstractFilter(DrawableContainer parent) { - this.parent = parent; - } - - public DrawableContainer GetParent() { - return parent; - } - - public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); - - protected void OnPropertyChanged(string propertyName) - { - propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs deleted file mode 100644 index 711c1d02b..000000000 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable] - public class BlurFilter : AbstractFilter { - public double previewQuality; - public double PreviewQuality { - get { return previewQuality; } - set { previewQuality = value; OnPropertyChanged("PreviewQuality"); } - } - - public BlurFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BLUR_RADIUS, 3); - AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - if (GDIplus.IsBlurPossible(blurRadius)) { - GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); - } else - { - using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect); - ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius); - fastBitmap.DrawTo(graphics, applyRect); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs deleted file mode 100644 index 852aca9de..000000000 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Imaging; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class BrightnessFilter : AbstractFilter { - - public BrightnessFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BRIGHTNESS, 0.9d); - } - - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS); - using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f)) { - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs deleted file mode 100644 index 4758d12bd..000000000 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - /// - /// Description of GrayscaleFilter. - /// - [Serializable()] - public class GrayscaleFilter : AbstractFilter { - public GrayscaleFilter(DrawableContainer parent) : base(parent) { - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] { - new[] {.3f, .3f, .3f, 0, 0}, - new[] {.59f, .59f, .59f, 0, 0}, - new[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - using (ImageAttributes ia = new ImageAttributes()) { - ia.SetColorMatrix(grayscaleMatrix); - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); - - } - } -} diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs deleted file mode 100644 index 36c574493..000000000 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class HighlightFilter : AbstractFilter { - public HighlightFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow); - } - - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) { - for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) { - Color color = fastBitmap.GetColorAt(x, y); - color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); - fastBitmap.SetColorAt(x, y, color); - } - } - fastBitmap.DrawTo(graphics, applyRect.Location); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs deleted file mode 100644 index 601d09967..000000000 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable] - public class MagnifierFilter : AbstractFilter { - public MagnifierFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - graphics.SmoothingMode = SmoothingMode.None; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - int halfWidth = rect.Width / 2; - int halfHeight = rect.Height / 2; - int newWidth = rect.Width / magnificationFactor; - int newHeight = rect.Height / magnificationFactor; - Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); - graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs deleted file mode 100644 index 129ba4822..000000000 --- a/Greenshot/Drawing/FreehandContainer.cs +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of PathContainer. - /// - [Serializable] - public class FreehandContainer : DrawableContainer { - private static readonly float [] PointOffset = {0.5f, 0.25f, 0.75f}; - - [NonSerialized] - private GraphicsPath freehandPath = new GraphicsPath(); - private Rectangle myBounds = Rectangle.Empty; - private Point lastMouse = Point.Empty; - private readonly List capturePoints = new List(); - private bool isRecalculated; - - /// - /// Constructor - /// - public FreehandContainer(Surface parent) : base(parent) { - Width = parent.Width; - Height = parent.Height; - Top = 0; - Left = 0; - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 3); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - } - - public override void Transform(Matrix matrix) { - Point[] points = capturePoints.ToArray(); - - matrix.TransformPoints(points); - capturePoints.Clear(); - capturePoints.AddRange(points); - RecalculatePath(); - } - - protected override void OnDeserialized(StreamingContext context) { - RecalculatePath(); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (disposing) - { - freehandPath?.Dispose(); - } - freehandPath = null; - } - - /// - /// Called from Surface (the parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - lastMouse = new Point(mouseX, mouseY); - capturePoints.Add(lastMouse); - return true; - } - - /// - /// Called from Surface (the parent) if a mouse move is made while drawing - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseMove(int mouseX, int mouseY) { - Point previousPoint = capturePoints[capturePoints.Count-1]; - - if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2*EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) - { - return true; - } - //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); - lastMouse = new Point(mouseX, mouseY); - freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); - // Only re-calculate the bounds & redraw when we added something to the path - myBounds = Rectangle.Round(freehandPath.GetBounds()); - - Invalidate(); - return true; - } - - /// - /// Called when the surface finishes drawing the element - /// - public override void HandleMouseUp(int mouseX, int mouseY) { - // Make sure we don't loose the ending point - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - RecalculatePath(); - } - - /// - /// Here we recalculate the freehand path by smoothing out the lines with Beziers. - /// - private void RecalculatePath() { - // Store the previous path, to dispose it later when we are finished - var previousFreehandPath = freehandPath; - var newFreehandPath = new GraphicsPath(); - - // Here we can put some cleanup... like losing all the uninteresting points. - if (capturePoints.Count >= 3) - { - int index = 0; - while ((capturePoints.Count - 1) % 3 != 0) - { - // duplicate points, first at 50% than 25% than 75% - capturePoints.Insert((int)(capturePoints.Count * PointOffset[index]), capturePoints[(int)(capturePoints.Count * PointOffset[index++])]); - } - newFreehandPath.AddBeziers(capturePoints.ToArray()); - } - else if (capturePoints.Count == 2) - { - newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); - } - - // Recalculate the bounds - myBounds = Rectangle.Round(newFreehandPath.GetBounds()); - - // assign - isRecalculated = true; - freehandPath = newFreehandPath; - - // dispose previous - previousFreehandPath?.Dispose(); - } - - /// - /// Do the drawing of the freehand "stroke" - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - using var pen = new Pen(lineColor) - { - Width = lineThickness - }; - if (!(pen.Width > 0)) - { - return; - } - // Make sure the lines are nicely rounded - pen.EndCap = LineCap.Round; - pen.StartCap = LineCap.Round; - pen.LineJoin = LineJoin.Round; - // Move to where we need to draw - graphics.TranslateTransform(Left, Top); - var currentFreehandPath = freehandPath; - if (currentFreehandPath != null) - { - if (isRecalculated && Selected && renderMode == RenderMode.EDIT) - { - isRecalculated = false; - DrawSelectionBorder(graphics, pen, currentFreehandPath); - } - graphics.DrawPath(pen, currentFreehandPath); - } - - // Move back, otherwise everything is shifted - graphics.TranslateTransform(-Left,-Top); - } - - /// - /// Draw a selectionborder around the freehand path - /// - /// Graphics - /// Pen - /// GraphicsPath - protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) - { - using var selectionPen = (Pen) linePen.Clone(); - using var selectionPath = (GraphicsPath)path.Clone(); - selectionPen.Width += 5; - selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); - graphics.DrawPath(selectionPen, selectionPath); - selectionPath.Widen(selectionPen); - selectionPen.DashPattern = new float[]{2,2}; - selectionPen.Color = Color.LightSeaGreen; - selectionPen.Width = 1; - graphics.DrawPath(selectionPen, selectionPath); - } - - /// - /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... - /// - public override Rectangle DrawingBounds { - get { - if (!myBounds.IsEmpty) { - int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); - int safetymargin = 10; - return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin)); - } - return new Rectangle(0, 0, _parent?.Width??0, _parent?.Height?? 0); - } - } - - /// - /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. - /// - /// object - /// bool - public override bool Equals(object obj) { - bool ret = false; - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - - if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) { - ret = true; - } - return ret; - } - - public override int GetHashCode() { - return freehandPath?.GetHashCode() ?? 0; - } - - public override bool ClickableAt(int x, int y) { - bool returnValue = base.ClickableAt(x, y); - if (returnValue) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - using var pen = new Pen(Color.White) - { - Width = lineThickness + 10 - }; - returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); - } - return returnValue; - } - } -} diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs deleted file mode 100644 index 858e1508b..000000000 --- a/Greenshot/Drawing/HighlightContainer.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class HighlightContainer : FilterContainer { - public HighlightContainer(Surface parent) : base(parent) { - Init(); - } - - /// - /// Use settings from base, extend with our own field - /// - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += HighlightContainer_OnFieldChanged; - ConfigurePreparedFilters(); - } - - protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if (!sender.Equals(this)) { - return; - } - if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT)) { - ConfigurePreparedFilters(); - } - } - - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.TEXT_HIGHTLIGHT: - Add(new HighlightFilter(this)); - break; - case PreparedFilter.AREA_HIGHLIGHT: - var brightnessFilter = new BrightnessFilter(this) - { - Invert = true - }; - Add(brightnessFilter); - var blurFilter = new BlurFilter(this) - { - Invert = true - }; - Add(blurFilter); - break; - case PreparedFilter.GRAYSCALE: - AbstractFilter f = new GrayscaleFilter(this) - { - Invert = true - }; - Add(f); - break; - case PreparedFilter.MAGNIFICATION: - Add(new MagnifierFilter(this)); - break; - } - } - } -} diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs deleted file mode 100644 index 013fb057f..000000000 --- a/Greenshot/Drawing/IconContainer.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.IO; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of IconContainer. - /// - [Serializable] - public class IconContainer : DrawableContainer, IIconContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); - - protected Icon icon; - - public IconContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - public IconContainer(Surface parent, string filename) : base(parent) { - Load(filename); - } - - public Icon Icon { - set { - icon?.Dispose(); - icon = (Icon)value.Clone(); - Width = value.Width; - Height = value.Height; - } - get { return icon; } - } - - /** - * This Dispose is called from the Dispose and the Destructor. - * When disposing==true all non-managed resources should be freed too! - */ - protected override void Dispose(bool disposing) { - if (disposing) - { - icon?.Dispose(); - } - icon = null; - base.Dispose(disposing); - } - - public void Load(string filename) { - if (File.Exists(filename)) - { - using Icon fileIcon = new Icon(filename); - Icon = fileIcon; - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - } - - public override void Draw(Graphics graphics, RenderMode rm) { - if (icon != null) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.DrawIcon(icon, Bounds); - } - } - - public override bool HasDefaultSize => true; - - public override Size DefaultSize => icon.Size; - } -} diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs deleted file mode 100644 index 0e23855bb..000000000 --- a/Greenshot/Drawing/ImageContainer.cs +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.IO; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Effects; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of BitmapContainer. - /// - [Serializable] - public class ImageContainer : DrawableContainer, IImageContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); - - private Image image; - - /// - /// This is the shadow version of the bitmap, rendered once to save performance - /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available - /// - [NonSerialized] - private Image _shadowBitmap; - - /// - /// This is the offset for the shadow version of the bitmap - /// Do not serialize, as the offset is recreated - /// - [NonSerialized] - private Point _shadowOffset = new Point(-1, -1); - - public ImageContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } - - public ImageContainer(Surface parent) : base(parent) { - FieldChanged += BitmapContainer_OnFieldChanged; - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.SHADOW, false); - } - - protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if (sender.Equals(this)) { - if (FieldType.SHADOW.Equals(e.Field.FieldType)) { - ChangeShadowField(); - } - } - } - - public void ChangeShadowField() { - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - if (shadow) { - CheckShadow(true); - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } else { - Width = image.Width; - Height = image.Height; - if (_shadowBitmap != null) { - Left += _shadowOffset.X; - Top += _shadowOffset.Y; - } - } - } - - public Image Image { - set { - // Remove all current bitmaps - DisposeImage(); - DisposeShadow(); - image = ImageHelper.Clone(value); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - CheckShadow(shadow); - if (!shadow) { - Width = image.Width; - Height = image.Height; - } else { - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } - } - get { return image; } - } - - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - DisposeImage(); - DisposeShadow(); - } - base.Dispose(disposing); - } - - private void DisposeImage() { - image?.Dispose(); - image = null; - } - private void DisposeShadow() { - _shadowBitmap?.Dispose(); - _shadowBitmap = null; - } - - - - /// - /// Make sure the content is also transformed. - /// - /// - public override void Transform(Matrix matrix) { - int rotateAngle = CalculateAngle(matrix); - // we currently assume only one transformation has been made. - if (rotateAngle != 0) { - Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); - DisposeShadow(); - using var tmpMatrix = new Matrix(); - using (image) - { - image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); - } - } - base.Transform(matrix); - } - - /// - /// - /// - /// - public void Load(string filename) { - if (!File.Exists(filename)) - { - return; - } - // Always make sure ImageHelper.LoadBitmap results are disposed some time, - // as we close the bitmap internally, we need to do it afterwards - using (var tmpImage = ImageHelper.LoadImage(filename)) { - Image = tmpImage; - } - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - /// - /// This checks if a shadow is already generated - /// - /// - private void CheckShadow(bool shadow) { - if (shadow && _shadowBitmap == null) - { - using var matrix = new Matrix(); - _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); - } - } - - /// - /// Draw the actual container to the graphics object - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) { - if (image != null) { - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - if (shadow) { - CheckShadow(true); - graphics.DrawImage(_shadowBitmap, Bounds); - } else { - graphics.DrawImage(image, Bounds); - } - } - } - - public override bool HasDefaultSize => true; - - public override Size DefaultSize => image.Size; - } -} diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs deleted file mode 100644 index af73529d4..000000000 --- a/Greenshot/Drawing/LineContainer.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing2D; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Drawing.Adorners; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class LineContainer : DrawableContainer { - public static readonly int MAX_CLICK_DISTANCE_TOLERANCE = 10; - - public LineContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, true); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - protected void Init() { - Adorners.Add(new MoveAdorner(this, Positions.TopLeft)); - Adorners.Add(new MoveAdorner(this, Positions.BottomRight)); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); - - currentStep++; - alpha -= basealpha / steps; - } - } - - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); - } - } - - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) +5; - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - - protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.LineAngleRoundBehavior.Instance; - } - } -} diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs deleted file mode 100644 index 07ea899ba..000000000 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class ObfuscateContainer : FilterContainer { - public ObfuscateContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += ObfuscateContainer_OnFieldChanged; - ConfigurePreparedFilters(); - CreateDefaultAdorners(); - } - - protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if(sender.Equals(this)) { - if(Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE)) { - ConfigurePreparedFilters(); - } - } - } - - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.BLUR: - Add(new BlurFilter(this)); - break; - case PreparedFilter.PIXELIZE: - Add(new PixelizationFilter(this)); - break; - } - } - } -} diff --git a/Greenshot/Drawing/Positions.cs b/Greenshot/Drawing/Positions.cs deleted file mode 100644 index 847d08415..000000000 --- a/Greenshot/Drawing/Positions.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * 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 1 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 Greenshot.Drawing -{ - /// - /// Position - /// - public enum Positions : int - { - TopLeft = 0, - TopCenter = 1, - TopRight = 2, - MiddleRight = 3, - BottomRight = 4, - BottomCenter = 5, - BottomLeft = 6, - MiddleLeft = 7 - } -} diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs deleted file mode 100644 index 623e28b22..000000000 --- a/Greenshot/Drawing/RectangleContainer.cs +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing2D; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Represents a rectangular shape on the Surface - /// - [Serializable] - public class RectangleContainer : DrawableContainer { - - public RectangleContainer(Surface parent) : base(parent) { - Init(); - } - - /// - /// Do some logic to make sure all field are initiated correctly - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); - } - - /// - /// This method can also be used from other containers, if the right values are passed! - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) - { - Width = lineVisible ? lineThickness : 1 - }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle( - rect.Left + currentStep, - rect.Top + currentStep, - rect.Width, - rect.Height); - graphics.DrawRectangle(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - - - if (Colors.IsVisible(fillColor)) - { - using Brush brush = new SolidBrush(fillColor); - graphics.FillRectangle(brush, rect); - } - - graphics.SmoothingMode = SmoothingMode.HighSpeed; - if (lineVisible) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawRectangle(pen, rect); - } - - } - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - - return RectangleClickableAt(rect, lineThickness, fillColor, x, y); - } - - - public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { - - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x,y)) { - return true; - } - } - - // check the rest of the lines - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White, lineThickness); - using GraphicsPath path = new GraphicsPath(); - path.AddRectangle(rect); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/RoundedRectangle.cs b/Greenshot/Drawing/RoundedRectangle.cs deleted file mode 100644 index 8a519d1ed..000000000 --- a/Greenshot/Drawing/RoundedRectangle.cs +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Drawing2D; - -namespace Greenshot.Drawing { - /// - /// TODO: currently this is only used in the capture form, we might move this code directly to there! - /// - public abstract class RoundedRectangle { - [Flags] - public enum RectangleCorners { - None = 0, TopLeft = 1, TopRight = 2, - BottomLeft = 4, BottomRight = 8, - All = TopLeft | TopRight | BottomLeft | BottomRight - } - - public static GraphicsPath Create2(int x, int y, int width, int height, int radius) { - GraphicsPath gp = new GraphicsPath(); - gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line - gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner - gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line - gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner - gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line - gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner - gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line - gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner - gp.CloseFigure(); - - return gp; - } - - public static GraphicsPath Create(int x, int y, int width, int height, int radius, RectangleCorners corners) { - int xw = x + width; - int yh = y + height; - int xwr = xw - radius; - int yhr = yh - radius; - int xr = x + radius; - int yr = y + radius; - int r2 = radius * 2; - int xwr2 = xw - r2; - int yhr2 = yh - r2; - - GraphicsPath p = new GraphicsPath(); - p.StartFigure(); - - //Top Left Corner - if ((RectangleCorners.TopLeft & corners) == RectangleCorners.TopLeft) { - p.AddArc(x, y, r2, r2, 180, 90); - } else { - p.AddLine(x, yr, x, y); - p.AddLine(x, y, xr, y); - } - - //Top Edge - p.AddLine(xr, y, xwr, y); - - //Top Right Corner - if ((RectangleCorners.TopRight & corners) == RectangleCorners.TopRight) { - p.AddArc(xwr2, y, r2, r2, 270, 90); - } else { - p.AddLine(xwr, y, xw, y); - p.AddLine(xw, y, xw, yr); - } - - //Right Edge - p.AddLine(xw, yr, xw, yhr); - - //Bottom Right Corner - if ((RectangleCorners.BottomRight & corners) == RectangleCorners.BottomRight) { - p.AddArc(xwr2, yhr2, r2, r2, 0, 90); - } else { - p.AddLine(xw, yhr, xw, yh); - p.AddLine(xw, yh, xwr, yh); - } - - //Bottom Edge - p.AddLine(xwr, yh, xr, yh); - - //Bottom Left Corner - if ((RectangleCorners.BottomLeft & corners) == RectangleCorners.BottomLeft) { - p.AddArc(x, yhr2, r2, r2, 90, 90); - } else { - p.AddLine(xr, yh, x, yh); - p.AddLine(x, yh, x, yhr); - } - - //Left Edge - p.AddLine(x, yhr, x, yr); - - p.CloseFigure(); - return p; - } - - public static GraphicsPath Create(Rectangle rect, int radius, RectangleCorners corners) { - return Create(rect.X, rect.Y, rect.Width, rect.Height, radius, corners); - } - - public static GraphicsPath Create(int x, int y, int width, int height, int radius) { - return Create(x, y, width, height, radius, RectangleCorners.All); - } - - public static GraphicsPath Create(Rectangle rect, int radius) { - return Create(rect.X, rect.Y, rect.Width, rect.Height, radius); - } - - public static GraphicsPath Create(int x, int y, int width, int height) { - return Create(x, y, width, height, 5); - } - - public static GraphicsPath Create(Rectangle rect) { - return Create(rect.X, rect.Y, rect.Width, rect.Height); - } - } -} diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs deleted file mode 100644 index f585af7aa..000000000 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing -{ - /// - /// Description of SpeechbubbleContainer. - /// - [Serializable] - public class SpeechbubbleContainer : TextContainer { - - private Point _initialGripperPoint; - - // Only used for serializing the TargetGripper location - private Point _storedTargetGripperLocation; - - /// - /// Store the current location of the target gripper - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (TargetAdorner != null) { - _storedTargetGripperLocation = TargetAdorner.Location; - } - } - - /// - /// Restore the target gripper - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - InitAdorner(Color.Green, _storedTargetGripperLocation); - } - - public SpeechbubbleContainer(Surface parent) - : base(parent) { - } - - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); - AddField(GetType(), FieldType.SHADOW, false); - AddField(GetType(), FieldType.FONT_ITALIC, false); - AddField(GetType(), FieldType.FONT_BOLD, true); - AddField(GetType(), FieldType.FILL_COLOR, Color.White); - AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); - AddField(GetType(), FieldType.FONT_SIZE, 20f); - AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center); - AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center); - } - - /// - /// Called from Surface (the _parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - if (TargetAdorner == null) { - _initialGripperPoint = new Point(mouseX, mouseY); - InitAdorner(Color.Green, new Point(mouseX, mouseY)); - } - return base.HandleMouseDown(mouseX, mouseY); - } - - /// - /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. - /// Should fix BUG-1682 - /// - /// - /// - /// base.HandleMouseMove - public override bool HandleMouseMove(int x, int y) { - bool returnValue = base.HandleMouseMove(x, y); - - bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0; - bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0; - - int xOffset = leftAligned ? -20 : 20; - int yOffset = topAligned ? -20 : 20; - - Point newGripperLocation = _initialGripperPoint; - newGripperLocation.Offset(xOffset, yOffset); - - if (TargetAdorner.Location != newGripperLocation) { - Invalidate(); - TargetAdorner.Location = newGripperLocation; - Invalidate(); - } - return returnValue; - } - - /// - /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. - /// - public override Rectangle DrawingBounds { - get { - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - using Pen pen = new Pen(lineColor, lineThickness); - int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); - using GraphicsPath tailPath = CreateTail(); - return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), inflateValue, inflateValue); - } - return Rectangle.Empty; - } - } - - /// - /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds - /// - /// - /// - private GraphicsPath CreateBubble(int lineThickness) { - GraphicsPath bubble = new GraphicsPath(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); - // adapt corner radius to small rectangle dimensions - int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); - int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); - if (cornerRadius > 0) { - bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); - bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); - } else { - bubble.AddRectangle(bubbleRect); - } - bubble.CloseAllFigures(); - using (Matrix bubbleMatrix = new Matrix()) { - bubbleMatrix.Translate(rect.Left, rect.Top); - bubble.Transform(bubbleMatrix); - } - return bubble; - } - - /// - /// Helper method to create the tail of the bubble, so we can also calculate the bounds - /// - /// - private GraphicsPath CreateTail() { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); - int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; - - // This should fix a problem with the tail being to wide - tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); - tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); - - GraphicsPath tail = new GraphicsPath(); - tail.AddLine(-tailWidth, 0, tailWidth, 0); - tail.AddLine(tailWidth, 0, 0, -tailLength); - tail.CloseFigure(); - - int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); - - using (Matrix tailMatrix = new Matrix()) { - tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); - tailMatrix.Rotate(tailAngle); - tail.Transform(tailMatrix); - } - - return tail; - } - - /// - /// This is to draw the actual container - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - if (TargetAdorner == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - if (Selected && renderMode == RenderMode.EDIT) { - DrawSelectionBorder(graphics, rect); - } - - GraphicsPath bubble = CreateBubble(lineThickness); - - GraphicsPath tail = CreateTail(); - - //draw shadow first - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - const int basealpha = 100; - int alpha = basealpha; - const int steps = 5; - int currentStep = lineVisible ? 1 : 0; - using Matrix shadowMatrix = new Matrix(); - using GraphicsPath bubbleClone = (GraphicsPath)bubble.Clone(); - using GraphicsPath tailClone = (GraphicsPath)tail.Clone(); - shadowMatrix.Translate(1, 1); - while (currentStep <= steps) { - using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { - shadowPen.Width = lineVisible ? lineThickness : 1; - tailClone.Transform(shadowMatrix); - graphics.DrawPath(shadowPen, tailClone); - bubbleClone.Transform(shadowMatrix); - graphics.DrawPath(shadowPen, bubbleClone); - } - currentStep++; - alpha -= basealpha / steps; - } - } - - GraphicsState state = graphics.Save(); - // draw the tail border where the bubble is not visible - using (Region clipRegion = new Region(bubble)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawPath(pen, tail); - } - graphics.Restore(state); - - if (Colors.IsVisible(fillColor)) { - //draw the bubbleshape - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, bubble); - } - graphics.Restore(state); - } - - if (lineVisible) { - //draw the bubble border - state = graphics.Save(); - // Draw bubble where the Tail is not visible. - using (Region clipRegion = new Region(tail)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); - using Pen pen = new Pen(lineColor, lineThickness); - //pen.EndCap = pen.StartCap = LineCap.Round; - graphics.DrawPath(pen, bubble); - } - graphics.Restore(state); - } - - if (Colors.IsVisible(fillColor)) { - // Draw the tail border - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, tail); - } - graphics.Restore(state); - } - - // cleanup the paths - bubble.Dispose(); - tail.Dispose(); - - // Draw the text - DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font); - } - - public override bool Contains(int x, int y) { - if (base.Contains(x, y)) { - return true; - } - Point clickedPoint = new Point(x, y); - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - using Pen pen = new Pen(lineColor, lineThickness); - using (GraphicsPath bubblePath = CreateBubble(lineThickness)) { - bubblePath.Widen(pen); - if (bubblePath.IsVisible(clickedPoint)) { - return true; - } - } - - using GraphicsPath tailPath = CreateTail(); - tailPath.Widen(pen); - if (tailPath.IsVisible(clickedPoint)) { - return true; - } - } - - return false; - } - - public override bool ClickableAt(int x, int y) { - return Contains(x,y); - } - } -} diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs deleted file mode 100644 index 26510e515..000000000 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. - /// To make sure that deleting recalculates, we check the location before every draw. - /// - [Serializable] - public sealed class StepLabelContainer : DrawableContainer { - [NonSerialized] - private StringFormat _stringFormat = new StringFormat(); - - private readonly bool _drawAsRectangle = false; - - private float fontSize = 16; - - public StepLabelContainer(Surface parent) : base(parent) { - parent.AddStepLabel(this); - InitContent(); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location - private int _number; - // Used to store the counter start of the Surface, as the surface is NOT stored. - private int _counterStart = 1; - public int Number { - get { - return _number; - } - set { - _number = value; - } - } - - /// - /// Retrieve the counter before serializing - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (Parent != null) { - Number = ((Surface)Parent).CountStepLabels(this); - _counterStart = ((Surface) Parent).CounterStart; - } - } - - /// - /// Restore values that don't serialize - /// - /// - protected override void OnDeserialized(StreamingContext context) - { - Init(); - _stringFormat = new StringFormat - { - Alignment = StringAlignment.Center, - LineAlignment = StringAlignment.Center - }; - - } - - /// - /// Add the StepLabel to the parent - /// - /// - protected override void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - base.SwitchParent(newParent); - if (newParent == null) - { - return; - } - // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) - newParent.CounterStart = _counterStart; - newParent.AddStepLabel(this); - } - - public override Size DefaultSize => new Size(30, 30); - - public override bool InitContent() { - _defaultEditMode = EditStatus.IDLE; - _stringFormat.Alignment = StringAlignment.Center; - _stringFormat.LineAlignment = StringAlignment.Center; - - // Set defaults - Width = DefaultSize.Width; - Height = DefaultSize.Height; - - return true; - } - - /// - /// This makes it possible for the label to be placed exactly in the middle of the pointer. - /// - public override bool HandleMouseDown(int mouseX, int mouseY) { - return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2); - } - - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); - AddField(GetType(), FieldType.LINE_COLOR, Color.White); - AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER); - } - - /// - /// Make sure this element is no longer referenced from the surface - /// - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (!disposing) { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - if (_stringFormat == null) - { - return; - } - _stringFormat.Dispose(); - _stringFormat = null; - } - - public override bool HandleMouseMove(int x, int y) { - Invalidate(); - Left = x - Width / 2; - Top = y - Height / 2; - Invalidate(); - return true; - } - - /// - /// Make sure the size of the font is scaled - /// - /// - public override void Transform(Matrix matrix) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int widthBefore = rect.Width; - int heightBefore = rect.Height; - - // Transform this container - base.Transform(matrix); - rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - int widthAfter = rect.Width; - int heightAfter = rect.Height; - float factor = ((float)widthAfter / widthBefore + (float)heightAfter / heightBefore) / 2; - - fontSize *= factor; - } - - /// - /// Override the parent, calculate the label number, than draw - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - string text = ((Surface)Parent).CountStepLabels(this).ToString(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - if (_drawAsRectangle) { - RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } else { - EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } - - using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); - using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); - TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); - } - - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - if (_drawAsRectangle) { - return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); - } else { - return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); - } - } - } -} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs deleted file mode 100644 index 3ec79db52..000000000 --- a/Greenshot/Drawing/Surface.cs +++ /dev/null @@ -1,2038 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using log4net; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using System.Windows.Forms; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing -{ - /// - /// Description of Surface. - /// - public sealed class Surface : Control, ISurface, INotifyPropertyChanged - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); - public static int Count; - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - - // Property to identify the Surface ID - private Guid _uniqueId = Guid.NewGuid(); - - /// - /// This value is used to start counting the step labels - /// - private int _counterStart = 1; - - /// - /// The GUID of the surface - /// - public Guid ID - { - get => _uniqueId; - set => _uniqueId = value; - } - - /// - /// Event handlers (do not serialize!) - /// - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged - { - add => _propertyChanged += value; - remove => _propertyChanged -= value; - } - - [NonSerialized] - private SurfaceElementEventHandler _movingElementChanged; - public event SurfaceElementEventHandler MovingElementChanged - { - add => _movingElementChanged += value; - remove => _movingElementChanged -= value; - } - - [NonSerialized] - private SurfaceDrawingModeEventHandler _drawingModeChanged; - public event SurfaceDrawingModeEventHandler DrawingModeChanged - { - add => _drawingModeChanged += value; - remove => _drawingModeChanged -= value; - } - [NonSerialized] - private SurfaceSizeChangeEventHandler _surfaceSizeChanged; - public event SurfaceSizeChangeEventHandler SurfaceSizeChanged - { - add => _surfaceSizeChanged += value; - remove => _surfaceSizeChanged -= value; - } - [NonSerialized] - private SurfaceMessageEventHandler _surfaceMessage; - public event SurfaceMessageEventHandler SurfaceMessage - { - add => _surfaceMessage += value; - remove => _surfaceMessage -= value; - } - - /// - /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action - /// - [NonSerialized] - private bool _inUndoRedo; - - /// - /// Make only one surface move cycle undoable, see SurfaceMouseMove - /// - [NonSerialized] - private bool _isSurfaceMoveMadeUndoable; - - /// - /// Undo/Redo stacks, should not be serialized as the file would be way to big - /// - [NonSerialized] - private readonly Stack _undoStack = new Stack(); - [NonSerialized] - private readonly Stack _redoStack = new Stack(); - - /// - /// Last save location, do not serialize! - /// - [NonSerialized] - private string _lastSaveFullPath; - - /// - /// current drawing mode, do not serialize! - /// - [NonSerialized] - private DrawingModes _drawingMode = DrawingModes.None; - - /// - /// the keys-locked flag helps with focus issues - /// - [NonSerialized] - private bool _keysLocked; - - /// - /// Location of the mouse-down (it "starts" here), do not serialize - /// - [NonSerialized] - private Point _mouseStart = Point.Empty; - - /// - /// are we in a mouse down, do not serialize - /// - [NonSerialized] - private bool _mouseDown; - - /// - /// The selected element for the mouse down, do not serialize - /// - [NonSerialized] - private IDrawableContainer _mouseDownElement; - - /// - /// all selected elements, do not serialize - /// - [NonSerialized] - private readonly IDrawableContainerList selectedElements; - - /// - /// the element we are drawing with, do not serialize - /// - [NonSerialized] - private IDrawableContainer _drawingElement; - - /// - /// the element we want to draw with (not yet drawn), do not serialize - /// - [NonSerialized] - private IDrawableContainer _undrawnElement; - - /// - /// the cropcontainer, when cropping this is set, do not serialize - /// - [NonSerialized] - private IDrawableContainer _cropContainer; - - /// - /// the brush which is used for transparent backgrounds, set by the editor, do not serialize - /// - [NonSerialized] - private Brush _transparencyBackgroundBrush; - - /// - /// The buffer is only for drawing on it when using filters (to supply access) - /// This saves a lot of "create new bitmap" commands - /// Should not be serialized, as it's generated. - /// The actual bitmap is in the paintbox... - /// TODO: Check if this buffer is still needed! - /// - [NonSerialized] - private Bitmap _buffer; - - /// - /// all stepLabels for the surface, needed with serialization - /// - private readonly List _stepLabels = new List(); - - public void AddStepLabel(StepLabelContainer stepLabel) - { - if (!_stepLabels.Contains(stepLabel)) - { - _stepLabels.Add(stepLabel); - } - } - - public void RemoveStepLabel(StepLabelContainer stepLabel) - { - _stepLabels.Remove(stepLabel); - } - - /// - /// The start value of the counter objects - /// - public int CounterStart - { - get => _counterStart; - set - { - if (_counterStart == value) - { - return; - } - - _counterStart = value; - Invalidate(); - _propertyChanged?.Invoke(this, new PropertyChangedEventArgs("CounterStart")); - } - } - - /// - /// Count all the VISIBLE steplabels in the surface, up to the supplied one - /// - /// can be null, if not the counting stops here - /// number of steplabels before the supplied container - public int CountStepLabels(IDrawableContainer stopAtContainer) - { - int number = CounterStart; - foreach (var possibleThis in _stepLabels) - { - if (possibleThis.Equals(stopAtContainer)) - { - break; - } - if (IsOnSurface(possibleThis)) - { - number++; - } - } - return number; - } - - /// - /// all elements on the surface, needed with serialization - /// - private readonly IDrawableContainerList _elements; - - /// - /// all elements on the surface, needed with serialization - /// - private FieldAggregator _fieldAggregator; - - /// - /// the cursor container, needed with serialization as we need a direct acces to it. - /// - private IDrawableContainer _cursorContainer; - - /// - /// the modified flag specifies if the surface has had modifications after the last export. - /// Initial state is modified, as "it's not saved" - /// After serialization this should actually be "false" (the surface came from a stream) - /// For now we just serialize it... - /// - private bool _modified = true; - - /// - /// The image is the actual captured image, needed with serialization - /// - private Image _image; - public Image Image - { - get => _image; - set - { - _image = value; - Size = _image.Size; - } - } - - /// - /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. - /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. - /// - public FieldAggregator FieldAggregator - { - get => _fieldAggregator; - set => _fieldAggregator = value; - } - - /// - /// The cursor container has it's own accessor so we can find and remove this (when needed) - /// - public IDrawableContainer CursorContainer => _cursorContainer; - - /// - /// A simple getter to ask if this surface has a cursor - /// - public bool HasCursor => _cursorContainer != null; - - /// - /// A simple helper method to remove the cursor from the surface - /// - public void RemoveCursor() - { - RemoveElement(_cursorContainer); - _cursorContainer = null; - } - - /// - /// The brush which is used to draw the transparent background - /// - public Brush TransparencyBackgroundBrush - { - get => _transparencyBackgroundBrush; - set => _transparencyBackgroundBrush = value; - } - - /// - /// Are the keys on this surface locked? - /// - public bool KeysLocked - { - get => _keysLocked; - set => _keysLocked = value; - } - - /// - /// Is this surface modified? This is only true if the surface has not been exported. - /// - public bool Modified - { - get => _modified; - set => _modified = value; - } - - /// - /// The DrawingMode property specifies the mode for drawing, more or less the element type. - /// - public DrawingModes DrawingMode - { - get => _drawingMode; - set - { - _drawingMode = value; - if (_drawingModeChanged != null) - { - SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs - { - DrawingMode = _drawingMode - }; - _drawingModeChanged.Invoke(this, eventArgs); - } - DeselectAllElements(); - CreateUndrawnElement(); - } - } - - /// - /// Property for accessing the last save "full" path - /// - public string LastSaveFullPath - { - get => _lastSaveFullPath; - set => _lastSaveFullPath = value; - } - - /// - /// Property for accessing the URL to which the surface was recently uploaded - /// - public string UploadUrl - { - get; - set; - } - - /// - /// Property for accessing the capture details - /// - public ICaptureDetails CaptureDetails { get; set; } - - /// - /// Base Surface constructor - /// - public Surface() - { - _fieldAggregator = new FieldAggregator(this); - Count++; - _elements = new DrawableContainerList(_uniqueId); - selectedElements = new DrawableContainerList(_uniqueId); - LOG.Debug("Creating surface!"); - MouseDown += SurfaceMouseDown; - MouseUp += SurfaceMouseUp; - MouseMove += SurfaceMouseMove; - MouseDoubleClick += SurfaceDoubleClick; - Paint += SurfacePaint; - AllowDrop = true; - DragDrop += OnDragDrop; - DragEnter += OnDragEnter; - // bind selected & elements to this, otherwise they can't inform of modifications - selectedElements.Parent = this; - _elements.Parent = this; - // Make sure we are visible - Visible = true; - TabStop = false; - // Enable double buffering - DoubleBuffered = true; - SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true); - } - - /// - /// Private method, the current image is disposed the new one will stay. - /// - /// The new image - /// true if the old image needs to be disposed, when using undo this should not be true!! - private void SetImage(Image newImage, bool dispose) - { - // Dispose - if (_image != null && dispose) - { - _image.Dispose(); - } - - // Set new values - Image = newImage; - Size = newImage.Size; - - _modified = true; - } - - /// - /// Surface constructor with an image - /// - /// - public Surface(Image newImage) : this() - { - LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); - SetImage(newImage, true); - } - - /// - /// Surface contructor with a capture - /// - /// - public Surface(ICapture capture) : this(capture.Image) - { - // check if cursor is captured, and visible - if (capture.Cursor != null && capture.CursorVisible) - { - Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); - Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); - // check if cursor is on the capture, otherwise we leave it out. - if (cursorRect.IntersectsWith(captureRect)) - { - _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); - SelectElement(_cursorContainer); - } - } - // Make sure the image is NOT disposed, we took the reference directly into ourselves - ((Capture)capture).NullImage(); - - CaptureDetails = capture.CaptureDetails; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - Count--; - LOG.Debug("Disposing surface!"); - if (_buffer != null) - { - _buffer.Dispose(); - _buffer = null; - } - if (_transparencyBackgroundBrush != null) - { - _transparencyBackgroundBrush.Dispose(); - _transparencyBackgroundBrush = null; - } - - // Cleanup undo/redo stacks - while (_undoStack != null && _undoStack.Count > 0) - { - _undoStack.Pop().Dispose(); - } - while (_redoStack != null && _redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - foreach (IDrawableContainer container in _elements) - { - container.Dispose(); - } - if (_undrawnElement != null) - { - _undrawnElement.Dispose(); - _undrawnElement = null; - } - if (_cropContainer != null) - { - _cropContainer.Dispose(); - _cropContainer = null; - } - } - base.Dispose(disposing); - } - - /// - /// Undo the last action - /// - public void Undo() - { - if (_undoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _undoStack.Pop(); - _redoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } - - /// - /// Undo an undo (=redo) - /// - public void Redo() - { - if (_redoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _redoStack.Pop(); - _undoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } - - /// - /// Returns if the surface can do a undo - /// - public bool CanUndo => _undoStack.Count > 0; - - /// - /// Returns if the surface can do a redo - /// - public bool CanRedo => _redoStack.Count > 0; - - /// - /// Get the language key for the undo action - /// - public LangKey UndoActionLanguageKey => LangKey.none; - - /// - /// Get the language key for redo action - /// - public LangKey RedoActionLanguageKey => LangKey.none; - - /// - /// Make an action undo-able - /// - /// The memento implementing the undo - /// Allow changes to be merged - public void MakeUndoable(IMemento memento, bool allowMerge) - { - if (_inUndoRedo) - { - throw new InvalidOperationException("Invoking do within an undo/redo action."); - } - if (memento != null) - { - bool allowPush = true; - if (_undoStack.Count > 0 && allowMerge) - { - // Check if merge is possible - allowPush = !_undoStack.Peek().Merge(memento); - } - if (allowPush) - { - // Clear the redo-stack and dispose - while (_redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - _undoStack.Push(memento); - } - } - } - - /// - /// This saves the elements of this surface to a stream. - /// Is used to save a template of the complete surface - /// - /// - /// - public long SaveElementsToStream(Stream streamWrite) - { - long bytesWritten = 0; - try - { - long lengtBefore = streamWrite.Length; - BinaryFormatter binaryWrite = new BinaryFormatter(); - binaryWrite.Serialize(streamWrite, _elements); - bytesWritten = streamWrite.Length - lengtBefore; - } - catch (Exception e) - { - LOG.Error("Error serializing elements to stream.", e); - } - return bytesWritten; - } - - /// - /// This loads elements from a stream, among others this is used to load a surface. - /// - /// - public void LoadElementsFromStream(Stream streamRead) - { - try - { - BinaryFormatter binaryRead = new BinaryFormatter(); - IDrawableContainerList loadedElements = (IDrawableContainerList)binaryRead.Deserialize(streamRead); - loadedElements.Parent = this; - // Make sure the steplabels are sorted accoring to their number - _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); - DeselectAllElements(); - AddElements(loadedElements); - SelectElements(loadedElements); - FieldAggregator.BindElements(loadedElements); - } - catch (Exception e) - { - LOG.Error("Error serializing elements from stream.", e); - } - } - - /// - /// This is called from the DrawingMode setter, which is not very correct... - /// But here an element is created which is not yet draw, thus "undrawnElement". - /// The element is than used while drawing on the surface. - /// - private void CreateUndrawnElement() - { - if (_undrawnElement != null) - { - FieldAggregator.UnbindElement(_undrawnElement); - } - switch (DrawingMode) - { - case DrawingModes.Rect: - _undrawnElement = new RectangleContainer(this); - break; - case DrawingModes.Ellipse: - _undrawnElement = new EllipseContainer(this); - break; - case DrawingModes.Text: - _undrawnElement = new TextContainer(this); - break; - case DrawingModes.SpeechBubble: - _undrawnElement = new SpeechbubbleContainer(this); - break; - case DrawingModes.StepLabel: - _undrawnElement = new StepLabelContainer(this); - break; - case DrawingModes.Line: - _undrawnElement = new LineContainer(this); - break; - case DrawingModes.Arrow: - _undrawnElement = new ArrowContainer(this); - break; - case DrawingModes.Highlight: - _undrawnElement = new HighlightContainer(this); - break; - case DrawingModes.Obfuscate: - _undrawnElement = new ObfuscateContainer(this); - break; - case DrawingModes.Crop: - _cropContainer = new CropContainer(this); - _undrawnElement = _cropContainer; - break; - case DrawingModes.Bitmap: - _undrawnElement = new ImageContainer(this); - break; - case DrawingModes.Path: - _undrawnElement = new FreehandContainer(this); - break; - case DrawingModes.None: - _undrawnElement = null; - break; - } - if (_undrawnElement != null) - { - FieldAggregator.BindElement(_undrawnElement); - } - } - - #region Plugin interface implementations - public IImageContainer AddImageContainer(Image image, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this) - { - Image = image, - Left = x, - Top = y - }; - AddElement(bitmapContainer); - return bitmapContainer; - } - - public IImageContainer AddImageContainer(string filename, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this); - bitmapContainer.Load(filename); - bitmapContainer.Left = x; - bitmapContainer.Top = y; - AddElement(bitmapContainer); - return bitmapContainer; - } - public IIconContainer AddIconContainer(Icon icon, int x, int y) - { - IconContainer iconContainer = new IconContainer(this) - { - Icon = icon, - Left = x, - Top = y - }; - AddElement(iconContainer); - return iconContainer; - } - public IIconContainer AddIconContainer(string filename, int x, int y) - { - IconContainer iconContainer = new IconContainer(this); - iconContainer.Load(filename); - iconContainer.Left = x; - iconContainer.Top = y; - AddElement(iconContainer); - return iconContainer; - } - public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this) - { - Cursor = cursor, - Left = x, - Top = y - }; - AddElement(cursorContainer); - return cursorContainer; - } - public ICursorContainer AddCursorContainer(string filename, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this); - cursorContainer.Load(filename); - cursorContainer.Left = x; - cursorContainer.Top = y; - AddElement(cursorContainer); - return cursorContainer; - } - - public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) - { - TextContainer textContainer = new TextContainer(this) {Text = text}; - textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); - textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); - textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); - textContainer.SetFieldValue(FieldType.FONT_SIZE, size); - textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor); - textContainer.SetFieldValue(FieldType.LINE_COLOR, color); - textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize); - textContainer.SetFieldValue(FieldType.SHADOW, shadow); - // Make sure the Text fits - textContainer.FitToText(); - // Align to Surface - textContainer.AlignToParent(horizontalAlignment, verticalAlignment); - - //AggregatedProperties.UpdateElement(textContainer); - AddElement(textContainer); - return textContainer; - } - #endregion - - #region DragDrop - - private void OnDragEnter(object sender, DragEventArgs e) - { - if (LOG.IsDebugEnabled) - { - LOG.Debug("DragEnter got following formats: "); - foreach (string format in ClipboardHelper.GetFormats(e.Data)) - { - LOG.Debug(format); - } - } - if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) - { - e.Effect = DragDropEffects.None; - } - else - { - if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) - { - e.Effect = DragDropEffects.Copy; - } - else - { - e.Effect = DragDropEffects.None; - } - } - } - - /// - /// Handle the drag/drop - /// - /// - /// - private void OnDragDrop(object sender, DragEventArgs e) - { - Point mouse = PointToClient(new Point(e.X, e.Y)); - if (e.Data.GetDataPresent("Text")) - { - string possibleUrl = ClipboardHelper.GetText(e.Data); - // Test if it's an url and try to download the image so we have it in the original form - if (possibleUrl != null && possibleUrl.StartsWith("http")) - { - using Image image = NetworkHelper.DownloadImage(possibleUrl); - if (image != null) - { - AddImageContainer(image, mouse.X, mouse.Y); - return; - } - } - } - - foreach (Image image in ClipboardHelper.GetImages(e.Data)) - { - AddImageContainer(image, mouse.X, mouse.Y); - mouse.Offset(10, 10); - image.Dispose(); - } - } - - #endregion - - /// - /// Auto crop the image - /// - /// true if cropped - public bool AutoCrop() - { - Rectangle cropRectangle; - using (Image tmpImage = GetImageForExport()) - { - cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); - } - if (!IsCropPossible(ref cropRectangle)) - { - return false; - } - DeselectAllElements(); - // Maybe a bit obscure, but the following line creates a drop container - // It's available as "undrawnElement" - DrawingMode = DrawingModes.Crop; - _undrawnElement.Left = cropRectangle.X; - _undrawnElement.Top = cropRectangle.Y; - _undrawnElement.Width = cropRectangle.Width; - _undrawnElement.Height = cropRectangle.Height; - _undrawnElement.Status = EditStatus.UNDRAWN; - AddElement(_undrawnElement); - SelectElement(_undrawnElement); - _drawingElement = null; - _undrawnElement = null; - return true; - } - - /// - /// A simple clear - /// - /// The color for the background - public void Clear(Color newColor) - { - //create a blank bitmap the same size as original - Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); - if (newBitmap != null) - { - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); - SetImage(newBitmap, false); - Invalidate(); - } - } - - /// - /// Apply a bitmap effect to the surface - /// - /// - public void ApplyBitmapEffect(IEffect effect) - { - BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); - backgroundForm.Show(); - Application.DoEvents(); - try - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Matrix matrix = new Matrix(); - Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); - if (newImage != null) - { - // Make sure the elements move according to the offset the effect made the bitmap move - _elements.Transform(matrix); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - SetImage(newImage, false); - Invalidate(); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) - { - _surfaceSizeChanged(this, null); - } - } - else - { - // clean up matrix, as it hasn't been used in the undo stack. - matrix.Dispose(); - } - } - finally - { - // Always close the background form - backgroundForm.CloseDialog(); - } - } - - /// - /// check if a crop is possible - /// - /// - /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) - { - cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); - if (cropRectangle.Left < 0) - { - cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top < 0) - { - cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); - } - if (cropRectangle.Left + cropRectangle.Width > Width) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top + cropRectangle.Height > Height) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); - } - if (cropRectangle.Height > 0 && cropRectangle.Width > 0) - { - return true; - } - return false; - } - - /// - /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area - /// - /// Who send - /// Type of message - /// Message itself - public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) - { - if (_surfaceMessage != null) - { - var eventArgs = new SurfaceMessageEventArgs - { - Message = message, - MessageType = messageType, - Surface = this - }; - _surfaceMessage(source, eventArgs); - } - } - - /// - /// Crop the surface - /// - /// - /// - public bool ApplyCrop(Rectangle cropRectangle) - { - if (IsCropPossible(ref cropRectangle)) - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage; - // Make sure we have information, this this fails - try - { - tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } - catch (Exception ex) - { - ex.Data.Add("CropRectangle", cropRectangle); - ex.Data.Add("Width", Image.Width); - ex.Data.Add("Height", Image.Height); - ex.Data.Add("Pixelformat", Image.PixelFormat); - throw; - } - - Matrix matrix = new Matrix(); - matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - - // Do not dispose otherwise we can't undo the image! - SetImage(tmpImage, false); - _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) - { - _surfaceSizeChanged(this, null); - } - Invalidate(); - return true; - } - return false; - } - - /// - /// The background here is the captured image. - /// This is called from the SurfaceBackgroundChangeMemento. - /// - /// - /// - public void UndoBackgroundChange(Image previous, Matrix matrix) - { - SetImage(previous, false); - if (matrix != null) - { - _elements.Transform(matrix); - } - _surfaceSizeChanged?.Invoke(this, null); - Invalidate(); - } - /// - /// Check if an adorner was "hit", and change the cursor if so - /// - /// MouseEventArgs - /// IAdorner - private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) - { - foreach (IDrawableContainer drawableContainer in selectedElements) - { - foreach (IAdorner adorner in drawableContainer.Adorners) - { - - if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) - { - if (adorner.Cursor != null) - { - Cursor = adorner.Cursor; - } - return adorner; - } - } - } - return null; - } - - /// - /// This event handler is called when someone presses the mouse on a surface. - /// - /// - /// - private void SurfaceMouseDown(object sender, MouseEventArgs e) - { - - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseDown(sender, e); - return; - } - - _mouseStart = e.Location; - - // check contextmenu - if (e.Button == MouseButtons.Right) - { - IDrawableContainerList selectedList = null; - if (selectedElements != null && selectedElements.Count > 0) - { - selectedList = selectedElements; - } - else - { - // Single element - IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - if (rightClickedContainer != null) - { - selectedList = new DrawableContainerList(ID) {rightClickedContainer}; - } - } - if (selectedList != null && selectedList.Count > 0) - { - selectedList.ShowContextMenu(e, this); - } - return; - } - - _mouseDown = true; - _isSurfaceMoveMadeUndoable = false; - - if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) - { - RemoveElement(_cropContainer, false); - _cropContainer = null; - _drawingElement = null; - } - - if (_drawingElement == null && DrawingMode != DrawingModes.None) - { - if (_undrawnElement == null) - { - DeselectAllElements(); - if (_undrawnElement == null) - { - CreateUndrawnElement(); - } - } - _drawingElement = _undrawnElement; - // if a new element has been drawn, set location and register it - if (_drawingElement != null) - { - if (_undrawnElement != null) - { - _drawingElement.Status = _undrawnElement.DefaultEditMode; - } - if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) - { - _drawingElement.Left = _mouseStart.X; - _drawingElement.Top = _mouseStart.Y; - } - AddElement(_drawingElement); - _drawingElement.Selected = true; - } - _undrawnElement = null; - } - else - { - // check whether an existing element was clicked - // we save mouse down element separately from selectedElements (checked on mouse up), - // since it could be moved around before it is actually selected - _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.MOVING; - } - } - } - - /// - /// This event handle is called when the mouse button is unpressed - /// - /// - /// - private void SurfaceMouseUp(object sender, MouseEventArgs e) - { - - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseUp(sender, e); - return; - } - - Point currentMouse = new Point(e.X, e.Y); - - _elements.Status = EditStatus.IDLE; - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.IDLE; - } - _mouseDown = false; - _mouseDownElement = null; - if (DrawingMode == DrawingModes.None) - { - // check whether an existing element was clicked - IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - if (element != null) - { - element.Invalidate(); - bool alreadySelected = selectedElements.Contains(element); - if (shiftModifier) - { - if (alreadySelected) - { - DeselectElement(element); - } - else - { - SelectElement(element); - } - } - else - { - if (!alreadySelected) - { - DeselectAllElements(); - SelectElement(element); - } - } - } - else if (!shiftModifier) - { - DeselectAllElements(); - } - } - - if (selectedElements.Count > 0) - { - selectedElements.Invalidate(); - selectedElements.Selected = true; - } - - if (_drawingElement != null) - { - if (!_drawingElement.InitContent()) - { - _elements.Remove(_drawingElement); - _drawingElement.Invalidate(); - } - else - { - _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); - _drawingElement.Invalidate(); - if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) - { - _drawingElement.Width = 25; - _drawingElement.Height = 25; - } - SelectElement(_drawingElement); - _drawingElement.Selected = true; - } - _drawingElement = null; - } - } - - /// - /// This event handler is called when the mouse moves over the surface - /// - /// - /// - private void SurfaceMouseMove(object sender, MouseEventArgs e) - { - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseMove(sender, e); - return; - } - - Point currentMouse = e.Location; - - Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; - - if (_mouseDown) - { - if (_mouseDownElement != null) - { // an element is currently dragged - _mouseDownElement.Invalidate(); - selectedElements.Invalidate(); - // Move the element - if (_mouseDownElement.Selected) - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - selectedElements.MakeBoundsChangeUndoable(false); - } - // dragged element has been selected before -> move all - selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - else - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - _mouseDownElement.MakeBoundsChangeUndoable(false); - } - // dragged element is not among selected elements -> just move dragged one - _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - _mouseStart = currentMouse; - _mouseDownElement.Invalidate(); - _modified = true; - } - else if (_drawingElement != null) - { - _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); - _modified = true; - } - } - } - - /// - /// This event handler is called when the surface is double clicked. - /// - /// - /// - private void SurfaceDoubleClick(object sender, MouseEventArgs e) - { - selectedElements.OnDoubleClick(); - selectedElements.Invalidate(); - } - - /// - /// Privately used to get the rendered image with all the elements on it. - /// - /// - /// - private Image GetImage(RenderMode renderMode) - { - // Generate a copy of the original image with a dpi equal to the default... - Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); - // otherwise we would have a problem drawing the image to the surface... :( - using (Graphics graphics = Graphics.FromImage(clone)) - { - // Do not set the following, the containers need to decide themselves - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size)); - } - return clone; - } - - /// - /// This returns the image "result" of this surface, with all the elements rendered on it. - /// - /// - public Image GetImageForExport() - { - return GetImage(RenderMode.EXPORT); - } - - /// - /// This is the event handler for the Paint Event, try to draw as little as possible! - /// - /// - /// PaintEventArgs - private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - Rectangle clipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(clipRectangle)) - { - LOG.Debug("Empty cliprectangle??"); - return; - } - - if (_elements.HasIntersectingFilters(clipRectangle)) - { - if (_buffer != null) - { - if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) - { - _buffer.Dispose(); - _buffer = null; - } - } - if (_buffer == null) - { - _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); - LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); - } - // Elements might need the bitmap, so we copy the part we need - using (Graphics graphics = Graphics.FromImage(_buffer)) - { - // do not set the following, the containers need to decide this themselves! - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - DrawBackground(graphics, clipRectangle); - graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(targetGraphics); - _elements.Draw(graphics, _buffer, RenderMode.EDIT, clipRectangle); - } - targetGraphics.DrawImage(_buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - } - else - { - DrawBackground(targetGraphics, clipRectangle); - targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle); - } - - // No clipping for the adorners - targetGraphics.ResetClip(); - // Draw adorners last - foreach (var drawableContainer in selectedElements) - { - foreach (var adorner in drawableContainer.Adorners) - { - adorner.Paint(paintEventArgs); - } - } - } - - private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) - { - // check if we need to draw the checkerboard - if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) - { - targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); - } - else - { - targetGraphics.Clear(BackColor); - } - } - - /// - /// Draw a checkboard when capturing with transparency - /// - /// PaintEventArgs - protected override void OnPaintBackground(PaintEventArgs e) - { - } - - /// - /// Add a new element to the surface - /// - /// the new element - /// true if the adding should be undoable - /// true if invalidate needs to be called - public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) - { - _elements.Add(element); - if (element is DrawableContainer container) - { - container.FieldChanged += Element_FieldChanged; - } - element.Parent = this; - if (element.Status == EditStatus.UNDRAWN) - { - element.Status = EditStatus.IDLE; - } - if (element.Selected) - { - // Use false, as the element is invalidated when invalidate == true anyway - SelectElement(element, false); - } - if (invalidate) - { - element.Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new AddElementMemento(this, element), false); - } - _modified = true; - } - - /// - /// Remove the list of elements - /// - /// IDrawableContainerList - /// flag specifying if the remove needs to be undoable - public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToRemove); - if (makeUndoable) - { - MakeUndoable(new DeleteElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var drawableContainer in cloned) - { - RemoveElement(drawableContainer, false, false, false); - } - ResumeLayout(); - Invalidate(); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = cloned}; - _movingElementChanged(this, eventArgs); - } - } - - /// - /// Remove an element of the elements list - /// - /// Element to remove - /// flag specifying if the remove needs to be undoable - /// flag specifying if an surface invalidate needs to be called - /// false to skip event generation - public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) - { - DeselectElement(elementToRemove, generateEvents); - _elements.Remove(elementToRemove); - if (elementToRemove is DrawableContainer element) - { - element.FieldChanged -= Element_FieldChanged; - } - if (elementToRemove != null) - { - elementToRemove.Parent = null; - } - // Do not dispose, the memento should!! element.Dispose(); - if (invalidate) - { - Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); - } - _modified = true; - } - - /// - /// Add the supplied elements to the surface - /// - /// DrawableContainerList - /// true if the adding should be undoable - public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToAdd); - if (makeUndoable) - { - MakeUndoable(new AddElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var element in cloned) - { - element.Selected = true; - AddElement(element, false, false); - } - ResumeLayout(); - Invalidate(); - } - - /// - /// Returns if this surface has selected elements - /// - /// - public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); - - /// - /// Remove all the selected elements - /// - public void RemoveSelectedElements() - { - if (HasSelectedElements) - { - // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. - RemoveElements(selectedElements); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - _movingElementChanged(this, eventArgs); - } - } - } - - /// - /// Cut the selected elements from the surface to the clipboard - /// - public void CutSelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - RemoveSelectedElements(); - } - } - - /// - /// Copy the selected elements to the clipboard - /// - public void CopySelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - } - } - - /// - /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. - /// Called when pressing enter or using the "check" in the editor. - /// - /// - public void ConfirmSelectedConfirmableElements(bool confirm) - { - // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) - List selectedDCs = new List(selectedElements); - foreach (IDrawableContainer dc in selectedDCs) - { - if (dc.Equals(_cropContainer)) - { - DrawingMode = DrawingModes.None; - // No undo memento for the cropcontainer itself, only for the effect - RemoveElement(_cropContainer, false); - if (confirm) - { - ApplyCrop(_cropContainer.Bounds); - } - _cropContainer.Dispose(); - _cropContainer = null; - break; - } - } - } - - /// - /// Paste all the elements that are on the clipboard - /// - public void PasteElementFromClipboard() - { - IDataObject clipboard = ClipboardHelper.GetDataObject(); - - var formats = ClipboardHelper.GetFormats(clipboard); - if (formats == null || formats.Count == 0) - { - return; - } - if (LOG.IsDebugEnabled) - { - LOG.Debug("List of clipboard formats available for pasting:"); - foreach (string format in formats) - { - LOG.Debug("\tgot format: " + format); - } - } - - if (formats.Contains(typeof(IDrawableContainerList).FullName)) - { - IDrawableContainerList dcs = (IDrawableContainerList)ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); - if (dcs != null) - { - // Make element(s) only move 10,10 if the surface is the same - bool isSameSurface = (dcs.ParentID == _uniqueId); - dcs.Parent = this; - var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; - // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList - Rectangle drawableContainerListBounds = Rectangle.Empty; - foreach (var element in dcs) - { - drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty ? element.DrawingBounds : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); - } - // And find a location inside the target surface to paste to - bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; - if (!containersCanFit) - { - Point containersLocation = drawableContainerListBounds.Location; - containersLocation.Offset(moveOffset); - if (!Bounds.Contains(containersLocation)) - { - // Easy fix for same surface - moveOffset = isSameSurface ? new Point(-10, -10) : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); - } - } - else - { - Rectangle moveContainerListBounds = drawableContainerListBounds; - moveContainerListBounds.Offset(moveOffset); - // check if the element is inside - if (!Bounds.Contains(moveContainerListBounds)) - { - // Easy fix for same surface - if (isSameSurface) - { - moveOffset = new Point(-10, -10); - } - else - { - // For different surface, which is most likely smaller - int offsetX = 0; - int offsetY = 0; - if (drawableContainerListBounds.Right > Bounds.Right) - { - offsetX = Bounds.Right - drawableContainerListBounds.Right; - // Correction for the correction - if (drawableContainerListBounds.Left + offsetX < 0) - { - offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); - } - } - if (drawableContainerListBounds.Bottom > Bounds.Bottom) - { - offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; - // Correction for the correction - if (drawableContainerListBounds.Top + offsetY < 0) - { - offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); - } - } - moveOffset = new Point(offsetX, offsetY); - } - } - } - dcs.MoveBy(moveOffset.X, moveOffset.Y); - AddElements(dcs); - FieldAggregator.BindElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } - } - else if (ClipboardHelper.ContainsImage(clipboard)) - { - int x = 10; - int y = 10; - - // FEATURE-995: Added a check for the current mouse cursor location, to paste the image on that location. - var mousePositionOnControl = PointToClient(MousePosition); - if (ClientRectangle.Contains(mousePositionOnControl)) - { - x = mousePositionOnControl.X; - y = mousePositionOnControl.Y; - } - - foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) - { - if (clipboardImage != null) - { - DeselectAllElements(); - IImageContainer container = AddImageContainer(clipboardImage as Bitmap, x, y); - SelectElement(container); - clipboardImage.Dispose(); - x += 10; - y += 10; - } - } - } - else if (ClipboardHelper.ContainsText(clipboard)) - { - string text = ClipboardHelper.GetText(clipboard); - if (text != null) - { - DeselectAllElements(); - ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, - FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); - SelectElement(textContainer); - } - } - } - - /// - /// Duplicate all the selecteded elements - /// - public void DuplicateSelectedElements() - { - LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); - IDrawableContainerList dcs = selectedElements.Clone(); - dcs.Parent = this; - dcs.MoveBy(10, 10); - AddElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } - - /// - /// Deselect the specified element - /// - /// IDrawableContainerList - /// false to skip event generation - public void DeselectElement(IDrawableContainer container, bool generateEvents = true) - { - container.Selected = false; - selectedElements.Remove(container); - FieldAggregator.UnbindElement(container); - if (generateEvents && _movingElementChanged != null) - { - var eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - } - - /// - /// Deselect the specified elements - /// - /// IDrawableContainerList - public void DeselectElements(IDrawableContainerList elements) - { - if (elements.Count == 0) - { - return; - } - while (elements.Count > 0) - { - var element = elements[0]; - DeselectElement(element, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - Invalidate(); - } - - /// - /// Deselect all the selected elements - /// - public void DeselectAllElements() - { - DeselectElements(selectedElements); - } - - /// - /// Select the supplied element - /// - /// - /// false to skip invalidation - /// false to skip event generation - public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) - { - if (!selectedElements.Contains(container)) - { - selectedElements.Add(container); - container.Selected = true; - FieldAggregator.BindElement(container); - if (generateEvents && _movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - if (invalidate) - { - container.Invalidate(); - } - } - } - - /// - /// Select all elements, this is called when Ctrl+A is pressed - /// - public void SelectAllElements() - { - SelectElements(_elements); - } - - /// - /// Select the supplied elements - /// - /// - public void SelectElements(IDrawableContainerList elements) - { - SuspendLayout(); - foreach (var drawableContainer in elements) - { - var element = (DrawableContainer) drawableContainer; - SelectElement(element, false, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - ResumeLayout(); - Invalidate(); - } - - /// - /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control) - /// - /// Keys - /// false if no keys were processed - public bool ProcessCmdKey(Keys k) - { - if (selectedElements.Count > 0) - { - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - int px = shiftModifier ? 10 : 1; - Point moveBy = Point.Empty; - - switch (k) - { - case Keys.Left: - case Keys.Left | Keys.Shift: - moveBy = new Point(-px, 0); - break; - case Keys.Up: - case Keys.Up | Keys.Shift: - moveBy = new Point(0, -px); - break; - case Keys.Right: - case Keys.Right | Keys.Shift: - moveBy = new Point(px, 0); - break; - case Keys.Down: - case Keys.Down | Keys.Shift: - moveBy = new Point(0, px); - break; - case Keys.PageUp: - PullElementsUp(); - break; - case Keys.PageDown: - PushElementsDown(); - break; - case Keys.Home: - PullElementsToTop(); - break; - case Keys.End: - PushElementsToBottom(); - break; - case Keys.Enter: - ConfirmSelectedConfirmableElements(true); - break; - case Keys.Escape: - ConfirmSelectedConfirmableElements(false); - break; - /*case Keys.Delete: - RemoveSelectedElements(); - break;*/ - default: - return false; - } - if (!Point.Empty.Equals(moveBy)) - { - selectedElements.MakeBoundsChangeUndoable(true); - selectedElements.MoveBy(moveBy.X, moveBy.Y); - } - return true; - } - return false; - } - - /// - /// Property for accessing the elements on the surface - /// - public IDrawableContainerList Elements => _elements; - - /// - /// pulls selected elements up one level in hierarchy - /// - public void PullElementsUp() - { - _elements.PullElementsUp(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements up to top in hierarchy - /// - public void PullElementsToTop() - { - _elements.PullElementsToTop(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements down one level in hierarchy - /// - public void PushElementsDown() - { - _elements.PushElementsDown(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements down to bottom in hierarchy - /// - public void PushElementsToBottom() - { - _elements.PushElementsToBottom(selectedElements); - _elements.Invalidate(); - } - - /// - /// indicates whether the selected elements could be pulled up in hierarchy - /// - /// true if selected elements could be pulled up, false otherwise - public bool CanPullSelectionUp() - { - return _elements.CanPullUp(selectedElements); - } - - /// - /// indicates whether the selected elements could be pushed down in hierarchy - /// - /// true if selected elements could be pushed down, false otherwise - public bool CanPushSelectionDown() - { - return _elements.CanPushDown(selectedElements); - } - - public void Element_FieldChanged(object sender, FieldChangedEventArgs e) - { - selectedElements.HandleFieldChangedEvent(sender, e); - } - - public bool IsOnSurface(IDrawableContainer container) - { - return _elements.Contains(container); - } - } -} diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs deleted file mode 100644 index 0be368cbe..000000000 --- a/Greenshot/Forms/AboutForm.cs +++ /dev/null @@ -1,333 +0,0 @@ -/* -* Greenshot - a free and open source screenshot tool -* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom -* -* For more information see: http://getgreenshot.org/ -* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -* -* 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 1 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; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Security.Permissions; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using log4net; - -namespace Greenshot.Forms { - /// - /// The about form - /// - public sealed partial class AboutForm : AnimatingBaseForm { - private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); - private Bitmap _bitmap; - private readonly ColorAnimator _backgroundAnimation; - private readonly List _pixels = new List(); - private readonly List _colorFlow = new List(); - private readonly List _pixelColors = new List(); - private readonly Random _rand = new Random(); - private readonly Color _backColor = Color.FromArgb(61, 61, 61); - private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); - - // Variables used for the color-cycle - private int _waitFrames; - private int _colorIndex; - private int _scrollCount; - private bool _hasAnimationsLeft; - - // Variables are used to define the location of the dots - private const int W = 13; - private const int P1 = 7; - private const int P2 = P1 + W; - private const int P3 = P2 + W; - private const int P4 = P3 + W; - private const int P5 = P4 + W; - private const int P6 = P5 + W; - private const int P7 = P6 + W; - - /// - /// The location of every dot in the "G" - /// - private readonly List _gSpots = new List - { - // Top row - new Point(P2, P1), // 0 - new Point(P3, P1), // 1 - new Point(P4, P1), // 2 - new Point(P5, P1), // 3 - new Point(P6, P1), // 4 - - // Second row - new Point(P1, P2), // 5 - new Point(P2, P2), // 6 - - // Third row - new Point(P1, P3), // 7 - new Point(P2, P3), // 8 - - // Fourth row - new Point(P1, P4), // 9 - new Point(P2, P4), // 10 - new Point(P5, P4), // 11 - new Point(P6, P4), // 12 - new Point(P7, P4), // 13 - - // Fifth row - new Point(P1, P5), // 14 - new Point(P2, P5), // 15 - new Point(P6, P5), // 16 - new Point(P7, P5), // 17 - - // Sixth row - new Point(P1, P6), // 18 - new Point(P2, P6), // 19 - new Point(P3, P6), // 20 - new Point(P4, P6), // 21 - new Point(P5, P6), // 22 - new Point(P6, P6) // 23 - }; - - // 0 1 2 3 4 - // 5 6 - // 7 8 - // 9 10 11 12 13 - // 14 15 16 17 - // 18 19 20 21 22 23 - - // The order in which we draw the dots & flow the colors. - private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; - - /// - /// Cleanup all the allocated resources - /// - private void Cleanup(object sender, EventArgs e) { - if (_bitmap == null) return; - _bitmap.Dispose(); - _bitmap = null; - } - - /// - /// Constructor - /// - public AboutForm() { - // Make sure our resources are removed again. - Disposed += Cleanup; - FormClosing += Cleanup; - - // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. - EnableAnimation = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - - // Only use double-buffering when we are NOT in a Terminal Server session - DoubleBuffered = !IsTerminalServerSession; - - // Use the self drawn image, first we create the background to be the back-color (as we animate from this) - - _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); - pictureBox1.Image = _bitmap; - - lblTitle.Text = $@"Greenshot {EnvironmentInfo.GetGreenshotVersion()} {(IniConfig.IsPortable ? " Portable" : "")} ({OsInfo.Bits}) bit)"; - - // Number of frames the pixel animation takes - int frames = FramesForMillis(2000); - // The number of frames the color-cycle waits before it starts - _waitFrames = FramesForMillis(6000); - - // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. - int pixelWaitFrames = FramesForMillis(2000); - // Create pixels - for (int index = 0; index < _gSpots.Count; index++) { - // Read the pixels in the order of the flow - Point gSpot = _gSpots[_flowOrder[index]]; - // Create the animation, first we do nothing (on the final destination) - RectangleAnimator pixelAnimation; - - // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted - int offset = (W - 2) / 2; - - // If the optimize for Terminal Server is set we make the animation without much ado - if (IsTerminalServerSession) { - // No animation - pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); - } else { - // Create the animation, first we do nothing (on the final destination) - Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); - pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); - // And than we size to the wanted size. - pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); - } - // Increase the wait frames - pixelWaitFrames += FramesForMillis(100); - // Add to the list of to be animated pixels - _pixels.Add(pixelAnimation); - // Add a color to the list for this pixel. - _pixelColors.Add(_pixelColor); - } - // Make sure the frame "loop" knows we have to animate - _hasAnimationsLeft = true; - - // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. - ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); - pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); - do { - _colorFlow.Add(pixelColorAnimator.Current); - pixelColorAnimator.Next(); - } while (pixelColorAnimator.HasNext); - - // color animation for the background - _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); - } - - /// - /// This is called when a link is clicked - /// - /// - /// - private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - if (!(sender is LinkLabel linkLabel)) return; - try { - linkLabel.LinkVisited = true; - Process.Start(linkLabel.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); - } - } - - /// - /// Called from the AnimatingForm, for every frame - /// - protected override void Animate() { - if (_bitmap == null) { - return; - } - if (!IsTerminalServerSession) { - // Color cycle - if (_waitFrames != 0) { - _waitFrames--; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) { - // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. - for (int index = _pixelColors.Count - 1; index > 0; index--) { - _pixelColors[index] = _pixelColors[index - 1]; - } - // Keep adding from the colors to cycle until there is nothing left - if (_colorIndex < _colorFlow.Count) { - _pixelColors[0] = _colorFlow[_colorIndex++]; - } - _scrollCount++; - } else { - // Reset values, wait X time for the next one - _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); - _colorIndex = 0; - _scrollCount = 0; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } - } else if (!_hasAnimationsLeft) { - return; - } - - // Draw the "G" - using (Graphics graphics = Graphics.FromImage(_bitmap)) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - graphics.Clear(_backgroundAnimation.Next()); - - graphics.TranslateTransform(2, -2); - graphics.RotateTransform(20); - - using SolidBrush brush = new SolidBrush(_pixelColor); - int index = 0; - // We assume there is nothing to animate in the next Animate loop - _hasAnimationsLeft = false; - // Pixels of the G - foreach (RectangleAnimator pixel in _pixels) { - brush.Color = _pixelColors[index++]; - graphics.FillEllipse(brush, pixel.Current); - // If a pixel still has frames left, the hasAnimationsLeft will be true - _hasAnimationsLeft |= pixel.HasNext; - pixel.Next(); - } - } - pictureBox1.Invalidate(); - } - - /// - /// CmdKey handler - /// - /// - /// - /// - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - try { - switch (keyData) { - case Keys.Escape: - DialogResult = DialogResult.Cancel; - break; - case Keys.E: - MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); - break; - case Keys.L: - try { - if (File.Exists(MainForm.LogFileLocation)) { - using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) { - // nothing to do, just using dispose to cleanup - } - } else { - MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - case Keys.I: - try { - using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) { - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - default: - return base.ProcessCmdKey(ref msg, keyData); - } - } catch (Exception ex) { - Log.Error($"Error handling key '{keyData}'", ex); - } - return true; - } - } -} \ No newline at end of file diff --git a/Greenshot/Forms/AnimatingBaseForm.cs b/Greenshot/Forms/AnimatingBaseForm.cs deleted file mode 100644 index db1c2b54d..000000000 --- a/Greenshot/Forms/AnimatingBaseForm.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Controls; - -namespace Greenshot { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class AnimatingBaseForm : AnimatingForm { - } -} diff --git a/Greenshot/Forms/BaseForm.cs b/Greenshot/Forms/BaseForm.cs deleted file mode 100644 index 392f37803..000000000 --- a/Greenshot/Forms/BaseForm.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 GreenshotPlugin.Controls; - -namespace Greenshot { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class BaseForm : GreenshotForm { - } -} diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs deleted file mode 100644 index f74aa431d..000000000 --- a/Greenshot/Forms/BugReportForm.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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.Diagnostics; -using System.Windows.Forms; -using Greenshot.Configuration; -using GreenshotPlugin.Core; - -namespace Greenshot.Forms { - public partial class BugReportForm : BaseForm { - private BugReportForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - ToFront = true; - } - - public BugReportForm(string bugText) : this() { - textBoxDescription.Text = bugText; - } - - private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - openLink((LinkLabel)sender); - } - - private void openLink(LinkLabel link) { - try { - link.LinkVisited = true; - Process.Start(link.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); - } - } - } -} diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs deleted file mode 100644 index bad4a0d24..000000000 --- a/Greenshot/Forms/CaptureForm.cs +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Drawing; -using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Globalization; -using System.Security.Permissions; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; - -namespace Greenshot.Forms { - /// - /// The capture form is used to select a part of the capture - /// - public sealed partial class CaptureForm : AnimatingForm { - private enum FixMode {None, Initiated, Horizontal, Vertical}; - - private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); - private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); - private static CaptureForm _currentForm; - private static readonly Brush BackgroundBrush; - - /// - /// Initialize the background brush - /// - static CaptureForm() { - Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); - BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); - } - - private int _mX; - private int _mY; - private Point _mouseMovePos = Point.Empty; - private Point _cursorPos; - private CaptureMode _captureMode; - private readonly List _windows; - private WindowDetails _selectedCaptureWindow; - private bool _mouseDown; - private Rectangle _captureRect = Rectangle.Empty; - private readonly ICapture _capture; - private Point _previousMousePos = Point.Empty; - private FixMode _fixMode = FixMode.None; - private RectangleAnimator _windowAnimator; - private RectangleAnimator _zoomAnimator; - private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; - private bool _isCtrlPressed; - private bool _showDebugInfo; - - /// - /// Property to access the selected capture rectangle - /// - public Rectangle CaptureRectangle => _captureRect; - - /// - /// Property to access the used capture mode - /// - public CaptureMode UsedCaptureMode => _captureMode; - - /// - /// Get the selected window - /// - public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; - - /// - /// This should prevent children to draw backgrounds - /// - protected override CreateParams CreateParams { - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - get { - CreateParams createParams = base.CreateParams; - createParams.ExStyle |= 0x02000000; - return createParams; - } - } - - private void ClosedHandler(object sender, EventArgs e) { - _currentForm = null; - // Change the final mode - if (_captureMode == CaptureMode.Text) - { - _capture.CaptureDetails.CaptureMode = CaptureMode.Text; - } - Log.Debug("Remove CaptureForm from currentForm"); - } - - private void ClosingHandler(object sender, EventArgs e) { - Log.Debug("Closing capture form"); - WindowDetails.UnregisterIgnoreHandle(Handle); - } - - /// - /// This creates the capture form - /// - /// - /// - public CaptureForm(ICapture capture, List windows) { - if (_currentForm != null) { - Log.Warn("Found currentForm, Closing already opened CaptureForm"); - _currentForm.Close(); - _currentForm = null; - Application.DoEvents(); - } - _currentForm = this; - - // Enable the AnimatingForm - EnableAnimation = true; - - // clean up - FormClosed += ClosedHandler; - - _capture = capture; - _windows = windows; - _captureMode = capture.CaptureDetails.CaptureMode; - - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - // Only double-buffer when we are not in a TerminalServerSession - DoubleBuffered = !IsTerminalServerSession; - Text = @"Greenshot capture form"; - - // Make sure we never capture the capture-form - WindowDetails.RegisterIgnoreHandle(Handle); - // Un-register at close - FormClosing += ClosingHandler; - - // set cursor location - _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - - // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor - if (_captureMode == CaptureMode.Window) { - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - } - - // Set the zoomer animation - InitializeZoomer(Conf.ZoomerEnabled); - - SuspendLayout(); - Bounds = capture.ScreenBounds; - ResumeLayout(); - - // Fix missing focus - ToFront = true; - TopMost = true; - } - - /// - /// Create an animation for the zoomer, depending on if it's active or not. - /// - private void InitializeZoomer(bool isOn) { - if (isOn) { - // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); - VerifyZoomAnimation(_cursorPos, false); - } - else - { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); - } - } - - private void CaptureFormKeyUp(object sender, KeyEventArgs e) { - switch(e.KeyCode) { - case Keys.ShiftKey: - _fixMode = FixMode.None; - break; - case Keys.ControlKey: - _isCtrlPressed = false; - break; - } - } - - /// - /// Handle the key down event - /// - /// - /// - private void CaptureFormKeyDown(object sender, KeyEventArgs e) { - int step = _isCtrlPressed ? 10 : 1; - - switch (e.KeyCode) { - case Keys.Up: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); - break; - case Keys.Down: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); - break; - case Keys.Left: - Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); - break; - case Keys.Right: - Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); - break; - case Keys.ShiftKey: - // Fix mode - if (_fixMode == FixMode.None) { - _fixMode = FixMode.Initiated; - } - break; - case Keys.ControlKey: - _isCtrlPressed = true; - break; - case Keys.Escape: - // Cancel - DialogResult = DialogResult.Cancel; - break; - case Keys.M: - // Toggle mouse cursor - _capture.CursorVisible = !_capture.CursorVisible; - Invalidate(); - break; - //// TODO: Enable when the screen capture code works reliable - //case Keys.V: - // // Video - // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { - // capture.CaptureDetails.CaptureMode = CaptureMode.Video; - // } else { - // capture.CaptureDetails.CaptureMode = captureMode; - // } - // Invalidate(); - // break; - case Keys.Z: - if (_captureMode == CaptureMode.Region) { - // Toggle zoom - Conf.ZoomerEnabled = !Conf.ZoomerEnabled; - InitializeZoomer(Conf.ZoomerEnabled); - Invalidate(); - } - break; - case Keys.D: - if (_captureMode == CaptureMode.Window) - { - // Toggle debug - _showDebugInfo = !_showDebugInfo; - Invalidate(); - } - break; - case Keys.Space: - // Toggle capture mode - switch (_captureMode) { - case CaptureMode.Region: - // Set the window capture mode - _captureMode = CaptureMode.Window; - // "Fade out" Zoom - InitializeZoomer(false); - // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - case CaptureMode.Text: - // Set the region capture mode - _captureMode = CaptureMode.Region; - Invalidate(); - break; - case CaptureMode.Window: - // Set the region capture mode - _captureMode = CaptureMode.Region; - // "Fade out" window - _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); - // Fade in zoom - InitializeZoomer(Conf.ZoomerEnabled); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - } - _selectedCaptureWindow = null; - OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); - break; - case Keys.Return: - // Confirm - if (_captureMode == CaptureMode.Window) { - DialogResult = DialogResult.OK; - } else if (!_mouseDown) { - HandleMouseDown(); - } else if (_mouseDown) { - HandleMouseUp(); - } - break; - case Keys.F: - ToFront = !ToFront; - TopMost = !TopMost; - break; - case Keys.T: - _captureMode = CaptureMode.Text; - if (_capture.CaptureDetails.OcrInformation is null) - { - var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - if (ocrProvider != null) - { - var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); - - Task.Factory.StartNew(async () => - { - _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); - Invalidate(); - }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); - } - } - else - { - Invalidate(); - } - break; - } - } - - /// - /// The mousedown handler of the capture form - /// - /// - /// - private void OnMouseDown(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - HandleMouseDown(); - } - } - - private void HandleMouseDown() { - Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - _mX = tmpCursorLocation.X; - _mY = tmpCursorLocation.Y; - _mouseDown = true; - OnMouseMove(this, null); - Invalidate(); - } - - private void HandleMouseUp() { - // If the mouse goes up we set down to false (nice logic!) - _mouseDown = false; - // Check if anything is selected - if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) { - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureRect.Height > 0 && _captureRect.Width > 0) { - // correct the GUI width to real width if Region mode - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - _captureRect.Width += 1; - _captureRect.Height += 1; - } - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) - { - // Handle a click on a single word - _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); - // Go and process the capture - DialogResult = DialogResult.OK; - } else { - Invalidate(); - } - - } - - /// - /// - /// - /// - /// - private bool IsWordUnderCursor(Point cursorLocation) - { - if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (lineBounds.IsEmpty) continue; - // Highlight the text which is selected - if (!lineBounds.Contains(cursorLocation)) continue; - foreach (var word in line.Words) - { - if (word.Bounds.Contains(cursorLocation)) - { - return true; - } - } - } - - return false; - } - - /// - /// The mouse up handler of the capture form - /// - /// - /// - private void OnMouseUp(object sender, MouseEventArgs e) { - if (_mouseDown) { - HandleMouseUp(); - } - } - - /// - /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed - /// - /// - /// - private Point FixMouseCoordinates(Point currentMouse) { - if (_fixMode == FixMode.Initiated) { - if (_previousMousePos.X != currentMouse.X) { - _fixMode = FixMode.Vertical; - } else if (_previousMousePos.Y != currentMouse.Y) { - _fixMode = FixMode.Horizontal; - } - } else if (_fixMode == FixMode.Vertical) { - currentMouse = new Point(currentMouse.X, _previousMousePos.Y); - } else if (_fixMode == FixMode.Horizontal) { - currentMouse = new Point(_previousMousePos.X, currentMouse.Y); - } - _previousMousePos = currentMouse; - return currentMouse; - } - - /// - /// The mouse move handler of the capture form - /// - /// object - /// MouseEventArgs - private void OnMouseMove(object sender, MouseEventArgs e) { - // Make sure the mouse coordinates are fixed, when pressing shift - var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); - _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); - } - - /// - /// Helper method to simplify check - /// - /// - /// - private bool IsAnimating(IAnimator animator) { - if (animator == null) { - return false; - } - return animator.HasNext; - } - - /// - /// update the frame, this only invalidates - /// - protected override void Animate() { - Point lastPos = _cursorPos; - _cursorPos = _mouseMovePos; - - if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) { - return; - } - - WindowDetails lastWindow = _selectedCaptureWindow; - bool horizontalMove = false; - bool verticalMove = false; - - if (lastPos.X != _cursorPos.X) { - horizontalMove = true; - } - if (lastPos.Y != _cursorPos.Y) { - verticalMove = true; - } - - if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) { - _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); - } - - // Iterate over the found windows and check if the current location is inside a window - Point cursorPosition = Cursor.Position; - _selectedCaptureWindow = null; - lock (_windows) { - foreach (var window in _windows) { - if (!window.Contains(cursorPosition)) - { - continue; - } - // Only go over the children if we are in window mode - _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; - break; - } - } - - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); - if (_captureMode == CaptureMode.Window) { - // Here we want to capture the window which is under the mouse - _captureRect = _selectedCaptureWindow.WindowRectangle; - // As the ClientRectangle is not in Bitmap coordinates, we need to correct. - _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); - } - } - - Rectangle invalidateRectangle; - if (_mouseDown && (_captureMode != CaptureMode.Window)) { - int x1 = Math.Min(_mX, lastPos.X); - int x2 = Math.Max(_mX, lastPos.X); - int y1 = Math.Min(_mY, lastPos.Y); - int y2 = Math.Max(_mY, lastPos.Y); - x1= Math.Min(x1, _cursorPos.X); - x2= Math.Max(x2, _cursorPos.X); - y1= Math.Min(y1, _cursorPos.Y); - y2= Math.Max(y2, _cursorPos.Y); - - // Safety correction - x2 += 2; - y2 += 2; - - // Here we correct for text-size - - // Calculate the size - int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); - int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); - - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); - x1 -= measureWidth.Width + 15; - - Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); - y1 -= measureHeight.Height + 10; - } - invalidateRectangle = new Rectangle(x1,y1, x2-x1, y2-y1); - Invalidate(invalidateRectangle); - } else if (_captureMode != CaptureMode.Window) { - if (!IsTerminalServerSession) { - Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); - allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); - if (verticalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - } - if (horizontalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - } - } - } else { - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - // Window changes, make new animation from current to target - _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); - } - } - // always animate the Window area through to the last frame, so we see the fade-in/out untill the end - // Using a safety "offset" to make sure the text is invalidated too - const int safetySize = 30; - // Check if the animation needs to be drawn - if (IsAnimating(_windowAnimator)) { - invalidateRectangle = _windowAnimator.Current; - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - invalidateRectangle = _windowAnimator.Next(); - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - // Check if this was the last of the windows animations in the normal region capture. - if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) { - Invalidate(); - } - } - - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - // Make sure we invalidate the old zoom area - invalidateRectangle = _zoomAnimator.Current; - invalidateRectangle.Offset(lastPos); - Invalidate(invalidateRectangle); - // Only verify if we are really showing the zoom, not the outgoing animation - if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) { - VerifyZoomAnimation(_cursorPos, false); - } - // The following logic is not needed, next always returns the current if there are no frames left - // but it makes more sense if we want to change something in the logic - invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; - invalidateRectangle.Offset(_cursorPos); - Invalidate(invalidateRectangle); - } - - // OCR - if (_captureMode == CaptureMode.Text && _capture.CaptureDetails.OcrInformation != null) - { - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - invalidateRectangle = Rectangle.Empty; - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) - { - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) - { - foreach (var word in line.Words) - { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - break; - } - } - } - } - if (!invalidateRectangle.IsEmpty) - { - Invalidate(invalidateRectangle); - } - } - // Force update "now" - Update(); - } - - /// - /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. - /// - /// - protected override void OnPaintBackground(PaintEventArgs pevent) { - } - - /// - /// Checks if the Zoom area can move there where it wants to go, change direction if not. - /// - /// preferred destination location for the zoom area - /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle - private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) { - Rectangle screenBounds = Screen.GetBounds(MousePosition); - // convert to be relative to top left corner of all screen bounds - screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); - int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; - // Make sure the final size is a plural of 4, this makes it look better - relativeZoomSize -= relativeZoomSize % 4; - Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); - Point zoomOffset = new Point(20, 20); - - Rectangle targetRectangle = _zoomAnimator.Final; - targetRectangle.Offset(pos); - if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) { - Point destinationLocation = Point.Empty; - Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) { - destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); - } else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); - } else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) { - destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); - } else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); - } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) { - VerifyZoomAnimation(pos, true); - } else { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); - } - } - } - - /// - /// Draw the zoomed area - /// - /// - /// - /// - private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) { - if (_capture.Image == null) { - return; - } - ImageAttributes attributes; - - if (_isZoomerTransparent) { - //create a color matrix object to change the opacy - ColorMatrix opacyMatrix = new ColorMatrix - { - Matrix33 = Conf.ZoomerOpacity - }; - attributes = new ImageAttributes(); - attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - } else { - attributes = null; - } - - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - using (GraphicsPath path = new GraphicsPath()) { - path.AddEllipse(destinationRectangle); - graphics.SetClip(path); - if (!_isZoomerTransparent) { - graphics.FillRectangle(BackgroundBrush, destinationRectangle); - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); - } else { - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes); - } - } - int alpha = (int)(255 * Conf.ZoomerOpacity); - Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); - Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); - - // Draw the circle around the zoomer - using (Pen pen = new Pen(opacyWhite, 2)) { - graphics.DrawEllipse(pen, destinationRectangle); - } - - // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair - graphics.SmoothingMode = SmoothingMode.None; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - // Calculate some values - int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; - int halfWidth = destinationRectangle.Width / 2; - int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; - int halfHeight = destinationRectangle.Height / 2; - int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; - - int drawAtHeight = destinationRectangle.Y + halfHeight; - int drawAtWidth = destinationRectangle.X + halfWidth; - int padding = pixelThickness; - - // Pen to draw - using (Pen pen = new Pen(opacyBlack, pixelThickness)) { - // Draw the cross-hair-lines - // Vertical top to middle - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); - // Vertical middle + 1 to bottom - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, destinationRectangle.Y + destinationRectangle.Width - padding); - // Horizontal left to middle - graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); - // Horizontal middle + 1 to right - graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, drawAtHeight); - - // Fix offset for drawing the white rectangle around the cross-hair-lines - drawAtHeight -= pixelThickness / 2; - drawAtWidth -= pixelThickness / 2; - // Fix off by one error with the DrawRectangle - pixelThickness -= 1; - // Change the color and the pen width - pen.Color = opacyWhite; - pen.Width = 1; - // Vertical top to middle - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Vertical middle + 1 to bottom - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Horizontal left to middle - graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - // Horizontal middle + 1 to right - graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - } - attributes?.Dispose(); - } - - /// - /// Paint the actual visible parts - /// - /// - /// - private void OnPaint(object sender, PaintEventArgs e) { - Graphics graphics = e.Graphics; - Rectangle clipRectangle = e.ClipRectangle; - //graphics.BitBlt((Bitmap)buffer, Point.Empty); - graphics.DrawImageUnscaled(_capture.Image, Point.Empty); - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - if (ocrInfo != null && _captureMode == CaptureMode.Text) - { - using var pen = new Pen(Color.Red); - var highlightColor = Color.FromArgb(128, Color.Yellow); - using var highlightTextBrush = new SolidBrush(highlightColor); - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) - { - graphics.DrawRectangle(pen, line.CalculatedBounds); - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - graphics.FillRectangle(highlightTextBrush, word.Bounds); - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) - { - foreach (var word in line.Words) - { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - graphics.FillRectangle(highlightTextBrush, word.Bounds); - break; - } - } - } - } - } - - // Only draw Cursor if it's (partly) visible - if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) { - graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); - } - - if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) { - _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen - - var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; - - // TODO: enable when the screen capture code works reliable - //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { - // graphics.FillRectangle(RedOverlayBrush, fixedRect); - //} else { - graphics.FillRectangle(GreenOverlayBrush, fixedRect); - //} - graphics.DrawRectangle(OverlayPen, fixedRect); - - // rulers - const int dist = 8; - - string captureWidth; - string captureHeight; - // The following fixes the very old incorrect size information bug - if (_captureMode == CaptureMode.Window) { - captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); - captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); - } else { - captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); - captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); - } - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); - Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); - int hSpace = measureWidth.Width + 3; - int vSpace = measureHeight.Height + 3; - Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); - Pen rulerPen = new Pen(Color.SeaGreen); - - // horizontal ruler - if (fixedRect.Width > hSpace + 3) - { - using GraphicsPath p = RoundedRectangle.Create2( - fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, - fixedRect.Y - dist - 7, - measureWidth.Width - 3, - measureWidth.Height, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2), fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width / 2 + hSpace / 2, fixedRect.Y - dist, fixedRect.X + fixedRect.Width, fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist - 3, fixedRect.X, fixedRect.Y - dist + 3); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3); - } - - // vertical ruler - if (fixedRect.Height > vSpace + 3) - { - using GraphicsPath p = RoundedRectangle.Create2( - fixedRect.X - measureHeight.Width + 1, - fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, - measureHeight.Width - 3, - measureHeight.Height - 1, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y, fixedRect.X - dist, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2)); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y + fixedRect.Height / 2 + vSpace / 2, fixedRect.X - dist, fixedRect.Y + fixedRect.Height); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y, fixedRect.X - dist + 3, fixedRect.Y); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height); - } - - rulerPen.Dispose(); - bgBrush.Dispose(); - } - - // Display size of selected rectangle - // Prepare the font and text. - using Font sizeFont = new Font( FontFamily.GenericSansSerif, 12 ); - // When capturing a Region we need to add 1 to the height/width for correction - string sizeText; - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - // correct the GUI width to real width for the shown size - sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1); - } else { - sizeText = _captureRect.Width + " x " + _captureRect.Height; - } - - // Calculate the scaled font size. - SizeF extent = graphics.MeasureString( sizeText, sizeFont ); - float hRatio = _captureRect.Height / (extent.Height * 2); - float wRatio = _captureRect.Width / (extent.Width * 2); - float ratio = hRatio < wRatio ? hRatio : wRatio; - float newSize = sizeFont.Size * ratio; - - if ( newSize >= 4 ) { - // Only show if 4pt or larger. - if (newSize > 20) { - newSize = 20; - } - // Draw the size. - using Font newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold); - PointF sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2); - graphics.DrawString(sizeText, newSizeFont, Brushes.LightSeaGreen, sizeLocation); - - if (_showDebugInfo && _selectedCaptureWindow != null) - { - string title = $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; - PointF debugLocation = new PointF(fixedRect.X, fixedRect.Y); - graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation); - } - } - } else { - if (!IsTerminalServerSession) { - using (Pen pen = new Pen(Color.LightSeaGreen)) { - pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = _capture.ScreenBounds; - graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); - graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); - } - - string xy = _cursorPos.X + " x " + _cursorPos.Y; - using Font f = new Font(FontFamily.GenericSansSerif, 8); - Size xySize = TextRenderer.MeasureText(xy, f); - using GraphicsPath gp = RoundedRectangle.Create2(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); - using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { - graphics.FillPath(bgBrush, gp); - } - using (Pen pen = new Pen(Color.SeaGreen)) { - graphics.DrawPath(pen, gp); - Point coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5); - graphics.DrawString(xy, f, pen.Brush, coordinatePosition); - } - } - } - - // Zoom - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - const int zoomSourceWidth = 25; - const int zoomSourceHeight = 25; - - Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); - - Rectangle destinationRectangle = _zoomAnimator.Current; - destinationRectangle.Offset(_cursorPos); - DrawZoom(graphics, sourceRectangle, destinationRectangle); - } - } - } -} diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs deleted file mode 100644 index bcf7e8889..000000000 --- a/Greenshot/Forms/ColorDialog.cs +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * 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 1 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 Greenshot.Configuration; -using Greenshot.Controls; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.Threading; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace Greenshot { - /// - /// Description of ColorDialog. - /// - public partial class ColorDialog : BaseForm { - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private static ColorDialog _instance; - public ColorDialog() { - SuspendLayout(); - InitializeComponent(); - SuspendLayout(); - CreateColorPalette(5, 5, 15, 15); - CreateLastUsedColorButtonRow(5, 190, 15, 15); - ResumeLayout(); - UpdateRecentColorsButtonRow(); - _instance = this; - } - - public static ColorDialog GetInstance() => _instance; - - private readonly List