This is a feature I missed from Photoshop: it sets the scale and
position so that the image fits (it's longest dimension) into
the editor view. There's a 5% border left around the image to
provide context. This is just arbitrary seemed like the right
amount after some trial and error.
Previously EraseTool would only let you have hard lines, similar
to PenTool. After inheriting from BrushTool in previous commits,
making the eraser (optionally) behave like a brush is much easier.
We only need to change how the colors are handled for the hardness,
which is why the `draw_point()` call is a bit more involved. Just
blending the colors doesn't work here since we actually want to
replace the previous color, unlike in BrushTool where we are just
layering the color on top.
This removes all the code to handle events that was essentially
duplicated from BrushTool anyway :^)
I've also renamed "thickness"->"size" to have consistent
terminology.
Most of the logic implemented in PenTool was the same as BrushTool
anyway, with the only difference being how the actual lines were
drawn at the end. We now just override the `draw_line()` and
`draw_point()` methods instead.
We don't strictly need to override `draw_line()` here, but that
would just result in repeated calls to `draw_point()`, which is
wasteful.
Also renamed "thickness"->"size" to have consistent terminology.
The BrushTool is very cool, but it doesn't allow us to re-use any
of the code in other classes. Many of the other tools have duplicated
code for handling mouse events / keeping track of previous location,
etc.
This commit sets up BrushTool so that other tools can inherit from
it and override some virtual functions to allow similar behavior
without re-writing the code to keep track of mouse positions, etc.
In particular, we add public setters/getters for `size` and
`hardness` properties, and make `draw_point()` and `draw_line()`
virtual so that derived classes can override them.
Note: We still pass in `color` as a parameter for `draw_line()` and
`draw_point()` instead of using `color_for()` directly because it
doesn't really make sense to be constantly asking the ImageEditor
for the color when it's not really changing (for instance along all
the points of a line)
Sometimes you want to draw a straight line between 2 points, but
using the nice-looking brush we have instead of the hard line we
would get using the LineTool.
This patch adds the ability to click somewhere with the brush, and
then Shift+click somewhere else to draw a line between the two
points using the brush stroke. Seems like an obvious addition
considering we already have a helper function to draw lines :^)
The BFS implementation for BucketTool's flood-fill had sitations
which could result in infinite loop, causing OOM crashes due to
the queue growing unbounded. The way to fix this is to keep track
of the pixels we have already visited in the flood-fill algorithm
and ignore those if we ever encounter them again.
This also fixes the crashing issue from #9003. We still need a
better way to account for transparency, but that is beyond the scope
of this commit, and this issue still exists without any transparent
pixels.
This will restrict 3DFileViewer's access to the file system.
3DFileViewer loads a texture based on the path of the model loaded, this
will request access to the texture file before loading.
Previously, Assistant was able to re-execute itself due to a quirk in
the global cursor tracking logic, it seems.
Now it has become necessary to explicitly drop the lockfile before
activating the new Assistant instance.
Alternatively, this has always been a latent bug that only now has
become more likely.
Showing the position only with an active tool seems a bit confusing,
if you've opened up an image just to find out the coordinates of
a pixel for instance, there shouldn't be a need to have to select
a tool first.
Previously, we were ignoring the scale of the editor in the second
paint step. If you were zoomed in, the size while you were drawing
was not the same as the size of the final shape.
Previously, we were ignoring the scale of the editor in the second
paint step. If you were zoomed in, the size while you were drawing
was not the same as the size of the final shape.
Previously, we were ignoring the scale of the editor in the second
paint step. If you were zoomed in, the size while you were drawing
was not the same as the size of the final shape.
A previous commit I made broke layer dragging since the hole_index
was always being computed with respect to the top of the layer list
widget, however we were now drawing layers from the bottom. When
you didn't have enough layers to fill up the full height, dragging
them around would be weird.
This patch computes the hole index correctly using the same offset
we start drawing from, and fixes the behavior.
In addition to adding the action, this commit also makes the
`did_change_rect()` method take in an optional rect, which
represents the new rect position. By default it is the same as
`rect()`.
When we are cropping an image, we don't want to move the whole
cropped section to the top-left of the original image in the
ImageEditor widget, so this allows us to keep the cropped image's
position fixed.
With this patch, we now initialize the `WebContentConsoleClient` as soon
as the Page has loaded, instead of waiting for the Console Window to be
shown. This finally lets us see log messages that happened before the
window was opened! :^)
However, it is not perfect. Waiting until the page has loaded means we
lose any messages that happen *during* page load. Ideally we would
initialize the WCCC when the page *starts* loading instead, but it
requires that the page has a document and interpreter assigned and
accessible. As far as I can tell with my limited knowledge, this is not
the case until the page has completed loading.
The console widget now requests messages and receives them in bulk,
using the shiny new IPC calls. This lets it display console messages
that occurred before the widget was created. :^)
Previously, it would keep a pointer to the interpreter of the previous
page, which resulted in Crashy Fun Times.
This also changes the clearing behavior - instead of clearing the
console output every time the window is shown, we clear it when the page
changes. This is more useful, since before you would lose any log
messages that had happened before opening the window.
Having the BrowserWindow assigning Tab's internals felt a bit wrong.
This is also a step towards removing BrowserWindow as a friend class.
While I was at it, changed the Tab to having a pointer to the
ConsoleWidget instead of the Window, since that is usually what we want
to use, and it's awkward having to static_cast the main-widget
repeatedly.
When using a dark theme the name of the key does not show up well at
all. This is due to it being set with pallete().button_text(), which for
dark themes is a light color. As Keyboard Mapper does not follow the
system color theme, the text on the keys should not either.
Previously we would loop over all glyphs in the GlyphMap, compute
their rects, and then test to see if the mouse click position was
inside that rect. This is silly since each element in the glyph
map for a particular font is the same size, and we can just do
some coordinate manipulation to get the index directly.
We can now drag-and-drop files onto PixelPaint to be able to open
them. Each dropped file opens in a separate editor (which is the
default behavior of Photoshop).
Previously, all the UI setup was done in `main.cpp`, with a whole
bunch of lambdas,, and actions etc just being stored in the main
function. This is probably an artifact from back when it was first
created.
Most other applications now have a "MainWidget" class of some sort
which handles setting up all the UI/menubars, etc. More importantly,,
it also lets us handle application-wide events which we were
previously not able to do directly, since the main widget was just
a default GUI::Widget.
This patch moves all the core functionality of the PixelPaint
application into PixelPaint::MainWidget, which is then instantiated
by the main function. There is likely some more refactoring that
would help, but this commit is big enough as it is doing mostly
a direct port.
freq_bin was converted to double after it was calculated, so there was
a much higher probability it could be 0 instead of some comma number,
which meant that the bars always stayed on top.
The freq_bin in bins_per_group was multiplied only to be divided later,
which could even result in a crash if you set higher buffer size
(like 1000ms) in PlaybackManager, due to rounding errors I presume.
Casting u64 to float is probably not a safe thing to do. Also, keep
time deltas in u64 values as they can easily wrap between calculations.
This fixes CPU usage calculation when a process is spinning in a loop.
Prior this change, opening a playlist always spawned a new widget.
This could end up with having a few the same widgets, which you couldn't
even close (besides the last one).
The fd would get closed when the File went out of scope, so we couldn't
open any file specified by 'pp <path to file>'. We need the fd to be
alive and we solemnly swear to take good care of it and close it
ourselves later.
Previously all memory values on the performance was formatted as KiB,
but with such formatting it can be quite hard to read large numbers
(as mentioned by Andreas on todays office hours livestream :^)).
This patch makes use of the human readable formatting utilies and
displays them in an easier to read format.
Every tool that has a slider now registers the primary/secondary
sliders and now uses the same keyboard shortcuts to modify the
primary and secondary properties. `[` and `]` for the primary,
`{` and `}` for the secondary.
There are quite a few tools that might want to change certain values
based on consistent keyboard shortcuts. This commit allows tools to
hook up a "primary" and "secondary" slider with the base `Tool`
class, which can then handle updating those sliders with the common
shortcuts.
Note that any derived classes that want to override the `on_keydown`
function will manually need to call `Tool::on_keydown()`.