This action is added to the toolbar but not to the viewer. Thus it
cannot be triggered when the toolbar is hidden. Adding it to
MainWindowViewer makes it available at all times.
Viewer::keyPressEvent()'s and MagnifyingGlass::keyPressEvent()'s custom
matching of these shortcuts is the same as
MainWindowViewer::keyPressEvent()'s before the recent commit
"Reader: make 3 keyboard shortcuts work with non-Latin layouts". That
commit's message details the issues with the custom code.
The Magnifying glass actions are now enabled/disabled when
loadedComicActions are enabled/disabled - for the same reason (see the
recent "Reader: make 12 keyboard shortcuts work with non-Latin layouts"
commit). In addition, Viewer::keyPressEvent() propagated the Magnifying
glass shortcuts to MagnifyingGlass only when it was visible. Therefore
showing/hiding Magnifying glass also enables/disables these actions.
Note that Viewer::showMagnifyingGlass() shows Magnifying glass only if
render->hasLoadedComic() returns true, so
MainWindowViewer::setMglassActionsEnabled slot can be connected directly
to Viewer::magnifyingGlassVisibilityChanged signal without checking this
condition again.
MagnifyingGlass::sizeUp() and MagnifyingGlass::sizeDown() grow/shrink
both width and height, but check only width's limits. Thus the user can
first increase Magnifying glass's height, then increase its size and
make the height greater than the main window's height. The user can also
first increase the width, then decrease the size until the height
shrinks to 0 and Magnifying glass disappears.
When Magnifying glass disappears, the only way to make it visible again
is to restore its default size by restarting YACReader, because the
invisible MagnifyingGlass widget does not receive wheel events and
Viewer::keyPressEvent() propagates shortcuts to mglass only if it is
visible. And even this workaround is possible only because YACReader
does not save/restore Magnifying glass's size (should it?).
Always checking both width and height limits fixes the bug. If one of
the dimensions reaches a limit, only the other dimension is modified. If
both dimensions reach their limits, neither is modified.
qobject_cast<const Viewer *> improves const correctness.
QLabel::pixmap() is const-qualified => make Viewer::pixmap() const too.
Return non-const QPixmap from Viewer::pixmap() to let compiler move the
return value at the function's call sites.
Introduce a named constant maxRelativeDimension. Change its type from
float to double, which usually multiplies faster on x86-64.
Remove redundant parentheses to improve readability.
Not all possible keyboard modifiers of a wheel event change
MagnifyingGlass's pixmap. So in case of e.g. MetaModifier or more than
one modifier, MagnifyingGlass::wheelEvent() calls updateImage() to no
avail.
Move the updateImage() call into the public slots to make them
self-sufficient. This also allows not to call updateImage() when the
pixmap is not changed in case the adjusted parameter has reached its
minimum or maximum value already.
Viewer::keyPressEvent()'s custom matching of these shortcuts is the same
as MainWindowViewer::keyPressEvent()'s before the recent commit
"Reader: make 3 keyboard shortcuts work with non-Latin layouts". That
commit's message details the issues with the custom code.
render->hasLoadedComic() condition in Viewer::keyPressEvent() becomes
true when Comic::_loaded is set to true. This always happens right after
Comic emits its numPages() signal. That is why the 12 fixed actions are
now enabled when Viewer emits its comicLoaded() signal, which is
connected to Render::numPages, which in turn is connected to
Comic::numPages signal.
The 12 fixed actions are now disabled when most other actions are
disabled: before a comic is opened and on comic opening error.
MainWindowViewer::keyPressEvent()'s custom matching of these shortcuts
does not leverage all the features of standard Qt shortcut matching. As
a result, the corresponding actions cannot be triggered when their
assigned shortcuts consist of a single Latin letter without modifiers
and e.g. Ukrainian keyboard layout is active.
Furthermore, some key presses (e.g. Scroll Lock in my customized
keyboard layout) set QKeyEvent::key() to 0, which the custom matching
considers equal to an unassigned shortcut. So an action without shortcut
is triggered by such a key press.
Adding these 3 actions to MainWindowViewer and connecting the
corresponding slots to their triggered() signals allows to remove the
custom matching code and thus eliminates both of its issues.
Creating a folder in search mode selects it and makes the UI look
half-way between Normal and Searching navigation statuses.
An alternative fix is to disable addFolderAction in search mode. But
this is more difficult to implement and inconsistent with the other
always-enabled folder and reading list actions.
This member function does not affect the logical state of the class.
Making std::condition_variable and std::mutex data members mutable is
idiomatic as these classes are thread-safe synchronization primitives.
The C++ standard specifies `std::condition_variable::wait(lock, pred)`
as equivalent to `while (!pred()) wait(lock);`. It is implemented
exactly so in libstdc++, libc++ and MSVC.
This function is called only from ~ConcurrentQueue(). joinAll() is not
thread-safe and it cannot be called earlier without introducing a null
state. Moving the function's implementation into the definition of
~ConcurrentQueue() makes the code clearer. Removing joinAll() also
allows to establish and document invariants for two data members.
Assert consistency between jobsLeft and _queue in ~ConcurrentQueue().
ConcurrentQueue is currently used only by two classes and a test, but
modifying concurrent_queue.h requires recompiling 30 source files. None
of the member functions is so lightweight as to make it worth inlining.
An alternative to `@note ConcurrentQueue is unable to execute jobs if
@p threadCount == 0.` is `assert(threadCount != 0);`. But this would
force classes that contain a ConcurrentQueue data member to always start
a thread, even if they detect at runtime that they are never going to
enqueue a job.
Add Job type alias to avoid repeating the type.
Use default member initializers instead of the member initializer list
to make it clear [to the reader of the header] that no data member is
left uninitialized.