-
Notifications
You must be signed in to change notification settings - Fork 275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue #1207 - Bucket features #1630
Conversation
- Uses manhattan distance algorithm to find pixels in neighborhood and then simply expands based on that data. It's very fast. O(n^2)
- Move bucket related code to own widget - Implements fill expand with - enable state - slider - spinbox - Improves tolerance by adding same checkstate to easily enable/disable the functionality.
- Add missing license header
- Implements UI and functionality to fill to current or layer below. - Implement UI and functionality to use current layer as reference or use all layers as reference!
I've tested this feature thoroughly and finds it working as expected. There were some minor issues, that CF has taken care of. |
This won't do as we don't backup layer movement or anything. If you create three drawings on layer 1, then go to layer two, swap the layers and undo.. the logic will (based on the index) try to undo on the wrong layer... I've made just enough changes to make the undo/redo feature work for filling on a different layer. There might be cases i've missed but I don't want to put too much energy into this because of the undo/redo rewrite...
FYI, i'm testing this. So far these are the issues I've found that I'll need to share a video to showcase the issues accurately so please hold off merging this before that. I'll provide the video before the weekend. |
@candyface Alright here's the video I promised. I was perhaps too enthusiastic so apologies if I fumble some words. I'll summarize the main issues:
|
- Add additional "Behind" fill behavior as discussed with Jose.
24637bf
to
8893310
Compare
- Fixed when Reference was current layer and fillTo was current layer, it would not fill within correct boundaries. - Fixed when reference was current layer and fillTo was current layer - Fixed various cases where dragging and filling would spill
Which of course doesn't exist at this point...
- Added check to always allow filling once - Simplify shouldFill logic - Fixes a few cases where filling with transparent with overlay would keep filling.. the new mAppliedColor should prevent that from happening.
- Fixed painting occurring outside region of interest - Fixed calling state even though floodfill didn't happen - Added test to make sure spilling doesn't occur.
Would happen when painting, then undo the steps and then fill again.. since the layer cache is expected to be valid in 90% cases, which doesn't include undo/redo.
PR is ready to be reviewed |
if (tool->type() == BUCKET) { | ||
disableAllOptions(); | ||
if (mBucketOptionsWidget == nullptr) { | ||
mBucketOptionsWidget = new BucketOptionsWidget(editor(), this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I prefer to create the widget at the initial stage. Especially when the widget will not be destroyed until the application ends.
} | ||
|
||
if (mTargetFillToLayer == nullptr) { | ||
Q_ASSERT(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean Q_ASSERT(false)
? it's the case that should never happen, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And looks like the assert
shouldn't be put here as the mTargetFillToLayer
could be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming based off of the changes you made that you realize that it can't be null. editor->layers()->currentLayer() asserts the return is not null, so initialLayer can't be null. findBitmapLayerBelow will return initialLayer or another layer which is allso asserted not to be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I finally got it :p
} | ||
|
||
if (mTargetFillToLayer == nullptr) { | ||
Q_ASSERT(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as the above comment.
int bucketFillExpand = 0; | ||
bool bucketFillExpandEnabled = 0; | ||
int bucketFillToLayerMode = 0; | ||
int bucketFillReferenceMode = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like all these newly added modes are exclusively for the bucket tool. I wonder if these variables could be moved to somewhere else better? And use enum
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup I considered that too, maybe we should do that. I simply added it there since we have most of the tool properties in basetool.
I think this PR is working as expected and generally good to go. I encountered once a bug that Before I merge this PR, I will make some minor code changes mentioned above. won't touch the main part. Great effort, well done. |
Sounds good, thanks for reviewing :) - I generally agree with your comments. I am away from the computer for the day, so apply the changes you see fit 👍 |
Inspired by davids work I set myself to see if I could improve on his expansion algorithm, as I found it problematic that it would be slower the more it needed to expand. I had recently bumped into an interesting image processing algorithm that could tell me the nearest pixels to a given color. This meant that by only searching the image once I could find pixels closest to the color and afterwards simply threshold based on the expand value. The result of this means the algorithm takes the same amount of time to expand a given region as we still only search the image once, compared to looping through the images x times which is not so problematic if you work with a relatively small image or only expand using 2-3 pixels but any more will take significantly longer.
PR content
I believe the PR fulfills most of the checkboxes in #1207 thus I think the issue can be closed after this PR has been merged.
What do you think?
Here's the UI when on bitmap layer
New feature - Fill to can be either:
An example of how "Layer below" works:
New feature - Reference can be either:
An example of how "all layers" reference mode works:
The all layer functionality basically flattens all bitmap layers of the current keyframe before it is run through by our floodfill algorithm, thus we can use all layers as reference to fill and in the end decide where we want to fill to.
Updated feature - Color tolerance:
New feature - Expand fill:
New feature - Drag to fill
From a technical perspective I have moved all bucket related tool property functionality to its own widget.
The bitmap bucket logic has been moved to a separate BitmapBucket class so it doesn't clutter the tool.
Pre-compiled builds are available to test here:
https://drive.google.com/drive/folders/0B7zQuPZEO_64NlFsM0JTTmwzdlk
closes #1207