fixes#2158
Issue:
The contents of the combo box, the array holding the raw mm values and
the index range checks were out of sync.
This led to wrong or no values at all during the wheel perimeter
calculation.
Changes:
* Add missing rim diameter 584mm
* Adjust rouding error in tire casing diameter
* Make index range checks more robust by using the actual array size
instead of just assuming a length
* Display ISO5775/ETRTO mm values in combo box
Combined with the Group By feature, it allows a simple way
to see weekly, monthly and yearly averages for cumulative
metrics s.t. Duration, Distance, TSS, etc.
.. lots of warnings about unused global variables that
are being used to call functions before main
.. a few other smaller nits that could be fixed easily
.. now get fewer warnings and more meaningful to then
review and resolve them
It is a more natural unit is most cases and allows enhanced
plotting in LTM charts since seconds are converted to hours.
Labels and ToolTip are shown in sexagesimal format.
.. the code was never written, so the season code just
crashes using an index of -1 into the season array
.. updated LTMSidebar.cpp to catch delete phase and handle
it appropriately, but the real fix should be to abstract
the code added into the Season/Phase classes.
Fixes#2139.
To enhance usability, specially when the locale uses 2 digits years.
Fixes#2123
In some places s.t. TPDowloadDialog and FileStore it was already set.
Not added to RideMetadata and RideImportWizard where 4 digits year is fixed.
Adds isMetricRelevantForRides(specification, metric) to RideCache
to check if a metric isRelevant for some of the activities passing
the specification
Also reduces from 3 to 1 the calls to getRideTypeCounts
... re-using the existing functions recognizing modified activities
... allowing to save all, without remembering to save one-by-one or
leaving GC to make sure that all was saved
... when changing the ride by clicking in the list - while change e.g. Detail data in the activities view GC aborted
because the proxyIndex.internalPointer() was not initialized
checking the initialization like in the other cases in the code fixed the problem
In ComparePane and RideSummary, to have a cleaner interval
comparison for multisport users having interval metrics
configured for different sports or cyclists using
metrics based on data not always present.
Fixes#2110
.. if the setting has not been made in options/prefs we
set the API web services to be disabled.
.. this is to stop warning messages about windows firewall
that will appear, and also to reflect the fact that
the majority of users will likely not require the
web services anyway.
.. when translating "Options" they are no longer put into
the main menu on OSX.
.. we now explicitly set the menu type to ensure this
happens regardless of the text.
To regenerate second-by-second data based on updated length-by-length info
and to recompute accumulated time and distance.
Laps are regenerated using pause lengths as markers.
.. the xdata wasn't being copied when dropping into the
compare pane. This has been resolved, but might be worth
looking closely at likely memory leak.
.. you can now use the XDATA function to return XDATA field
values using a wildcard.
.. this is likely to be most useful for ignoring the xdata
name when searching for a specific data series.
.. e.g. XDATA("*", "YAW", repeat) will get the YAW data series
regardless of the name of the xdata name that the user
chooses.
.. extracting with a view to identifying special cases in
the FIT developer fields.
.. in this instance the Moxy series have special values of
54 and 57, but its not clear how we can handle this in a
generic fashion (the whole thing is stinky).
.. added to DataFilter XDATA_UNITS("..", "...") returns the units as
a string.
.. added to the various dialogs in RideEditor, to enable units and
series name to be set and edited by the user.
.. added to JSON file format, set when importing from RP3 and FIT files
.. primarily used by FIT developer fields that contain unit data
.. but we add units for file formats where we know them (as an english
language string)
.. in part 2 we will add units to the datafilter expressions and the
dialogs in the ride editor to let users edit unit names along with
value names.
A Garmin Vivoactive Sportswatch may be identified by its product code 1907.
A BSX Insight 2 Sensor may be identified by the manufacturer code 98 and the product code 2.
References #2040
please review
In CSV-files recorded by a BSX-Insight 2 sensor the running speed measured using a footpod is denoted as *speed*. Running speed is recorded in m/s. Conversion to km/h is implemented. The metric is converted to mph if GC is configured to use non metric units.
please review
In file src/Metrics/BasicRideMetrics.cpp the minimum values of SmO2 and tHb and the average of tHb are calculated incorrectly. In functions compute of class MinSmO2 resp. class MintHb actually the maximum values get computed.
For MinSmO2 the comparison in function compute should read:
```c++
if (point->smo2 >= 0.0f && (notset || point->smo2 < min)) {
min = point->smo2;
if (point->smo2 > 0.0f && notset)
notset = false;
}
```
with min being a double initialized to 0.0f and notset a boolean initialized to true.
For MinSmO2 we've got to handle that the first recorded values might be zero, e.g. when the athlete did not attach the Moxy sensor to the muscle prior to starting recording. If the comparison given above holds true we have to verify that we get a valid value > 0 first before allowing SmO2 to fall down to zero again.
For MintHb the comparison in function compute should read:
```c++
if (point->thb > 0.0f && (notset || point->thb < min)) {
min = point->thb;
notset = false;
}
```
with min being a double initialized to 0.0f and notset a boolean initialized to true.
Please note that for physiological reasons the minimum value of tHb must not be zero as this would imply that the muscle under observation were totally drained from blood.
At the end of functions compute in classes MinSmO2 and MintHb we have to set the correct value:
```c++
setValue(min); // was max before
```
In class AvgtHb we have to take into account that tHb must not be zero as well for the same reason as stated above. In function compute the comparison should read:
```c++
if (point->thb > 0.0f) {
total += point->thb;
++count;
}
```
References #2050
please review
to run an specific Data Processor, even if not configured to run
automatically on import, over existing activities which pass the
filter expression using configured parameters.
Fixes#2037
Reproducible downloading/importing a PowerTap .raw file and
selecting an interval for the first time, _model->series is NULL
in this case, no model case added for safety
Stroke Rate: counting both arms for crawl/back corrected by 3m push-off when Pool Length is defined
Swim Pace: average swim pace in min/100m or min/100yd when Cadence>0, to avoid kick/drill sets
Strokes Per Length: counting only the arm with the watch, pool length defaults to 50m
SWolf: Strokes Per Length plus time in seconds, pool length defaults to 50m
Also moved Distance Swim and Pace Swim from BasicRideMetrics.cpp
.. when working with user data and user metrics its often
useful to work with arrays or index into the ride data.
.. a new variable INDEX is available that is the sample
number in the array of samples that make up the ride.
.. you can dereference samples in a ride using the []
operator so POWER[55] is the 55th sample for power.
.. when iterating you should consider the recording interval
so NN <- 1200 / RECINTSECS would set NN to the number of
samples in 20 minutes.
.. you can also use your own arrays: MYARRAY[44] <- 100 will
set the 44th item in MYARRAY to 100.
.. the old vector syntax [ date : date ] has been deprecated
since it is too complex !
.. a much simpler approach to aligning the xdata series
with the standard series, using a single index.
.. its faster and makes implementing the four different
merge algorithms much more straight forward.
.. committing alone to separate from the implementation
of separate algorithms.
.. for thread safety the Leaf tree must NOT be used for state
data when parsing / evaluating data filters -- the
DataFilterRuntime object should be used.
.. updated to use this for xcurrent/xnext during XDATA
processing which fixes UserMetric calculation using XDATA
for intervals
.. also added a 'print' function in the datafilter syntax to
help with debugging calculations.
.. now we return values when working with metrics and user data
.. you can now create user metrics and user data to plot on the
allplot or metrics charts
.. the XDATA function currently always returns a 'repeat' of the
last value used until a new value is available, will fix this
in commit 3 of 3
.. Filter rides for presence of XDATA by name using the syntax:
XDATA("XDATANAME", "SERIESNAME", sparse|repeat|interpolate|resample)
.. this is the first of 2 commits, in this one we have added XDATA to
the rideitem and rideDB.json so we can check if XDATA is present
without opening the ridefile
.. this allows us to return true or false for an XDATA(..) call when
working across rideitems (not data points) in DataFilter evaluate,
note that the join control (sparse,repeat etc) is ignored when you
are filtering ride items
.. in the next commit we will add the ability to get at the xdata
values when iterating in user data or user metrics
.. there are likely to be further refinements for the outer join
required to support interpolation and resampling in a third commit.
.. rather than using setTabBar() to keep resetting the view
for the XDATA tabs in RideEditor the model updates the
views correctly.
.. makes the editing of XDATA more responsive and doesn't
keep resizing columns on every change.
One record per length with 3 fields:
TYPE: 0-pause, 1-free, 2-back, 3-breast, 4-fly, 5-drill, 6-mixed, 7-IM
DURATION: seconds per length
STROKES: total strokes per length
Related to #2010
Added Specification parameter to AddIntervalDialog::findPeaks
So it can be used as a more general replacement for
BestIntervalDialog::findBests and findBestsKPH
.. context menu on xdata editor row/column headings now
adds functions to add/remove rows and columns
.. users can now manually create and maintain XDATA in the
ride editor
.. the UX is a bit naff and needs to be cleaned up; the
visual cues are missing on redo/undo and the performance
is poor since setTabBar is called too frequently. Will
look to fix these nits over the next few days.
Conflicts:
src/FileIO/XDataTableModel.cpp
.. get ride of the xdata by closing its tab at the bottom
of the chart. This is similar to how worksheets are
removed in Excel and should be intuitive to most people.
.. a warning is issued before removing the data, but it can
be undone as all data commands are performed on the
command stack
.. added the ability to edit point values with XDATA
series displayed as 'worksheets' within the ride editor,
in keeping with the 'Spreadsheet' UX
.. need to refine the cosmetics and work on more useful
functions like add/remove row/column etc but the basic
view and edit functions are in place.
.. add XDataDialog and tabs to the ride editor, so you can
add and remove xdata and the individual data series.
.. next commit will add editing of the xdata values.
.. there was a memory leak in RideFile and FitRideFile
.. added a test file with weather data that can be used to
test XDATA processing (it has 10 weather points with
wind, humidity etc).
.. added a new 'XDATA' element for the JsonRideFile and
RideFile classes.
.. this allows ride file readers to extract and load any
time series data that doesn't neccessarily fit into
the usual data points.
.. this was added to support weather data from FIT files
and also to support 3rd party merging data with the
GC supported data.
.. ** IMPORTANT ** the XDATA segment is added at the END
of the JSON format. So older parsers will fail to read
but will have loaded all data already (i.e. they will
fail gracefully enough)
This means files with XDATA can be read by earlier
versions of GC, but the XDATA will be discarded.
.. should be 'cycles' per minute (i.e. a pair of steps, one left
and one right)
.. previously it was number of 'steps' per minute (i.e. how many
footsteps did you take in one minute)
.. will pair and count strides to derive speed and cadence
.. this commit covers the ANT+ side of things, will now
update the config to enable the user to set stride length
When runs have power PMC metrics are inconsistent otherwise, better
to have separated rTSS/sTSS which could be added as builtin or user
defined metric.
.. it should be calculated in a data processor rather
than in the file processor.
.. Damien is looking to add one, so commenting it out
for now (so the code can be reused if needed).
Simpler and more robust lap alignment
Fixed for empty lengths due to false starts and
pauses in some devices s.t. Garmin 910xt
Added 2 contributed test files
... align terminology (upload/download vs. import/publish)
... make pushbuttons right-aligned (in sync with most GC dialogs)
... ask for confirmation before finally deleting a chart from CloudDB
.. use GcChartWindow as the base class for all charts -- so
we can truly upload *any* chart to the cloudDB
.. miscellaneous charts that were still defined as GcWindow
have been converted to GcChartWindow
.. GcChartWindow layout issues (using QGridLayout insted of
a QStackedLayout) are fixed which will also resolve a few
rendering issues related to NOWEBKIT.
.. Aerolab needed lots of cosmetic fixups once it became
a GcChartWindow
.. Added 'Upload Chart...' to mirror the 'Download Chart..'
option on the hamburger menu as users will instinctively
look for the option there instead of under the chart menu.
... add "Sport" metadata as filter option
... move "Import" from main menue to "add chart"
... make chart lists context sensitive on home, activities and diary
... import directly - without extra dialog
... add export support for the new .gchart format (allowing to post all chart types to CloudDB)
... add import in main menu for the new .gchart format
... allow to import multiple charts at once
... remove specific LTM Chart support (menu, db,... -since this is covered by general .gchart format)
.. you can now fetch activities as a list and split them
based upon gaps in recording (recording anomalies).
.. this is to support trackeR; data should already be cleaned
by the user, but thats not always the case (!)
.. completes the updates to RTool.cpp
.. as predicted by forming the pmc data.frame via an S3
list instead of a pair list the merge() function works
properly and column names are retained.
.. we should use a list not an old pair list when constructing
lists and data.frames.
.. to ensure better compatibility with coercion functions in R
and also possibly to resolve known issues with merge()
.. this is part 1 of 2, breaking up the mass changes to the many
data wrangling functions in RTool.cpp
.. it also contains an update to RLibrary to resolve the functions
used when working with lists (SET_VECTOR_ELT).
.. allow user to select target view for trends/diary charts
since they can be used on either
.. don't just add when only 1 chart imported, always let the
user confirm and adjust
.. use translated names for the views so they are more meaningful
to the end user
.. the default methods in QGraphicsView handle these
events; we don't want this since we handle them in
mainwindow
.. fixes drag-n-drop onto mainwindow as well as working
with the compare pane 'auto-open'.
.. A single .gchart file being dropped into MainWindow will
add and select it on the view.
.. still need to add a dialog when dropping multiple charts
to let user control if they want them all.
.. using mvjson not Qt Json classes, to avoid a dependency on
Qt5. The format was kept simple specifically to avoid that.
.. the chart ultimately is defined a list of properties with
a key and value.
.. export any chart to a file for sharing with others
.. the import functionality will come next (and will need to
determine property formats by querying the newly created
chart metatypes).
.. the ability to apply a datafilter to the data retrieved
is extended to the season.metrics, season.meanmax and
season.peaks methods
.. this helps to let GC filter out e.g. power data is present
before we do anything in R since GC is faster and it also
reduces the data being passed back etc.
.. clean it up, rather than resolve source (there is still a
problem in there somewhere).
.. at least now interval plots and model fits aren't skewed
by a trailing zero value
.. we really don't need 10k history on errors in the rchart
.. this is a hangover from the early development that should
have been reduced before being published
.. You can now specify which activity to retrieve by passing
a POSIXct date time representing the start time of the ride
.. this is mostly useful when used in conjunction with
GC.activities(filter=...) to select ride dates.
.. allow user to pass a data filter to evaluate when getting
a list of activities.
.. e.g. GC.activities('Workout_Code = "1L2")
will get a list of activity start times where the workout
code is 1L2.
.. when returning values we honour whatever filter is active
at the time from home sidebar or the search box
.. it is applied regardless of which view the chart is on.
This commit fixes the issue that the interval bars (in AllPlotInterval) are not correctly aligned
with the interval sections in the main plot (AllPlot). This is done by calculating the margins from
the main plotting area to the border and setting left and right margin of the interval plot
accordingly.
.. Add option to disable embedded R in preferences
.. Better diagnostics if load fails
.. If we find it in the usual place we load and set R_HOME
automatically without requiring R_HOME or config
.. The config option overrides R_HOME not the other way around
Use total duration for both length and lap messages to synch them,
even when using drill mode. Tested with Garmin Swim and 920xt files.
Garmin 310xt is special cased since it doesn't generate rest length messages
Add Pool Length in meters as metadata
.. added a checksum metric for an activity that can be used as a key
in R scripts to invalidate / reuse caches.
.. when R scripts are computationally expensive we can store the
results in a cache with a key for the activity involved -- then
the cache is tied to a particular activity (and state).
.. since caching in R has many options we may develop a 'basic'
cache function that can be guaranteed to be available to any
script so they can be shared.
.. get runtime version loaded and show on crash dialog and console
since the runtime may be different from compile time as it is
now dynamically loaded.
.. no need to define GC_WANT_R_DYNAMIC any more since it is now
working across all 3 supported platforms.
.. we need to improve the way R_HOME is configured and validated
for non-technical users.
.. fixed up to work on Windows too.
.. needed to add a couple of functions used by Windows;
getRUser(), get_R_HOME() and getDLLVersion().
.. also needed to add a path to the DLL that included the
address space (x64 or i386).
.. we can now load the installed dynamic library rather than
distributing with the version we built with.
.. the lib is loaded and symbols resolved at runtime.
.. need to fixup for Windows and remove GC_WANT_R_DYNAMIC option
and make it the way we integrate R for GC_WANT_R
.. add Graphics device entry points and almost done with defining
proxy functions to call at runtime
.. will need to create a QLibrary object to load and resolve
symbols for the proxies to call next.
.. if you add GC_WANT_R_DYNAMIC to gcconfig.pri it enables
this, but it will crash, this is a wip.
.. get peak values across rides in a season.
.. series="power", or series=c("power", "heart.rate") and
duration=1 or duration=c(1,10,100)
.. where series is a mean maximal series in the ride file cache
and duration is in seconds
.. will make this compare aware shortly.
.. get a dataframe with season details
.. all lists all seasons, compare lists those being compared and
if neither true returns the currently selected season
.. also renamed functions so we now have
GC.season.metrics -> GC.metrics
GC.season.pmc -> GC.pmc
but he old GC.metrics/pmc are retained for backward compatibility
.. some users get confused, so make the splitter sit
in the middle (ish) to help them
.. need to still fixup save/restore splitter position
to chart config.
.. instead of hacking the text to avoid a global world
transform we now transform y ourselves
.. it looks like text needs to be centered will test and
fix shortly.
.. was using invertColor and resulted in white on dark for the
default setup and was very jarring. The color is toned down
to a gray if it results in white.
.. add a new method to fetch a data.frame of PMC data
for the passed metric, by default it returns for the
selected date range, all=TRUE will fetch all dates.
.. GC.activity(compare=TRUE) will return a list of compares
.. If you are not in compare mode it will be 1 element long
and represent the currently selected ride
.. otherwise it will have one entry for each activity dropped
into the compare pane
.. each element has a $activity and a $color
Example:
df <- GC.activity()
.. do plot ..
Now:
compares <- GC.activity(compare=TRUE)
for (compare in compares) {
df <- compare$activity
col <- compare$color
.. do plot ...
}
.. you can pass all=TRUE|FALSE to GC.metrics if you want to
override the date range selection
.. also added connect to daterange select so a trend chart
will refresh when you select a date range
.. set a script to run when an activity is selected
.. this allows a plot to be generated and displayed when
you select a ride in analysis view
.. the script is stored with the chart settings
.. it now builds and runs on Windows
.. there is a runtime crash when embedded R is initialised
that needs to be reolved
** NOTE **
R is not distributed with a .lib that can be linked to
with the MS VC linker. Instead, we need to generate a
lib and exp file from the dll:
1. dumpbin /exports R.dll > R.def
2. edit the .def output to have EXPORTS at the top and
a list of functions only (last column, delete the rest)
3. lib /machine:x64 /def:R.def
After linking remember to copy the DLLs to the GoldenCheetah
build directory from the $R_HOME/bin/x64/*.dll
.. and a few more tidy ups.
.. never cease to be amazed at how some developers
will feel its OK to define generic symbols like
TRUE and FALSE in their code (!!)
.. R is a mess.
.. mostly startup issues when R_HOME is not known
.. need to think carefully about how we get the user to
register the R home. We could let them select the R
binary so we can run `R RHOME` and apply that (?)
.. we no longer need RInside or Rcpp as we use
100% R API calls to embed
.. the following need to be resolved:
1. R_HOME / Options *must* be set to startup
embedded R but we don't check / restart or
default via system("R HOME")
2. Output is not trapped - all output is sent
directly to the console you started GC on
.. will fixup the 2 above before finally:
3. Build for Windows using MSVC !
.. we can register routines when embedding via the
R_getEmbeddingDLLInfo()
.. so we just register our functions directly now
in RTool rather than needing a dynamic library.
.. its cleaner and there are no nasty casts and build
settings required
.. reimplemented with native R API
.. switched to .Call in R function since .C means all functions
return void and must return by a pass by reference parameter.
.. its not needed as the workaround of using an extern "C" function
to perform the function pointer cast conforms to standard.
.. this just simplifies src.pro that was getting heavy
.. fixup R SHLIB build and integration to work on OSX
**** WARNING ****
If you build for OSX with GC_WANT_R You will need to
manually copy RGoldenCheetah.so into the app bundle.
$ cp RGoldenCheetah.so ./GoldenCheetah.app/Contents/MacOS
*****************
.. phew. that was hard.
.. To register routines with R you need to place them in a shared
library.
.. The routines we want to register are part of the GC codebase so
cannot be linked into that shared library (it would be the whole
of GC).
.. So; we have a shared library (RGoldenCheetah.cpp) which has stubs
for all the registered functions and an array of pointers to the
actual functions.
.. We load the library (once R is embedded it is loaded in main.cpp)
.. After the library is loaded we then call one of its public
functions (GCInitialiseFunctions) to tell it where all the GC
functions are (we only have GCdisplay at present for this proof
of the concept).
.. Along the way we need to deref/cast DL_FUNC in RTool.cpp which
is not permitted in ISO C, so we also update qmake to add a
special rule to compile `dodgy' sources with -fpermissive. And
the only dodgy source is RTool.cpp.
.. This commmit will break GC_WANT_R builds on OSX, and will be
fixed up shortly.
.. The motivation behind this is to avoid RInside/Rcpp for Windows
builds -- enabling R support (which is not currently possible).
.. to use the R C API for to avoid use of Rcpp and RInside
.. the shlib doesn't do anything and isn't loaded in RTool
at this point. Need to get this working cross-platform
and iron out the build time nits.
.. so don't even try to build and warn via qmake
.. RInside/Rcpp do not suport MSVC
.. Microsoft Open R may help, but doesn't at this point
.. we can revisit at a later date.
.. not complete, but we now have a canvas (QGraphicsView)
to plot the R output without needing to use x11() or
quartz(), window() etc.
.. the primitives do not honour the graphic engine context so
all lines etc are white on black.
.. will fix and improve in followup commits, need to test
with QT4.8 and cross-platform.
.. since the R runtime is shared by charts we offer the ability
to prefix variables with $$ to ensure they don't conflict
across multiple RCharts.
.. $$d <- GC.activity() would actually be parsed within R as
gc0d <- GC.activity(). The next chart would get gc1 and so
on.
.. it is optional, so charts could share data structures (but
wonder why you might do that)
.. we still need to encapsulate the code to plot within a
script to ensure it is refreshed when the chart is selected
or underlying data changes.
.. believe it or not the R base code for plot (plot.c)
skipped plotting circles if they were white on white.
.. took me 4 hours to fix this by setting startcol and
startfill in DevDesc for the device.
.. But at least the R driver now works properly -- we can
now integrate with a qt widget.
.. the R graphics device now gets called for hist() so we can
work on the interaction with a QT widget now.
.. still have other problems to deal with (!)
.. GoldenCheetahGD is instantiated
.. GC.display() to create new GD
GC.activate() to activate the GD
NOTE: a fair amount of qDebug() in at present as
the graphics functions are being created.
.. don't crash when cannot initialise (e.g. when RInside not
available or R is not installed)
.. handle messaging via signals to trap 'late' messages from
the R Runtime
.. refactoring code to introduce an RTool for working
with RInside and Rcpp and move code away from main.cpp
.. get ready to write all the data accessors in a way
that supports multiple athlete windows.
.. now have a console in the RChart to issue R commands.
Its very basic and doesn't handle multi-line commands
well nor support up/down to cursor through history.
.. added a "GC" object with 3 variables
GC.version - a version string
GC.build - build id, later always higher
GC.home - root of all athlete directories
.. No access yet to athlete, metrics, models and rides.
This will come very shortly; need to decide on best
way to handle accessing different athletes within
a single global context.
.. of you cancel before opening an athlete you get a SEGV
on some platforms under some conditions (threads)
.. we now tidy up a little better and avoid deleting static
objects when application->exec() has not been called.
.. still working on the build/configuration to get things
started. main.cpp now creates an instance of RInside
that is shared by all athletes/charts.
.. not clear if this is going to work (!)
.. pushing to repo to test cross-platform support during
development. It /should/ not impact any code since it
will be an optional dependency.
.. first part just to get the configuration ready to
build out a chart for the trend and activity view
.. src.pro and gcconfig.pri are updated to link in with
the RInside/Rcpp package install (new dependency)
.. there is a script in util called install-packages.R
which can be run to install the packages so long as
R is available:
$ R CMD BATCH util/install-packages.R
.. if NOWEBKIT is set in gcconfig.pri when QT < 5 we unset it, since
it is only supported for QT versions > 5.0 where QWebEngine is
available
.. gcconfig.pri.in has also been updated to have a line to set
NOWEBKIT as a signpost to the user
.. we /could/ use the sed s/#DEFINES/DEFINES technique in .travis.yml
now to set NOWEBKIT always and it will only take effect if building
with QT5
... using AppVeyor.com
... only 64Bit builds with QT 5.6.0 / MSVC2015
... all libraries included (pre-compiled)
... using QtWebEngine configuration, not QtWebKit
When there are (planned) activities with future days it is
annoying to start at the latest planned activity, this change
try to select the latest which is not in the future.
.. in RideSummaryWindow we update to show
progress of the model estimates, but it
errors if the html is not set or is blank
and does not contain the div 'modhead'.
The following will always be located in the
source directories so we can find them across
the different trees:
* ../lib/libqwt.a
* ../kqoauth/libkqoauth.a (linux only)
* ./Resources
The references are made via $${PWD} which is
the directory for the currently processed
.pro file.
.. LYC set the date to 2000 from 2016 !
.. we check the date when downloading from a CERVO and if the year
is set to 2000 we set it to the current year.
.. if the date resulting is in the future (e.g download a ride in Jan
2017 from a ride in Dec 2016) then we subtract a year.
.. it will be interesting to see what happens in 2017 !
.. remove Webkit dependency if the user adds the following
to their gcconfig.pri: DEFINES += NOWEBKIT
.. at present the build disables:
* Bing map
* Google map
* Ride Window
* Street View
.. since QT 5.6 enables c++11 dependent libs may no longer
compile with c++11 enabled (e.g. qwtplot3d)
.. this is experimental and in place to enable further work
on deprecating the webkit dependency in GoldenCheetah v4.0
.. notably c++11 needed which breaks a few dependencies
.. WebKit is not available and breaks our builds
.. we will likely need to fixup WebEngine and c++11 in some
fashion. This may mean we deprecate qwtplot3d and we
pre-build WebKit for builds
.. there is a fixup for this in Qt 5.6 but not prior and
it causes horrible performance problems on the QXT
span slider on Linux, which is irritating when trying
to zoom into an area of a ride.
.. when searching for weight in withings readings there will
be measurements that do not include weight -- these are
now skipped to avoid returing a 0kg weight.
.. don't paint dots for cost > 100kJ. It was good for debugging
and checking the solver, but now its just distracting and a
very large performance overhead.
.. probability(), temperature() and neighbour() functions were
not implemented for a correct SA implementation.
.. results still need to be constrained to avoid solutions that
are implausible for the athlete status or history
.. added a solver using a simulated annealing algorithm.
.. the solver is constrained to physiologically plausible
values, but these may not be valid for the athlete. So
a second update is required to allow the user to constrain
the solver.
.. secondly, the algorithm cannot be halted and doesn't use
multiple CPUs/threads should they be available this should
be in a second update to part 2
.. finally, a visualisation is needed to show the solver progress
across the search space to give the user an indication of
where the best solutions were found (especially if they don't
constrain it themselves).
.. add the dialog to mainwindow, but not functioning.
.. Part 2 will add the Solver and Part 3 will add the
progress visualisation.
[this is a recommit after reverting the previous one
that borked line endings to MSDOS crlf]
For builtin metrics it shows the newly added description if available
and refers to the Glossary otherwise
For user defined metrics it is the text provided by the user
Complete descriptions for Running and Swimming metrics and partial
update for BasicMetrics, it defaults to a message referring to the wiki.
Fixes#1850
.. rather than only build with Google Drive support if
using QT5.4 just adapt the code to avoid issues with
QJsonObject -> operator present in QT5.x < 5.4.
.. see https://bugreports.qt.io/browse/QTBUG-29573
.. when saving weight/height the saveClicked() function was using the
value in context->athlete->useMetricUnits to decide if to perform
conversion of the values stored in the widgets -- BUT -- it will
reflect the value BEFORE our update since it has not been updated
yet (via the configChanged() signal.
.. instead we look at the pending value when deciding if the values
need conversion.
Fixes#1868
.. previously it was disabled via VLC, but if you're not running
with video then the screensaver will kick in on Windows.
.. we now disable it via the Windows API too
Fixes#1859
Introducing a directory structure to make it a bit less
daunting for new developers and perhaps even old hands.
The main folders all start with an upper character, so src
files are now located in;
* Core - Core data structures
* Gui - Main GUI elements
* Metrics - Models and Metrics
* FileIO - Device and File I/O
* Charts - All the chart types
* Cloud - Working with Web Resources
* Train - Anything Train View specific
* ANT - Our ANT+ Stack
* Resources - Images, Translations, Web etc
Apologies to anyone who needs to merge across this update.
.. using scatter plot of metrics as a basis to develop a class
hierarchy to replace all chart 'types' by a single suite of
classes
.. this is to enable easier additions of features like interval
analysis and UX as well as greater consistency (data that is
available, functions etc)
.. but for v4.0 we will just use this to introduce a scatter plot
for the trends view and develop it further in v4.1
.. this is the initial class design.
Helps startup time a bit more, mainly by removing
all of the QTextEdit controls used for html esacping
and moving them into a utils class.
also stopped excessive looping in setymax where axis height
was small.
simpler implementation of ceil used rather than calling qCeil.
G3 hubs intermittently broadcast battery status messages, which
were being treated as telemetry and saved into lastMessage. This
was then corrupting the ANT_WHEELTORQUE_POWER calculations for
speed & power after each battery message.
Note: don't have a G3 to verify this agaist, but this fix makes
sense given the supplied log files!
.. when zoomed if you highlight the qwkcode the view makes sure
the gui is visible and centered if poss.
.. also ensures 'now' is centred and visible when recording - makes
the view useful as a close-up view of 'whats coming up' during
recording.
.. zooming in / out now animates to make it less jarring.
.. we now need to add 'ensureVisible' for the cursor when
cursoring down the qwkcode to make sure block is visible
on the gui side when zoomed.
.. now user metrics will reference pre-computed metrics
during the computeMetrics() call, we need to NOT do
this when they're empty.
.. there is really only one time this happens - when we
are testing a metric in the preferences pane.
Changed EditUserMetricDialog parent so that Options/Preferences dialog doesn't get hidden by main window
Added double-click as an alternative to edit button
.. use the symbols computed for an interval when calculating
for an interval and not those calculated against the entire
ride.
.. we now use datafilters in a lot of contexts and should
consider moving to handling scope more formally within
the language grammar.
.. allow the user to create a new workout and also
to save as a new file, which are complementary functions.
.. we also now prompt the user if they have made changes that
have not been saved to make sure they don't lose them by
accident.
.. a few bits of code were not removed from the different
approaches taken whilst developing the splash progress
window before the last commit, so cleaning them away.
.. The eCP model keeps a note of the peak efforts used to derive the
model parameters. This is so we can work with them later, possibly
to store in the ride item and plot alongside the model etc
.. we may choose to use confidence intervals across them since they
will always represent the peak "anaerobic and/or aerobic" efforts
in each ride.
... GC needed a "libusb0.dll" being available on Windows system to be able to start (even if not used)
... Library/dll is now dynamically searched and loaded if available - allowing GC to start even if the system
has no "libusb0.dll" installed/available
Auto connects to the selected train device(s), re-connects if device
selection or configuration changes. Adds a temporary button to
manually toggle connected state.
Emits signal on change of view to support connect/disconnect on view change.
Only gathers telemetry when on train view tab, unless during workout.
Decouples the gui timer from session start/stop. Only updates time and
distance if session is running. Passes the running/paused state into
context, and only updates performance plot while running.
Builds list of active devices when connecting - used to disconnect the
previous selections when they have already changed in the device tree widget.
Disables whichever train view controls are not applicable to the current state.
Dependent on timing, the closing ANT channel can transition into a closed state
before it's checked, resulting in it being re-opened.
When the ANT channel is closed and then immediately re-opened (for instance when
changing the device selection in train view), it may generate a libusb error
message. Adds a small delay to the closing, enabling the device to settle.
... add menu for Curation only if started with "--clouddbcurator" option
... restructure menus (User vs. Curator)
... add Curator validation (check athlete UUID vs. entry in Curator DB)
.. if your power output is not within 5% of the
target power and you're in ERG mode the the
background color of the dial is changed to
let you know.
RED background power is > 105% of target
BLUE background power is < 95% of target
Basically mimics the scheme used in TrainerRoad.
.. the timer event for click and hold was not cleared
when the user pressed the mouse again (typically when
drawing points very quickly).
.. this mean't that the timeout from an earlier click event
arrived just after a new click event causing a block to
be added rather than a point.
.. we now clear the timer event when a new mouse click arrives
and set a new timer from this event.
.. not sure what it was trying to fix, but it didn't actually
do anything except declare a couple of variables and set them
to a value that was never used.
.. compiler no longer warnds 'unused variables'.
.. we can also write Zwift workout files using the
workout editor.
.. it doesn't retain texts, and category/categoryIndex
we can fix that when we look at metadata.
.. its just a temporary measure but moving them to the bottom
of the screen as they're really annoying popping up over the
main view -- have to move them out of the way EVERY time I
go into train view is a ballache !!
.. when cursoring up and down the Qwkcode text
the hover block now highlights the block in
the workout plot so you can see what points
the line is relevant to.
.. ensure duplicate points survive the round-trip
from points -> qwkcode -> points to enable editing
of qwkcode and mixing with undo/redo.
.. point data now stored as ints not doubles and use
integer arithmetic etc. Makes things more consistent
and a hell of a lot faster.
.. QT code supplied was QT5 only, fixed up to compile
on QT4 by including relevant headers
.. moved the responsibility for code highlighting back
to the editor as it is the sensible place to do it.
.. add a text edit to edit the workout quickly
without having to use a gui or work with the
ERG file format.
.. need to make it round-trip, hover highlight
and generally make it easier on the eye.
.. when updating an ergfile after edit if the duration of
the workout has changed the "Duration" member needs to be
updated to reflect the change since it is used by
wattsAt() to decide if at the last section of the erg file.
- Fortius read was timing out on some hardware
- If read fails then write fails
- Moved write before read to rectify
- Added windows 10 x64 compatible driver inf built with Zadig
.. so other plots see changes we made (without saving).
.. the reason we don't insist on saving the erg file is
because we often increase intensity or repeat sections
just for a one off run.
.. the changes made within the editor are applied to the in-memory
representation when the workout is started -- that way the edits
are executed.
.. the workout changes are not saved (yet).
.. will now plot telemetry as you are recording so can be
used as a drop in replacement for ErgFilePlot.
.. bear in mind it does not support slope mode yet, so
cannot be used for CRS, MRC and PGMF workouts.
.. will adjust what is shown when resized to a small size
.. will hide toolbar whilst recording
.. getting ready to plot telemetry when recording so we
can replace the workout plot.
... double-click on "small chart" opens Window with full version (re-sizable)
... pictures stored as PNG (not JPG) any more (due to much better quality when showing full chart screenshot)
... add "common" feature for this and future CloudDB artifacts
... add Cache for Chart Headers
... add Language parameter for Chart publishing
... add Text and Language as Filter for Chart Selection
... provide Terms&Conditions acceptance Popup (first proposal of T&C)
... will need Native Speaker adjustments
... track T&C acceptance / rejection in properties
.. on import and export, using the "pwrright" element.
.. this is not part of the public PWX schema but has
been used by ipbike when writing PWX, and may or may
not be supported by TrainingPeaks.com
.. using the sustained interval algorithm we can now
find sections of a ride that are impossible to
complete according to the 2 parameter model.
.. only looks at durations > 2 mins.
.. this pastes a 'block' that has been copy/cut
but needs to be updated to work in an expected
way -- it pastes points, not blocks which leads
to situations that will confuse users.
.. one fix would be to be paste intelligently to
avoid duplicate points and "join" the pasted
blocks to the existing blocks.
... move Chart Import to Library/Sidebar (and remove from LTMTool)
... enhance Import Dialog / First Filter function - Curated
... introduce local Cache to not re-read all time
... read/display in chunks of 10 charts from GAE
... simplify find structure (in sync with CloudDB)
... no statusId, no explicite versioning
... Refactoring of File and Class Names to provide a common
structure for future CloudDB artifacts
.. to cut and copy the block selection to the clipboard.
this is very different to delete points since it will
shift the remaining points to fill the gap.
.. from a UX perspective the cut/copy/paste functions will
work with BLOCKS not POINTS. This may cause a bit of
confusion.... not sure how to deal with that.
This prevents channel searches from taking precedence over
established connections.
When the timeslots for searching and established channels
overlap, the search will blocked for that period instead
of the established channel.
This prevents data loss on the established channels at the
expense of potentially longer search time (only in the case
of channel collisions).
Moved the signal to stop the timer from AttemptTransition() to
Close(), as was not reliably reached.
Also disconnect the timer event slot on close, to avoid multiple
calls on subsequent sessions.
Fixes related to debugging..
Recognise TX events from the master channel (avoid dropping
through to default handler).
Parse the event messages correctly, was checking wrong byte.
.. just a simple indicator in the x-axis for now
when points are selected. may extend to the y-axis
as well.
.. lots more to come on smart guides but needs a lot
of thought and play time.
.. estimates should be sport specific (modality)
.. this is a hack to fixup cycling, but the whole estimate
code needs to be reworked as it isn't well thought through
and isn't well integrated into the rest of the code.
.. thanks to Jon Beverley for heads up and code fixes.
.. when you create a block (by pressing and holding the mouse
button) it now enters dragging mode (dragblock state) to allow
the user to move it around before releasing the mouse button
to create.
.. we DESPERATELY need guides to appear whilst dragging (!)
For Date Ranges and Intervals, only when activities are homogeneous
to select the correct Pace Zones
Also enabled Time in Power Zones only when activities are homogeneouse
to select the correct Power Zones
.. press and hold a mouse button to create a block
whilst in draw mode (or shifted in select mode).
.. will add a block in the middle or at the end of
the workout depending on where you click.
.. refactor as paint based approach was awful
from a utility and performance perspective.
Even though it was just a UX experiment it
bombed to CPU on Linux and Windows.
.. needs to have pointer in it !
.. we may need to do this in the eventFilter rather than
the paint event to stop repainting every time the cursor
moves and also to manage block selection etc.
.. the toolbar draw/select buttons now set the mode.
.. in select mode you can select points (same as holding
shift whilst in draw mode).
.. this is just to make the UX less complex for casual users.
.. when using a rectangle selection we clear all
the currently selected points. More often than
not this behaviour is preferred, we could add a
keyboard modifier in the future.
.. added a static fastSearch() function to the
RideFileCache class to perform a search on a
single series of data without any data prep.
.. its super quick and will work with the workout
editor recompute() function, but need to think
about how we can display the MMP curve as we
edit.
.. for now pressing SHIFT and CLICK will enable
selecting points.
shift-click when hovering on a point will toggle
selection of that point
shift-click in space will start a rectangle select
tool; as it drags it will select points within it.
hitting the ESC key will clear all selections.
.. the toolbar button "Select" needs to be integrated
into this scheme so users don't need to know about
the ability to select with the shift key (as we had
this before with intervals and it wasn't intuitive
to casual users).
.. resampling is the WRONG approach for the erg points
they need to be INTERPOLATED!
.. e.g. a ramp from 0w to 100w over 10 minutes was previously
resampled as 10 minutes of 0w followed by a jump to 100w
and thus W'bal was way off !!
.. we calculate for ourselves since its probably
quite expensive to calculate every metric.
.. could look to use the metric factory in the future
if we want to make these metrics more configurable
... Windows/MSVC QWT config creates 2 libs (release and debug)
... previous patch to support MSVC for this did not consider the different behaviour on other OS
so this is reverted and changed to be platform specific
... error/exception only visible when running in Debug Mode
... the destructor fo tooltip fires (via multiple step) and mouse even to AllPlot standard,
which at that point is already deleted - changing the sequence let's GC
end gracefully also in Debug Mode
... Assert error in MSVC-core library when running code compied with /MDd (debug mode)
... Solution - removed BUGFix code related to QTBUG-14831 (which worked fine until now)
... Tested under MSVC (Release && Debug) QT 5.6.0 and MinGW (Release) QT 5.4.2
.. we only have two commands; create and move point
but baking this in early so we can adopt it for
all other commands as they arrive.
.. due to the interactive nature of a graphical editor
the command class behaves differently to the one
used on the ride data editor; commands are added to
the stack when they complete (so move point isn't a
history of the mouse cursor moving its just the begin
and end point).
.. of point based editing, which is a bit difficult
without constraints like snap-to, guides, undo
or delete. But the basic concept is there to play
with.
.. of course it will still be possible to edit in a more
traditional 'blocks' and 'rectangles' way too but that
code hasn't been written yet.
.. compress and maths libs with win32 and gnu toolchain
.. WINKIT_INSTALL to specify where winkit is installed for MSVC toolchain
.. update gcconfig.pri to reflect this
.. initial code to display an ERG file for editing
.. this just introduces the basic model for rendering
the erg file and loading the model.
.. the interaction model using a 'points' editor will
follow next and then one to use 'blocks'.
.. There is a LONG way to go, this commit is just to
put a checkpoint down and test across platforms
.. most importantly start to remove any reference
to .lib or .a library files since these differ
depending upon toolchain.
.. instead we should use a combination of
LIBS += -Lfolder
LIBS += -llib
.. so for example
LIBS += ../qwt/lib/libqwt.a
becomes
LIBS += -L../qwt/lib -lqwt
and is now platform neutral.
.. this needs to be applied throughout to ensure
src.pro works for MSVC and GNU toolchains
.. it had become a bit of a mess with various changes
over the last 5 years so restructured into 3 sections
* core and platform config
* optional dependencies
* source and headers
This is to help make it easier to maintain, especially
since support for the MSVC toolchain is likely to mean
it is modified quite a bit (in section 2 anyway)
.. gets rid of an iritating compiler warning when
compiling with VS2015 and MSVC
.. is good because user metrics aren't fixed so the
assert assumption is wrong now
.. means we have to add assert.h to all the source
files that had it from including RideMetric.h
and want to use it.
... first set of syntax error fixes to compile GC using Visual Studio 2015
... changes are encapsulated and tested to not conflict with GCC compilation
Note: there is no full compatibility - so GC is not building with MSVC2015 yet
.. if you delete a user metric after adding it to the
interval metrics list the interval summary window
will crash.
.. the fix goes to source where the RideMetric::compute()
method now ignores metrics that are not known instead
of adding a NULL pointer to the results.
.. the DataFilterFunctions[] were not processed correctly
after validation of calls to named functions was added
and the correction applied previously only worked for
functions defined by the lexer/parser, not those defined
in DataFilterFunctions[]
.. this fixes that, but it would be nice if this was cleaned
up in to one unified place in the datafilter.
.. recent commit for Pmax on the PfPv plot introduced
a stray line of code settng cranklength incorrectly.
This results in the QA plot being blank and a warning
message from qDebug() about trying to read a cyclist
setting incorrectly.
.. logic error if/else for plotting rides vs dateranges
along with assumption that zones will not be NULL (esp
for running) lead to a repeated crash when running power zones
are not defined.
.. additionally, when summarising for a date range the table was
displayed for running vs cylcing based upon the current ride item.
This has been changed to use cycling power zones always.
.. the proper fix would be to summarize power time in zone for running
and cycling separately.
.. the compare logic appears to be unaware of power time in zone for
running and so does not have the same SEGV but will also need to
be updated to list time in zone for running and power separately.
.. it broke all the builtin functions !
.. we need to check for user functions after all the
builtins e.g. config(cp) was marked as inerror
when it should not have been.
.. User Metrics now integrated into the factory, ride cache
and of course rides and intervals. Which means you can define
a user metric and it will be computed and displayed like any
of the builtin metrics.
.. lots of technical changes to support this:
* DataFilter gets a runtime object to support multi-threading
and uses a context for construction only - item contexts are
used when evaluating an expression
* RideMetric factory can now remove user metrics
* The context in which the user modifies the user metrics will
notify all other contexts of the change ***
*** NOTE: STRONGLY RECOMMEND THAT YOU DO NOT HAVE MULTIPLE ATHLETES
OPEN WHEN DEVELOPING NEW METRICS SINCE IT WILL TRIGGER A
METRIC REFRESH FOR ALL OPEN ATHLETES.
ZonePage, CPPage and SchemePage changes to support separate editing
Zones and Settings to allow for separate GC_USE_CP_FOR_FTP
RideItem and Coggan metrics are running aware por power zones
Update of all metrics to work with a RideItem
not directly with a RideFile.
When iterating over the activity samples we now
use a Specification and RideFileIterator to bound
the set of samples used. This means that we can
compute metrics for intervals without having to
create a temporary ridefile.
RideItem now has first class members for zoneRange,
hrZoneRange and paceZoneRange to avoid calculating
for every metric which are stored in RideDB.json.
Compare pane continues to construct a ride file
when working with intervals since it is used lots
of charts, this is unlikely to ever change.
A SEGV in compare intervals has been fixed where
interval items were repointed to temporary compare
pane objects that are deleted - see RideItem::setFrom.
THIS COMMIT CONTAINS 3 REGRESSIONS:
1. TcxRideFile no longer computes metrics
2. FitlogRideFile no longer computes metrics
3. WorkoutWizard no longer computes metrics
-- The workout wizard will be replaced with a new
Workout editor, whilst the RideFile metrics
may be deprecated (but considering options)
.. useful for simplifying iteration over the ride
samples in the metric compute() method and possibly
elsewhere in the code
.. will iterate for rides and intervals.
.. the specification class is used for filtering
rides but now also supports filtering ride points
.. this is so we can refactor the metric code to
use a specification when computing metrics
.. the next update will include a refactor of
all the metric compute() functions to use this
new approach
.. datafilter uses a context that was used to create it
which is fine until it is used in user metrics which
are global and shared across multiple contexts.
.. so now when evaluating a ride item we use the context
for the rideitem being evaluated not the context of
the data filter performing the evaluation
.. next couple of commits will need to look at the way
we use RideItem and RideFile when computing both
Ride and Interval metrics.
.. User metrics can be created, deleted and edited
in the preferences pane.
.. A new dialog has been created to create user metrics
and will need to be updated after step 3 of this multi
part update completes the UserMetric code and integrates
it into the RideMetric factory.
.. User defined metrics where a user can define code
to compute a metric from ride data that can be used
in the same way as builtin metrics.
* Part 1 : Introduce User Metrics, Settings and XML config
* Part 2 : Introduce Dialog for User Metric CRUD in Preferences
* Part 3 : Integrate with Cache refresh and fingerprints
* Part 4 : Resolve dependency tree and related aspects
.. The user code will be via a DataFilter; this code has
already been updated to include variables, functions and
if/else/while constructs.
We now have named functions that can be called in the datafilter.
This is primarily to support user defined metrics where we will expect
the user to optionally define a bunch of functions we will call as
part of the ridemetric methods (see design mock up).
.. Datafilters can be defimed in three forms;
* a single line, typically as a filter
e.g. TSS > 100
* a block of code, typically as a formula
e.g. { val <- TSS; val > 100; }
* a program made up of functions, typically as a user metric
e.g. { pass { TSS>100; } main { pass(); } }
.. This example is functionally equivalent to "TSS>250":
{
pass {
# only filter rides with a high TSS
TSS > 250;
}
main {
# call our function to filter rides
pass();
}
}
.. Functions can only be defined within a block
.. Functions must be defined before use
.. A "main" function must be defined as an entry point
into the program if any functions are defined.
When the Diary checkbox is set for a metric
"Name: value" is added to Calendar Text.
The "Weight" field is special cased to "Athlete Weight" metric.
Calendar Text is no longer stored in json files, just cached
from Metadata Configuration, Tags and Metrics values.
Fixes#1563
.. Balsamiq mock.
.. note the use of "special" symbols in the code
to introduce blocks of code that will be called
at certain points, these will need to be aligned
to the RideMetric class but limited to those
attributes that are activity specific
isRelevantForRide()
initialize()
compute()
setValue()
setCount()
we may want to add other attributes like aggregate
zero and lowerisbetter to the dialog too.
.. NA equates to RideFile::NA when working with
samples or averages etc and wanting to check
.. RECINTSECS is only really available when working
with ride samples (e.g. in user metrics coming soon)
.. Added if else logic but could not avoid
needing the statement to be terminated with a
semi-colon (;)
.. so examples are:
if (TSS>100) TSS; else 0;
if (TSS>100) {
temp <- TSS;
temp;
} else {
temp <- BikeScore;
temp;
}
.. Doesn't add much beyond the existing conditional statement
using '?' and ':' but is a lot more readable (!)
.. start of transition to a full grammar, so now
we have statements and compound statements.
This update just differentiates between an expression
which is a conditional, logical or binary expression
versus a statement introducing a user symbol
.. You can now use compound statements in data filters
.. A compound statement is:
{ s1; } evaluates to s1
{ s1; s2; s3; .. sn; } evaluates to sn
.. It is possible to use the recently added user defined
symbols to build up processing logic:
{ temp <- TSS; temp > 100 }
is functionally equivalent to
TSS > 100
.. At present there are no control statements outside of
the ? and ?: operators but these will no doubt be added
in due course.
.. allow users to introduce their own symbols
into a datafilter with:
symbol <- expression
Which will initialise symbol and evaluate it
with the expression. The symbol can override
a metric name, but that would be rather dumb!
Number of data fields depends on sensor model
MoxySensor transmit SMO2 as cadance, tHB as speed,
BSX Insight 2 transmit only SMO2 as cadance, tHB is not supported.
So in case of BSXInsight we should not convert speed data. Let's allow
user to chose which datafields to transfer.
This patch add two new check buttons FixMoxy dialog
- Cadence to SMO2
- Speed to tHb
.. x ?: y
Evaluates to x if it is non-zero, otherwise it
evaluates to y. y is only evaluated once and only
if x is zero. Similarly, x is only evaluated once
and returned if it is non-zero.
.. it doesn't work and might be better to use a
secure ftp approach or similar.
.. need to fix this for the nightly development
builds planned for v4.0
[skip ci]
Major new features
Sync across PCs via Dropbox cloud storage
Sync via local folder, thumb drive, Google mounted drive etc
Added Daniels VDOT and T-Pace tools for Running
User Formulas
Restful API Web-Services for integration with R,Matlab,Orange,Tableau etc
Support FE-C trainer
Monark ERG Support
Support Stryd Power Meter for Running
BSX Insight 2 support
Ambit SML import support
RLV Support, playback to riding speed.
Video Overlays in Train View
SportsPlusHealth upload support
Backup and Autobackup
Better swim workout support incl. lap workouts
SrmRideFile: v9 support (SRM PC8)
Add new language support: Chinese(Traditional)
GPL v3 License
Severe Bugs Fixed
Fix 3DP file import 'hang'
Joule GPS+ import issues
Checkbox metadata fields not saved, ^S save errors
Fix GPU battery drain on Mac OSX
Fix HR > 8 Zone Crash
Fix 'Fix Elevation' SEGV
Fix Interval Search SEGV on High Power
DataProcessor 'Auto' runs on import only
Fix Memory Exhaustion on Mass Import/Sync
Fix SEGV when sharing activity on Strava with no internet
Fix IntervalNavigator SEGV
Fix SEGV LTM Edit
Minor new features
TrainSidebar: Delete multiple workouts
Configure CP and FTP separately
FixSmO2: Add a tool to remove anomalies in SmO2 data
Recognise more Garmin devices based on FIT SDK
Fix Freewheeling Tool
Added W'bal Work In Zone Metrics
Add W'bal Zones - Time above CP
Added Autoimport Stealth/Background Mode
TrainMode - Use Multimedia Keys
Fix Speed from Distance tool
Delete Athlete now supported
Settings stored in athlete folder config directory
Bugfix merge of hrm and gpx
Mass update metadata with set, isset and unset commands
Add a Derive Distance tool (from GPS position)
Read R-R data from polar hrm files
Add User parameters for Bike Weight and CRR to Power Estimation Tool
Multiple fixups for DataFilter expressions and precedence logic
LTM Filter for a curve
Rename Route
.. updated COPYING file
.. We are GPL v3 to enable mixing with other licenses that
become important due to the libraries we optionally link
with that are already v3 or BSD/Apache/MIT; e.g. libsamplerate,
libkml or use LGPL; e.g. libvlc
.. The intention of upgrading this license is to enable GC
code to be shared more widely and used in other contexts
without the restrictions that were present in v2 of the GPL.
.. the resampling code caused issues (not 100% sure why) so
reimplemented using the resampling method from Txt file
processing (also for Computrainers).
.. we know that approach is accurate since it accumulates
work and resamples to 1s intervals precisely.
.. two regression impacts; we no longer import the virtual
altitude and sample rate is 1s not 250ms.
Samples of swimming type are used to update distance and speed
of periodic samples, cadence is computed counting Stroke events.
Includes test file contributed by Serban Mestecaneanu
... caused error in list-model since entries are added and "end-of" dbtable
... now only update of texts in upgrade to handle pre 3.3 translation problems
.. for future use, we create a QUUID when the athlete is
created and it is used for ever after that point.
.. it will be used to share data with the open data initiative
to ensure activities can be collected for a single athlete
without revealing any personal identifiable information.
Sport is now recognized as swimming and Pool length extracted from session message
There still remain lap alignment issues in some files from Garmin Swim and 920xt
..Support a user defined MapQuest API key in gcconfig.pri
.. Use exceptions to trap Bad Request and API errors and
stop processing early.
.. Delete the networkMgr object to prevent a file descriptor leak
which can cause GC to crash when fix-elevation is configured
for auto-processing on import of files and there are many files
being imported.
The ANT_TE_AND_PS_POWER events are directly related to
either the ANT_STANDARD_POWER or ANT_CRANKTORQUE_POWER events
(whichever is sooner). The eventCount of TE_AND_PS will match
the eventCount of either of those events to be considered valid.
This change is required for Garmin Vector pedals which deliver
a sequence of ANT_STANDARD_POWER events, interleaved with
ANT_CRANKTORQUE_POWER events and occasional ANT_TE_AND_PS_POWER
events. Without the change, the user will experience very frequent
power drop-outs (0W readings). With the change, the power readings
are smooth and consistent.
It generates both record and length messages for
each length, we use length messages to recognize
lap swimming and filter out record messages.
Includes test file contributed by Jonathan Beverley
.. when building on Debian there is no package for
KQOauth, so as a temporary measure we're pulling it
into the repo to support packaging.
.. as soon as a KQOauth package is made available we
will remove it from our repo
.. It seems like a good idea to provide a default value,
or you could just add a different #else case, e.g.,
.arg("no GC_VIDEO_ value provided"), or fail compilation.
.. usage: python gh-downloads.py GoldenCheetah GoldenCheetah <tag>
will fetch the binary downloads stats for the release with
the specified tag (e.g. v3.2)
.. it is a clone from: https://github.com/kefir500/ghstats
This reverts commit 2f9d74d759.
Will come back and look again at QT5.5 with QT7 but for
now lets just stick with the method that works (albeit the
binary created doesn't work!)
If a trainer does not advertise simulation support, it could be
put into power mode, with GC calcuating the required load from
current speed/gradient etc.
setChannelID() could be called with a null device_id. This may
result in pairing with an unexpected channel type if more than
one channel is available from that device_number.
.. don't want qt4 any more
.. qwtplot3d fails to build on QT 5.5, we may need to think about
either pulling it into the repo and patching, or just deprecating
it altogether.
.. for ANT+ CTF devices that are incorrectly recorded such
that Cadence/Power are repeated 3 times when the rider
starts to freewheel.
This was a common issue with Garmin firmware and is now
happening with SRM PC8 bike computers -- so added a tool
to fix it.
.. fixes a SEGV in ride summary window where only 8
HR Zones are supported, but historically the number that
can be configured in preferences was changed to 10.
.. the 10 limit was probably a cut and paste error but it
is out there now, so we need to support 10 zones.
.. all the other zone configurations are set to a max
of 10 zones anyway.
.. when freewheeling some headunits record the repeated
power/cadence values rather than resetting them.
.. the ANT spec for CTF power devices says that these
should be reset after 3 seconds on the display -- but
crucially they should also not be recorded in the file.
.. we should also add a 'fix tool' to find and fix these issues.
.. added an environment variable TESTVAR to see if
it can be made available during the build. Will
remove this once it is working in order to add
the API keys for twitter, dropbox etc
.. doesn't honour font sizes (long story but too complicated
to unpick all the fugly code in QtMacButton.mm)
.. but at least the chartbar is tall enough for the "standard"
size on OS X
.. and resizes as the font gets bigger so you can
at least adjust when running on a high resolution
display.
.. still need to do ScopeBar and SidebarItem too
.. videosync table version stored in TrainDB (was missing before)
.. upgrade to 3.3 fixes default entries for Workouts (e.g. due to wrong translation with missing " " in text - German)
... new Feature to Autoimport without Dialog (with same timeframe option like the Dialog version)
... in case "Dates/Time" is missing - the Dialog Window appears and waits for input -
if entered and "Save" presses no further input action is required
... malformed activity files are silently ignored
... to avoid inconsistencies closing of the Athlete for which Background Import is running
is blocked until the Import is finalized (Info on import complete is sent to UI)
.. UI is not blocked by Autoimport - but a bit less reactive as long as the import is executed
.. check for NULL.
.. this is odd, some behaviour upstream has changed
and needs to be investigated as this bug is too
significant to have only just been found.
... fix problems when dates are converted back/forth with fromString/toString to avoid Locale related mismatches
... use ISO 8601 format (YYYY-MM-DD) in such cases (Qt::ISODate)
... applied to "RideImport" and "ComparePane"
... does not recognize that Interval was added and may loose the intervals on saving
... causing inconsistency in Cache - blocking the deletion of the interval after re-starting
... add Multimedia Keys to control the train mode
... Start/Stop/Forward/Rewind/Pause working on MCE (Windows Media Center compatible remote controls) without any problems
... tested with 2 MCE remotes
... For "new Lap" none of the special media keys worked - so choose "0" since this is available even on pure remotes
Since in earlier versions of QT not all Keys are defined, just start with 5.4 as pre-requisite.
... store Videosync files in Workout Folder as well / adjust configuration description
... report non-existing Workouts/Videosyncs when scrolling through the treelist (and offer to remove them from the library)
... properly handle "imports" of files from the Workout Directory in case of "overwrite"
... add tr() in multiple places
... unify some of the texts - terminology
... add Directory to Configuration Page
... set Default similar to Workout Directory in Main
General
... start Directory Browsing on Config Page with the configured directory (if is existing/valid)
... collects all relevant Files from the Athletes directory subfolders (keeps the folder structure)
and add them to a .zip file which can be stored in a different folder
... runs automatically when closing an Athlete (window or tab)
... configurable per Athlete
-- Folder into which the .zip shall be stored
-- #of times GC shall close without backup before the backup is activated
(0 == no Auto Backup, every other number "x" means that GC closes
x-1 times without running the backup and after running, resets
the counter)
.. caused v3.2 to crash on interval discovery and
contains out of bound values for power, speed and
cadence.
.. good for testing code doesn't make assumptions about
data values.
.. thanks to Neil Jones for the test file and permission
to distribute for testing
... UTF-8 ByteOrderMarks was missing in the exported XML,... files causing problems on Windows e.g. in cyrillic
... BOM header added for PWX, Fitlog, GC and TCX format
... Fixes https://github.com/GoldenCheetah/GoldenCheetah/issues/1547
.. RideCache::addRide() deletes the prior ride, which is rather meaningless
if you are just importing a ride, but when syncing large numbers
of rides will stop memory being exhausted.
.. similarly in the FileStoreSyncDialog we now free up the memory
used to read the downloaded files before moving on to the next.
.. so we can read/write zip files that can be opened
outside of GC. For example, when working with a file
store we want to write .json.zip that could be read
using winzip et al
.. layout on athlete About row missed leaving a
gap between widgets vertically.
.. moved use CP for FTP checkbox to zone config page
and not on athlete About page.
... use an shared network drive (e.g. mounted via WebDAV) to synchronize activity data
(similar to Dropbox,...)
Open/TBD:
... where to best put the Preferences for the different FileStores
(currently add the Network folder configuration on Preferences->Passwords,
even though no PW is needed - with growing number of FileStores a
dedicated Preferences Page may be the solution)
... where to put the MainWindow Menu entries if the number of FileStores increases
.. Mac Finder creates .DS_Store in subdirectories when you
browse in them to store customisation etc. So we need to
wipe them away when deleting the athlete folders.
.. sync with a dropbox folder
This is based upon the TPDownloadDialog but refactored for
use with a FileStore (in this case Dropbox). It should be
extensible to use with any kind of FileStore object.
... first Athlete opened with new logic determines the general settings
... if configuration is already migrated (based on one of the previous commits) -
migration can be forced to happen again by removing the INI files or
just the preferences pages has to be opened and Saved with the
unit settings you want
.. basic functions working to upload a single ride
to a dropbox file store.
.. this is a safety commit before looking to resolve
issues with async updates.
NOTE: the upload completes but the dialog needs to
be cancelled manually -- this is a bug and
will be resolved in the next update.
.. so you can now choose the directory to sync
data with. Its a very basic file dialog but
will allow you to create and choose a folder.
.. Config is now completed with token a folders
now configurable by the user.
.. I cannot believe we needed to write a pesky file
chooser dialog in 2015 (!)
.. first parts of the implementation of a base class
for working with file stores and the Dropbox
API.
.. all we actually get in this commit is the abstract
classes and an implementation of readdir for Dropbox
along with a config setting which needs to browse
directories
.. in the next commit we'll add the directory chooser
dialog which will need to implement a ftw() across the
associated filestore and present a gui to choose a
directory to store athlete data in
... select only files for import which are created or changed of the last 90/180/360 days
... thus limiting the number of files which are considered for import in the source directory
(without changing/deleting the source files - and without the need to track indexes,...
of what has already been imported).
Based on TCX/GPX support
Includes laps and no-gps support for indoor activities, but not lap swimming.
Test files were contributed by forum members Frederic and Servan
Fixes#1559
... change storage format to .INI files (which is QTs cross-system format)
... differentiate between System, Global and Athlete specific settings
... store the Global Settings in the AthleteDirectory (root)
... store the Athlete specific Settings in the Athletes Names subdir /config
... migrate existing Settings from current location into new formats "on-the-fly"
.. by default no metadata is provided when you
get a ride list. So we now let you specify
via a parameter what metadata fields you
want.
e.g.
http://localhost:12021/athlete?metadata=allhttp://localhost:12021/athlete?metadata=Workout_Code,Recording_Interval
Metric overrides are ignored and all data is
fixed to never send a double quote ("), it is
converted to a single quote (') to avoid tripping
up CSV parsers.
To show it is a string field both the heading and
content are always surrounded by double quotes.
.. now we are able to manage settings with the response
to control how the response is built we don't need to
store it in the JSONContext structure - so just cleaning
it up.
.. to list rides without metrics and therefore just
traverse the activity directory and parse date from
the filename.
.. for a quick way to get a list of activities without
anything to plot etc.
.. adds overlay widgets to show telemetry on top
of video as you ride with a customisable view.
.. not tested but pulled into the repo to enable
testing to start with a view to inclusion in
the 3.3 release.
.. just the key parameters, not the zones themselves.
although we could add that possibly.
URL to get zone config:
http://localhost:12021/athlete/zones
By default will return power zones but can be
called with a 'for' parameter, which is one of;
power, hr, pace, swimpace.
The result is returned as csv data.
.. if the caller sets a content type we can provide in the
header of the http request then we honour it; e.g.
Accept: "text/csv" we will convert to CSV.
.. also updated to set the content type to match the file
format we are providing; just in case the client needs to
know what it got !
.. when retreiving an activity using the API
you can now specify the format you want the
data to be returned in.
it can be one of;
tcx - garmin training centre xml
pwx - training peaks xml
json - goldencheetah json
csv - all available data (not powertap csv)
.. along the way the file writers for the respective
formats now accept a NULL context to work standalone.
this may be useful as a file conversion tool.
.. just straight up for now, so;
http://localhost:12021/athlete/activity/2015_08_09_10_59_09.json
will just return the ride unchanged in the format
it is stored in. Some parameters will now be added
to enable the format to be selected, from those that
we can support.
.. To restrict to more recent rides the
API for list rides will now take a
parameter 'since'
localhost:12021/athlete/?since=2015/02/01
Will only list rides since 1st February 2015
and can of course be used alongside 'metrics'
to control what metrics are returned.
localhost:12021/athlete/?since=2015/02/01&metrics=NP
.. when getting the ride list its useful to be
able to get specific metrics (rather than all
260 odd).
URL can have parameter metrics that is a comma
separated list of metrics to provide e.g;
localhost:12021/athlete/?metrics=NP,Average_Power
.. will provide the metric db for an athlete as the
activity list including all metrics in CSV format
at the URL:
http://localhost:12021/Athlete Name/
The data is sent in chunks as it is parsed from the
ride cache. We do not cache or maintain state so this
call is expensive !
.. just 4 endpoints available;
- list athletes
- list rides
- get ride sample data
- get ride mmp data
.. next few commits will need to implement each of the 4
API endpoints, returning CSV data in the response.
.. GoldenCheetah --server [dir]
Will run without a GUI as a console application sending
log messages to stdout. A web server is never started
when in normal GUI mode.
The optional 'dir' parameter can be used to specify the
location of the athlete data -- you could run several
servers on different directories since the config for the
server is located in the root of the directory.
.. added the http listener, with a default handler
that just returns a 501 Not Implemented result.
.. now the basic server is available we can start to
add a request handler and build up an API that can
be called externally when GC is running.
.. the default config file is written to the gc home
directory above the athlete directories and sets the
server port to 12021.
.. 12021 was chosen as a memorable port number that does
not seem to be used by any other application that is
popular or well known.
.. see http://stefanfrings.de/qtwebapp/index-en.html
.. this is a lightweight web server to allow GC to
provide webservices.
.. we will be providing web services on localhost to
enable R integration.
.. we will use web services to standardise the
interface to provide something we can use in R
but also anything else at a later date.
.. gcconfig.pri contains $$HTPATH that points to
the location of the code, if it is not set then
the web server is not compiled in.
.. allow users to use a set command to add
an override or set metadata under certain
conditions.
e.g. set(Workout_Code, "HT", IF>0.9)
set(TSS, 65, TSS <= 0 && Route = "Fave Loop")
.. we should probably add an unset() command
to do the reverse and clear values under
conditions too.
USE WITH CAUTION -- TAKE A BACKUP BEFORE
MAKING ANY RADICAL CHANGES TO YOUR DATA
.. compare mode now works with user data
series on AllPlot.
.. probably a few minor nits to clean up
and maybe some refinements will come.
One thing is for sure, AllPlot and AllPlotWindow
have reached the limit of maintainability and we
should think carefully about how they move forward.
.. user curves now appear on the series and all plot
with axis hiding etc
Next commit will add to compare mode and then we
can start cleaning up the nits and refining how it
chooses axes and have a checkbox to hide and show
.. Edit dialogs and integration into AllPlotWindow
NOTE: AllPlot does not use the config, or even save
it to the property at this point. We just have
mostly reusable code for user maintenance of
formulas for ride series data.
.. passed to eval and symbols now recongised.
.. sample data is referenced using symbol names
in all caps to make it clear you are referencing
ride dample data.
.. the next commits will add defining formulas and plotting
the derived data series in allplot.
Tie HR warnings to Max-HR, if available, instead of hard-coded 200bpm
Speed warning changes to 9kph for swims, 36 for runs and 100 for rides
Cadence warning changes to 80 for swims, 120 for runs and 200 for rides
"Non-zero torque but zero cadence" is disabled for runs and swims
Fixes#1483
.. To select in a vector. The notation
is a selection criteria followed by
a list of values / vectors
e.g. which(x>0, TSS[date:date])
will create a vector where TSS is non
zero for the day.
"x" is replaced with the vector values
and as such is a special symbol.
.. also fixed a bug with the snip cache.
.. when running a formula it may use a vector
operation to calculate e.g. an average for the
date range.
.. these get called for every ride, but actually they
perform the same calculation over and over
.. we cache the vector operation and result to avoid
repeated calculations; these are only cached whilst
a datafilter is being evaluated, so we do not need
to worry about stale/refreshing.
.. estimate(model, duration) or to get the model
parameters estimate(model, parameter) always
for the date of the ride.
e.g. estimate(2p, cp) gets the estimated CP
for the date of the ride using the classic
2 parameter model
Models are one of;
2p - classic monod scherrer
3p - morton 3p
ext - gc extended
ws - ward-smith
velo - veloclinic
Parameters are one of;
w' - W'
cp - critical power
ftp - functional threshold power
pmax - max power
For watts per kilo just add / config(weight)
or Athlete_Weight to take into account ride
specific weight settings / overrides.
.. can now use a formula in the lts, sts
sb, rr functions.
.. e.g lts(TSS/2) evaluates to the "CTL"
value for the ride if using TSS/2 as
the input.
NOTE: you only get a value where a ride
exists. We may want to think about the
way we scope formulas; are they iterating
over rides or dates ?
.. slight fixup to use Leaf expression not the
entire data filter in PMCData and now the
series is stored in the Athlete PMC store
alongside the other series.
.. just need to adjust the parser to accept
expr rather than symbols as inputs to the
lts functions.
.. to use when e.g. using a data filter as an input
into the PMC functions. The data series is stored
against a signature for the function as opposed to
the metric symbol.
.. we need to do it for an expr not the data filter
.. add the computation of PMC stress using a
data filter as an input as opposed to a
metric.
.. part 2 will update the parser to support
sts/lts/rr/sb to use an expression.
.. part 3 will update Athlete to enable
storing PMCdata against the datafilter signature
instead of a metric name.
.. to use when e.g. using a data filter as an input
into the PMC functions. The data series is stored
against a signature for the function as opposed to
the metric symbol.
.. but do continue to highlight bad symbols etc
with a red wavy line.
.. still need to;
a) syntax highlight in the formula edit (just symbols
and literals, not parsing content)
b) add an error navigator to click on errors and have the
text highlighted that incurred that error.
Adding a comparison expression cexpr and separate productions
for each operator allows to define precedence rules to remove
all shift-reduce conflicts, except one due to the -probably
harmless- (expr) and (lexpr) ambiguity.
.. the daterange() commit broke almost every builtin
function ! (it converted them to integers due to
and if/else logic error.
.. also tidied parser to separate literals and symbols
whilst making builtin functions expr elements to
look more closely at precedence
.. oopsie on binary expression.
NOTE: it may be better to highlight tokens rather than
via the parser as errors make it impossible to
highlight the "intention" of the user
Particularly useful when working with a vector
but can be used with other things.
e.g. max(xPower, BikeScore)
Or, for getting a ride's TSS expressed as a percentage
of the average TSS for the currently selected daterange.
e.g. TSS / mean(TSS[daterange(start):daterange(stop)])
You can create a vector using the notation:
expr [ from : to ]
Where 'expr' will be evaluated for every activity
between the dates from and to.
e.g. TSS[today - 90 : today]
will evaluate to TSS for the last 90 days
e.g. Activities [ date:date ] > 1
Will find all days with more than one workout.
.. when using a vector in any arithmetic expression it
will be evaluated to a sum; this will be fixed shortly
to enable the use of sum/mean/max/min functions.
.. If needed we can add vector operations but this will
likely confuse many users (hell, they confuse developers)
so we will need a good reason to add them !
Lastly, I have also added daterange(from) and daterange(to)
literals to get access to the currently selected daterange
when working in the trends view.
.. update the editor to do some basic syntax
highlighting; literals in red, comments in
blue and so on.
.. next commit will focus on highlighting errors
with a wavy line and some form of error list.
.. updated the datafilter to handle general functions
and parse them without needing them declared in the lexer
.. makes it much easier to add new functions in the future
.. did this to add core math functions;
* sin, cos, tan, asin, acos, atan,
* sinh, cosh, tanh, asinh, acosh, atanh
* exp, log, log10, ceil, floor, round
* fabs, isinf, isnan
.. we can add more later; erf/gamma spring to mind !
.. uses the C/C++ notation:
expr ? expr2 : expr3
Where expr is the condition e.g. X>2
and expr2 is what to evaluate to if expr is true
and expr3 is what to evaluate to if expr is false
e.g.
(Workout_Code = "1L3") ? 1 : 0
Will evaluate as 1 for all workouts where the
workout code is 1L3 and 0 for all other workouts.
.. now will repeat completion beyond the very
first word on the line
.. needs to be enhanced to work when not at the
end of the text (i.e. cursor move)
.. resize event was checking menu icon, which was never
going to change due to a resize event.
.. it crashed during window exit since it dereferenced objects
that had been deleted.
.. for now, it crashes occasionally due to cross-thread
issues, and doesn't work across the text anyway.
will make it permanently associated by not active
when in search mode.
.. get rid of terrible cut and paste code, duplicating
eval for particular leafs
.. eval returns a Result() object which can be numeric
or textual (date strings are parsed to numeric)
.. can now add formulas to LTM as well as adding more
functions that may be useful (conditionals, maths
spring to mind first).
... removing tests,... from LIBKML build
... allowing building of base functionality of LIBKML on Windows with MinGW
... covering the LIBKML functional scope used by GoldenCheetah
.. NP > 200 && IF > 0.85 didn't work because the datafilter
grammar needed fixing up for precedence of the && and || operators.
.. this has been fixed by embedding into the grammar; binary expressions
and logical expressions are now declared individually.
.. the generated tree uses the same encoding so no changes required
to the code, just the grammar
Imported data:
- speed, cadence, hearthrate, power, latitude, longitude, altitude, temperature.
Laps are not yet supported. (laps in Rox 10.0 slf are encoded at the end of the file as <Markers>).
In case user borked them in setup, applies to:
- Ride Date (startTime.date)
- Ride Time (startTime.time)
- Device (deviceType)
- Recording Interval (recIntSecs)
- Identifier (Id)
Since latest update for metadata now honours user configuration.
.. change LTM trend background to same as ride plot on upgrade
as by default it will be black and look different
.. remove metal look on anything other than Mac prior to the
10.10 Yosemite look. Metal looks naff these days.
.. we have been granted permission to use the TCore algorithm
and so the attributions have been added to the code and about
box.
.. Mark Buller should be added to the contributors too.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.