Commit graph

73 commits

Author SHA1 Message Date
Berthold Stoeger
5c5c0c4880 profile: redo animation of labels and grid lines
The old animation was weird: it would reuse the labels
based on the index, not on the value. Thus, with the
new scaling code, sometimes there was no animation at all,
if the value, but not the position changed.

Consider the values instead and let labels appear/disappear.
This makes things slightly more complex.

While changing this code, create our own animation-class.
Thus, we can avoid having the dive axes being QObjects.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
afb0978460 profile: shorten DiveCartesianAxis::posAtValue(qreal value)
This function was just needlessly complicated. For one, it
considered the position of the line, but that is never changed
since redoing the positioning code. Moreover, it does in
lots of lines what is a very idiomatic operation: a
one-dimensional affine transformation. Let's shorten the
actual calculation to two lines.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
176a62f752 profile: improve calculation of the right border
The time axis might need some space and the average depth item
puts a formatted depth at to right of the profile. Consider
these when calculating the right border.

Since I found no way to turn of the average depth, this creates
a permanent border, which might or might not be a good thing.

Contains some refactoring of the label-size functions provided
by DiveTextItem.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
6b33c3e721 profile: better increments for the time axis
The usual increments (leading 1, 2, 4 or 5) don't look
natural for the time axis. Therefore special case the
time axis and to increments in 1, 2, 3, 4, 5, 6 or 12
parts of a minute or second.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
210660d057 profile: rewrite ProfileScene::pointOnProfile()
This function was used to check wether a screen-point
is located on the profile. Bizzarely, this was done by
transforming into local coordinates and checking
min/max value. Simply check the screen coordinates
directly. Moreover, make the function return whether
the point is inside the region, not outside the region,
to make logic more straight forward.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
6cc6fe4d91 profile: fix y-coordinate of picture thumbnails
When changing from relative to absolute scaling of the char
elements, positioning of the picture thumbnails was broken.

To emulate the old behavior, add a function to DiveCartesianAxis,
that allows positioning with respect to the axis on the screen.

To simplify tuning of the poctuire positions, name a few
constants explicitly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
d3a2c40f52 profile: remove "changed" flag of DiveCartesianAxis
This prevented the axes from being redrawn on resize. It shouldn't
be necessary anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
efc89b9d9c profile: use dynamic distances between labels on chart
Use variable intervals for printing temperature and heart
beat labels. Obviously, so that the labels don't become
sparse on zooming, but also to make them not too crowded
on mobile / small screens.

This doesn't work for depth labels, because these labels
use data provided from the profile.c core that doesn't
know about the size of the chart.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
2f9c0c04b5 profile: replace orientation by inverted flag
There were two somewhat redundant flags for the axes: the position
(left, right, bottom) and the orientation (up-down, left-right, etc).

Replace the latter by an inverted flag: if true, the axis is
up-down or right-left, i.e. the opposite of what one would expect
for a normal graph.

Set the flag in the constructor and remove the setOrientation()
function.

Sadly, the code is a bit complex, because screen coordinates are
top-to-bottom. Who thought that would be a good idea?

Note: this also fixes the placement of the ticks of the time
axis.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
3a79f3e78a profile: set textColor in constructor of DiveCartesianAxis
There were virtual functions to calculate the label colors
based on the value of the label. However, these functions
only returned constant values. Therefore, just set these
in the constructors.

Thuse, a few virtual functions and derived classes can be
removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
ea59e5cf7a profile: remove DiveCartesianAxis::gridColor member variable
This was only used in the constructor to create the pen for
the grid lines. Not need to keep it around.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
7bc90b6dfe profile: set visibility of text and lines in constructor
The visibility of axis text / lines is never changed, so set
in axis constructor.

Moreover, instead of rendering the lines/text and then setting
them invisible, do not render them if invisible.

The whole thing appears superfluous, since the proper way to
not show lines/text is to just not call updateTicks on the
axis. But in the future we might want to have axes with text
but no lines, so keep for now.

Since this means breaking out the text / line rendering
into their own function, we might rename some variables to
make them (at least somewhat) more clear.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
a7a7bd182e profile: special case time axis
Rounding the axes dimensions to "nice" number may have been a
good idea, but for the time-axis it feels weird.

Therefore revert the time axis to the previous behavior:
range is set according to the data. To differentiate between
time an other axes, use the position: the time axis is the
only axis at the bottom. Yes, that's ugly but pragmatic.

Since we have that flag also use it for the special casing
of the text-display. Spares us one virtual function dispatch.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
3e11c13100 profile: use sensible tick-intervals
The integers were simply rounded to integers, which might give
ugly intervals (e.g. multiples of 3). Use the code of the
statistics tab, with one modification: take care not to
use intervals below the given precision. The statistics work
differently: there, the precision is adjusted according to
the interval size, not the other way around.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
99c4741508 profile: avoid double recalculation of tick positions
The ticks were recalculated twice per plotDive() call:
1) When updating the position of the axes in updateChangeLine()
2) After setting the bounds in plotDive() via setBounds()

Remove the first instance. updateChangeLine() is called in
only one place [from plotDive()] and therefore, the recalculation
is always redundant. Moreover, rename the function to setPosition(),
since it doesn't do any animation at all.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
b0faf2e4b1 profile: remove DiveCartesianAxis::sizeChanged() signal
This was used to animate the position of the dive event items
when the size of the axis changed. However, that doesn't work
since quite some time. The axes size are changed when
 1) switching dives
 2) resizing the drawing area
In the first case, the dive event items are fully recalculated.
In the second case, animation speed is set to instant, since
resizing of windows is done continuously on any reasonably
modern desktop anyway. It might make sense on mobile, where
size changes are discontinuous, but there we use static
profiles anyway. Moreover, I checked a few applications and
none of them had animations when switching orientation of
my tablet.

Let's just remove this disfunctional thing and replace it
later, should someone complain.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
2c4e4b1e86 profile: move setting of gasYAxis bounds to plotDive()
The partial-pressure-axis was the only DiveCartesianAxis
child that had its own code to set the bounds. The bounds
of all other axes were set in plotDive().

For consistency, do this here as well. Thus, the whole
class can be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
0de40a85b7 profile: generalize tick generation
The number of ticks was generated for each axis with custom
code. This code was not aware of the size of the profile and
could result in overly dense or sparse ticks.

Generalize the generation of the ticks. For now, round tick
values to integers. In the future, try to use more "nice"
looking values as we do for the statistics tab.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
177df72d33 profile: unify formating of axis labels
Instead of a host of virtual functions, let the base class
(DiveCartesianAxis) do the formatting of the axis labels.
To do so, it needs to know how to convert the internal
representation (e.g. mm) into the displayed value (e.g. feet).
Moreover, this transformation has to be adapted when changing
the locale-setting, therefore do it for every plot() call.

The transformation itself cannot be a simple linear translation,
because we have non-absolute display units, namely °C and °F.
Thankfully affine transformations are enough though.

Only one custom formatter remains: the time axis. It might
be a good idea to remove the virtual function and do this
via a flag.

This is all done not so much for code simplification, but
because for a general layout of the axis labels, the
axis has to understand the values of the labels and not
only handle them as opaque texts.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
322e2baa8d profile: calculate maximum label sizes on construction
Instead of calculating the label sizes of the axes when
relayouting the chart, calculate them at construction time.

To do so, pass the digits before and after the decimal comma
to the constructor.

This is not so much an optimization thing, but rather an
first stab at more general label rendering. Time, of course,
will always be an exception. But hopefully the remaining
values can be done more generally.

Note that currently this code is a total mess. For example,
the labels for the temperature axes are not converted to
F if needed. And therefore also not shown. This will need
some major rethinking.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
f19ab2e4fd profile: set DiveCartesianAxis::fontLabelScale in constructor
This never changes, no need for the complexities of a setter
function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
4b9177c098 profile: remove DepthAxis constructor specialization
All this did was setting changed to true. Obviously an
artifact, since that is done in the constructor of the
base class anyway. Remove.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
89d9105209 profile: set minimum/maximum of axes with a single call
This is bike-shedding: Instead of two setMinimum()/setMaximum()
calls, use a single setBounds() call. A few axes (notably depth
and time) always have a 0 as lower bound. However, this will
change once there is a proper zooming functionality.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
a031f3444c profile: make DiveCartesian axis grayscale aware
I doubt that this is necessary, but since most of the rest
of the profile code passes "isGrayscale" to "getColor()",
do the same here for consistency.

To avoid storing the isGrayscale flag, just create the pens
at construction time and store those.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
2615ba02bb profile: remove DiveCartesianAxis::setColor() and setTextColor()
These functions had no users.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
505e4e47eb profile: reimplement DivePercentageItem
The tissue percentages were realized as 16 independent polygons.
That didn't work at all with the new absolute scaling.

Reimplement the item and blast it onto a pixmap. Not only is
this artifact-free, it also should (hopefully) be quite a bit
more efficient than painting numerous lines.

In contrast to the old code, this does access the plot_info
structure directly instead of using the model. Not so much
for performance reason, but rather to make things more robust:
We have a strongly typed language. Why would we shoehorn data
through the weakly typed QVariant and mess with wierd
index-arithmetics. Makes no sense to me. Qt-model have to
be used for interfacing with Qt. They are terrible for
intra-application data transfer.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
179df1bf80 profile: remove DiveCartesianAxis::tick_size
No user of that. Also remove the setter function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
d0beae59f9 profile: start with "absolutizing" the profile layout
The chart items were laid out in relative terms with respect
to a fixed scene size (100.0, 100.0). This simply does not
cut it when resizing the chart. Why should the axes always
occupy the same fraction of the chart independent of the size.

Moreover, this led to basically unmaintainable code.

Resize the scene according to the viewport and do
absolute placement of the items. This breaks the layout,
but at least now we have a chance to fix things
somewhat reasonably.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
41c23dcb22 profile: remove color parameter of DiveCartesianAxis::updateTicks()
The grid color is saved on construction, no need to pass a parameter.
Note that this fixes a bug where the color was passed as animation
speed. Ooops. That's what you get from weak typing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
277b9234ab profile: pass position and gridColor on construction of axes
This is less hassle, than passing these around as parameters.
Note: The values are stored but not yet used ("position" has
not use yet and gridColor is still passed as parameter).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
abadbb6783 profile: add DiveCartesianAxis::height()
This is needed to properly layout the axes.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
04e0d96bae profile: set text and brush of DiveTextItem concurrently
The text and the brush are the two properties of text items
that change dynamically. To avoid complexities concerning
redrawing, set them concurrently instead of in two separate
calls.

Since setting one of the properties requires a full redraw,
there is no performance advantage in setting them individually.

This fixes a theoretical bug: the colors of axis labels were not
updated appropriately. However, it seems like value-dependent
labels weren't used anyway.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
2ebe6e3684 profile: set alignment and scale of DiveTextItem at construction
Alignment and scale of DiveTextItems are never changed. Therefore,
pass them at construction time. This makes things much easier
if we want to cache the rendered text [currently the text is
rerendered at every paint() event].

This also removes the "parent=0" default parameter of the
constructor, because inadvertently leaving out the last argument
led to a subtle bug.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
7dd9b65df0 profile: add width() function to DiveCartesian axis
To properly layout the profile we need to know the expected space
required by the vertical axes. In the general case, format the
the text "999". For the partial-pressure-axis, use "0.99".

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
f713858ba4 profile: rename printFontScale to dpr (device pixel ratio)
The printFontScale is used to scale up fonts (and icons) when
rendering to high-DPI devices. With absolute scaling, this
will also be used to scale the size of different chart
regions, line thickness, etc. Therefore, give it an more
appropriate name. "Device pixel ratio", which is a well
established term, seems to appropriately describe the
concept.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
84ebd1d67a profile: pass print-mode add construction of ProfileScene
Setting the profile and grayscale mode of the profile via
functions is from a time when the same profile widget was
used for printing and the UI. It is simpler to set the mode
when constructing the object and not deal with changes.

To prepare for this scenario, take the flag at construction
time. This still keeps the callers as-is. These will be
adapted later.

Logically, then the printFlag also has to be set in
DiveCartesianAxis at construction time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
1327043d6e profile: rectify animSpeed data flow
The cartesian axes use animSpeed to animate changes. Instead
of passing down the value to the respective functions, the
speed was stored in the ProfileScene and the axes would
access it there. Very messy. Let's just pass down the speed.

There still are back-references from the axes to the scene,
notably to place labels "outside" of the scene. Let's try
to remove them later.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
d19b095db1 profile: remove settings-changed slots in DiveCartesianAxis
The profile is fully redrawn anyway, there is no point in these
redundant slots.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
9f6e487790 profile: remove redundant parameter in setPrintMode()
Since using separate profile-instances for print/export,
we never exit print mode. Therefore, the mode parameter
can be removed. This is a preparatory commit for passing
the printMode at construction time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
db726862ae profile: move axes to ProfileScene
Part of separating the static (for printing, export) and
dynamic (UI) parts of the profile. This is still quite messy
with many direct accesses from the ProfileWidget.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
01983c65c3 profile: pass fontPrintScale at construction time
Instead of intializing the text fields and then changing the
font scale via signal-rigmarole, pass down the font-scale
at construction time.

Since the fontPrintScale is only set in print mode, we also
can access it directly instead of testing for printMode.

Since the DiveTextItem is not updated using signals anymore,
the connected flag can be removed.

The commit is larger than I had hoped for, but this makes
things ultimately less brittle.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
7744fec0bf cleanup: reuse constructor of DiveCartesianAxis
The constructors of Time- and TemperatureAxis don't do anything.
In reasonable modern C++ we can simply reuse the constructor
of the base class with a "using" directive.

The point here is to simplify followup commits that will
add additional parameters to the constructors of the axes.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
d725170914 cleanup: remove DiveCartesianAxis::fontLabelScale accessor
This was only used internally - there is no point in an
accessor function. It only makes grepping more complicated.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
1ddb55dcad profile: use printMode flag directly in DiveCartesianAxis
The axis has a print-mode flag. There is no point in querying
the widget.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-06-04 08:45:32 -07:00
Berthold Stoeger
b2b24665e7 profile: remove DiveCartesianAxis::maxChanged signal
The last listener was removed in 0104b0a915.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-06-04 08:45:32 -07:00
Berthold Stoeger
04d7c9b808 cleanup: remove DiveCartesianAxis::unitSystem
This was only used by the child class DepthAxis,
where it was defined separately. An oversight?

In any case, remove the unused member.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-06-01 09:25:32 -07:00
Berthold Stoeger
dd0939b6f5 profile: explicitly update gas-axis
On each profile replot, the gas axis was implicitly reset
by calling "dataModel->emitDataChanged()", which would send
a signal recieved by the axis. To make the code less confusing
and, more importantly, make order of execution deterministic,
explicitly reset the axis.

Rename the function that resets the axis from "settingsChanged"
to "update" to reflect its usage.

Moreover, remove the "setModel()" function and pass the model
to the constructore. Make it a const reference to make clear
that it can't change during the life time of the axis.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
e61466e178 profile: turn static into member variable
When the settings change, the depth axis is redrawn
to reflect metric/imperial units. To check whether the
units changed, the old length unit is saved in a static
variable. This makes no sense and allows for only one
depth axis. Make this a normal member variable that is
initialized in the constructor.

Also remove the settingsChanged() call in the constructor,
since this is a no-op (the depth unit is unchanged).

Contains a whitespace fix.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
bd01e91ea3 cleanup: make DiveCartesianAxis functions const
A few DiveCartesianAxis functions that were pure accessors
were not const. Make them so. Moreover, mark a few overridden
virtual functions as such.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
2d7be7a0e3 preferences: create global settingsChanged signal
So far, the PreferencesDialog emitted a settingsChanged signal.
This meant that models that listened to that signal had to
conditionally compile out the code for mobile or the connection
had to be made in MainWindow.

Instead, introduce a global signal that does this and move
the connects to the listeners to remove inter-dependencies.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00