Planner: Improve Gas Handling in CCR Mode.
This has become a bit of a catch-all overhaul of a large portion of the planner - I started out wanting to improve the CCR mode, but then as I started pulling all the other threads that needed addressing started to come with it. Improve how the gas selection is handled when planning dives in CCR mode, by making the type (OC / CCR) of segments dependent on the gas use type that was set for the selected gas. Add a preference to allow the user to chose to use OC gases as diluent, in a similar fashion to the original implementation. Hide gases that cannot be used in the currently selected dive mode in all drop downs. Include usage type in gas names if this is needed. Hide columns and disable elements in the 'Dive planner points' table if they can they can not be edited in the curently selected dive mode. Visually identify gases and usage types that are not appropriate for the currently selected dive mode. Move the 'Dive mode' selection to the top of the planner view, to accommodate the fact that this is a property of the dive and not a planner setting. Show a warning instead of the dive plan if the plan contains gases that are not usable in the selected dive mode. Fix the data entry for the setpoint in the 'Dive planner points' table. Fix problems with enabling / disabling planner settings when switching between dive modes. Refactor some names to make them more appropriate for their current usage. One point that is still open is to hide gas usage graphs in the planner profile if the gas isn't used for OC, as there is no way to meaningfully interpolate such usage. Signed-off-by: Michael Keller <github@ike.ch>
3
.gitignore
vendored
|
@ -17,6 +17,9 @@ Documentation/docbook-xsl.css
|
|||
Documentation/user-manual*.html
|
||||
Documentation/user-manual*.pdf
|
||||
Documentation/user-manual*.text
|
||||
Documentation/mobile-manual*.html
|
||||
Documentation/mobile-manual*.pdf
|
||||
Documentation/mobile-manual*.text
|
||||
Documentation/mobile-images/mobile-images
|
||||
packaging/windows/subsurface.nsi
|
||||
packaging/macos/Info.plist
|
||||
|
|
Before Width: | Height: | Size: 22 KiB |
BIN
Documentation/images/CCR_b1.png
Normal file
After Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 30 KiB |
BIN
Documentation/images/CCR_b2.png
Normal file
After Width: | Height: | Size: 189 KiB |
Before Width: | Height: | Size: 32 KiB |
BIN
Documentation/images/CCR_b3.png
Normal file
After Width: | Height: | Size: 198 KiB |
Before Width: | Height: | Size: 71 KiB |
BIN
Documentation/images/PlannerWindow1.png
Normal file
After Width: | Height: | Size: 350 KiB |
Before Width: | Height: | Size: 81 KiB |
BIN
Documentation/images/Planner_CCR.png
Normal file
After Width: | Height: | Size: 321 KiB |
Before Width: | Height: | Size: 81 KiB |
BIN
Documentation/images/Planner_OC_deco.png
Normal file
After Width: | Height: | Size: 346 KiB |
BIN
Documentation/images/Planner_OC_gas_for_CCR.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 69 KiB |
BIN
Documentation/images/Planner_OC_rec1.png
Normal file
After Width: | Height: | Size: 227 KiB |
Before Width: | Height: | Size: 74 KiB |
BIN
Documentation/images/Planner_OC_rec2.png
Normal file
After Width: | Height: | Size: 235 KiB |
BIN
Documentation/images/Planner_issues.png
Normal file
After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 86 KiB |
BIN
Documentation/images/Planner_pSCR.png
Normal file
After Width: | Height: | Size: 341 KiB |
Before Width: | Height: | Size: 31 KiB |
BIN
Documentation/images/planner1.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
Documentation/images/planner2.png
Normal file
After Width: | Height: | Size: 18 KiB |
|
@ -3825,24 +3825,18 @@ user interface. It is explicitly used under the following conditions:
|
|||
|
||||
=== The _Subsurface_ dive planner screen
|
||||
|
||||
Like the _Subsurface_ dive log, the planner screen is divided into several sections (see image below). The *setup*
|
||||
parameters for a dive are entered into the sections on the left hand and bottom side of the screen.
|
||||
They are: Available Gases, Rates, Planning, Gas Options and Notes.
|
||||
|
||||
At the top right hand is a green *design panel* on which the profile of the dive can be
|
||||
manipulated directly by dragging and clicking as explained below. This feature makes the
|
||||
_Subsurface_ dive planner unique in ease of use.
|
||||
|
||||
At the bottom right is a text panel with a heading of _Dive Plan Details_. This is where the details of
|
||||
the dive plan are provided in a way that can easily be copied to other software. This is also where
|
||||
any warning messages about the dive plan are printed.
|
||||
|
||||
image::images/PlannerWindow1.jpg["FIGURE: Dive planner startup window",align="center"]
|
||||
Like the _Subsurface_ dive log, the planner screen is divided into several sections (see image below):
|
||||
- At the top left of the screen are the *dive parameters* that will be stored with the planned dive, like dive time, dive mode, and water type.
|
||||
- Below this are tables that allow the user to configure the *cylinders* used on the dive, and the *depth / time and breathing gas* used for the individual parts of the planned dive.
|
||||
- At the bottom of the screen are the *parameters used by the planner* to plan the dive, like ascent / descent rates, planning parameters, and gas options.
|
||||
- At the top right hand is a green *design panel* on which the profile of the dive can be manipulated directly by dragging and clicking as explained below. This feature makes the _Subsurface_ dive planner unique in ease of use.
|
||||
- On the bottom right is a field for the *dive plan details* - this is where the planner will show the dive plan in text form, which will also persisted to the dive notes when the planned dive is saved. This field is designe to be easily copied to other software. It also shows any warning messages about the dive plan.
|
||||
|
||||
image::images/PlannerWindow1.png["FIGURE: Dive planner startup window",align="center"]
|
||||
|
||||
=== Open circuit dives
|
||||
|
||||
- Towards the center bottom of the planner (circled in blue in the image above) is a dropdown list with three options. Select the appropriate one of these:
|
||||
- In the top left of the planner (circled in blue in the image above) is a dropdown list with three options. Select the appropriate one of these:
|
||||
** Open Circuit (the default)
|
||||
** CCR
|
||||
** pSCR
|
||||
|
@ -3870,7 +3864,7 @@ image::images/PlannerWindow1.jpg["FIGURE: Dive planner startup window",align="ce
|
|||
O~2~% according to the depth set. Set to ''*'' to calculate the best O~2~% for the dive maximum depth.
|
||||
** MND: the gas Maximum Narcotic Depth (MND). Automatically calculated based on the Best Mix END
|
||||
preference (default 30m / 98 ft). Editing this field will modify the He% according to the depth set.
|
||||
Set to ''*'' to calculate the best He% for the dive maximum depth. Depending on the checkbox, oxygen
|
||||
Set to ''*'' to calculate the best He% for the dive maximum depth. Depending on the checkbox, oxygen
|
||||
is considered narcotic (the END is used) or not (the EAD is used).
|
||||
|
||||
- The profile of the planned dive can be created in two ways:
|
||||
|
@ -3882,11 +3876,14 @@ image::images/PlannerWindow1.jpg["FIGURE: Dive planner startup window",align="ce
|
|||
* The most efficient way to create a dive profile is to enter the appropriate values into the table
|
||||
marked _Dive planner points_. The first line of the table represents the duration and the final
|
||||
depth of the descent from the surface. Subsequent segments describe the bottom phase of the dive.
|
||||
The _CC setpoint_ column is only relevant for closed circuit divers.
|
||||
The ascent is usually not specified because this is what the planner is supposed to calculate.
|
||||
Add additional segments to the profile by selecting the "+" icon at the top right hand of the
|
||||
table. Segments entered into the _Dive planner points_ table automatically appear in the *Dive
|
||||
Profile* diagram.
|
||||
* If the _Dive mode_ of the planned dive is changed after gases and segments have been added, it can happen that the _Use_ of a gasmix or the _Used gas_ selected for a segment are not appropriate for the selected _Dive mode_. In this case _Subsurface_ will highlight the problematic selection with a red background to help the user identify and correct the issue. The dive plan will not be calculated until all issues are resolved.
|
||||
|
||||
image::images/Planner_issues.png["FIGURE: Dive planner: Issue display",align="center"]
|
||||
|
||||
|
||||
==== Recreational dives
|
||||
|
||||
|
@ -3963,7 +3960,7 @@ the nitrogen load incurred during previous dives.
|
|||
Below is an image of a dive plan for a recreational dive at 30 meters with gradient factors of 100. Because the no-deco limit (NDL) is 22
|
||||
minutes, there remains a significant amount of air in the cylinder at the end of the dive.
|
||||
|
||||
image::images/Planner_OC_rec1.jpg["FIGURE: A recreational dive plan: setup",align="center"]
|
||||
image::images/Planner_OC_rec1.png["FIGURE: A recreational dive plan: setup",align="center"]
|
||||
|
||||
The dive profile in the planner shows the maximum dive time within no-deco limits using the
|
||||
Bühlmann ZH-L16 algorithm and the gas and depth settings specified as described above. The _Subsurface_ planner
|
||||
|
@ -3976,7 +3973,7 @@ it means that recreational dive limits are exceeded and either the dive duration
|
|||
Below is the same dive plan as above, but with a safety stop and reduced gradient factors for
|
||||
a larger safety margin.
|
||||
|
||||
image::images/Planner_OC_rec2.jpg["FIGURE: A recreational dive plan: gradient factors setup",align="center"]
|
||||
image::images/Planner_OC_rec2.png["FIGURE: A recreational dive plan: gradient factors setup",align="center"]
|
||||
|
||||
==== Non-recreational open circuit dives, including decompression
|
||||
|
||||
|
@ -4093,12 +4090,16 @@ _Type_ select the appropriate cylinder size by using the dropdown list that appe
|
|||
double-clicking a cell in this column. By default, a large number of sizes are listed,
|
||||
and a new cylinder size can be created by typing this into the text box. The cylinder size, start pressure
|
||||
and default switch depths are initialized automatically. Specify the gas composition
|
||||
(e.g. helium and oxygen content). A non-zero value in the "CC setpoint" column of the table of dive planner points
|
||||
indicates a valid setpoint for oxygen partial pressure and that the segment
|
||||
is dived using a closed circuit rebreather (CCR). If the last manually entered
|
||||
segment is a CCR segment, the decompression phase is computed assuming the diver
|
||||
(e.g. helium and oxygen content) and - in the case of planning a CCR dive, the intended use as diluent or OC bailout gas.
|
||||
When planning CCR dives, a segment is calculated as a closed circuit segment if the gas that is used is a _diluent_, and as an open circuit segment if the gas is an _OC-gas_. If the user enables the _Allow open circuit gas to be used as bailout_ option in the _Tech setup_ preferences, then an additional column will be shown allowing the user to select the _Dive mode_ for each segment dived on an _OC-gas_.
|
||||
|
||||
image::images/Planner_OC_gas_for_CCR.png["FIGURE: Planning a dive: OC as CCR",align="center"]
|
||||
|
||||
For CCR dives, an additional column is shown in the _Dive planner points_ table, allowing the user to specify the _Setpoint_ for each closed circuit segment.
|
||||
If the last manually entered
|
||||
segment is a closed circuit segment, the decompression phase is computed assuming the diver
|
||||
uses a CCR with the specified set-point. If the last segment (however
|
||||
short) is on open circuit (OC, indicated by a zero set-point) the
|
||||
short) is on open circuit the
|
||||
decompression is computed in OC mode and the planner only considers gas
|
||||
changes in OC mode.
|
||||
|
||||
|
@ -4112,16 +4113,19 @@ you wish to use this gas during the very start of the dive (the other gas is not
|
|||
Upon pressing Enter on the keyboard, that segment is moved to the top of that table and the plan is adjusted
|
||||
automatically to take into account this new segment of the dive plan (image B below).
|
||||
|
||||
image::images/planner1.jpg["FIGURE: Planning a dive: segments",align="center"]
|
||||
*A:*
|
||||
image::images/planner1.png["FIGURE: Planning a dive: segments 1/2",align="center"]
|
||||
*B:*
|
||||
image::images/planner2.png["FIGURE: Planning a dive: segments 2/2",align="center"]
|
||||
|
||||
Below is an example of a dive plan to 55m using Tx20/30 and the Bühlmann algorithm,
|
||||
followed by an ascent using EAN50 and using the settings as described above.
|
||||
|
||||
image::images/Planner_OC_deco.jpg["FIGURE: Planning a dive: setup",align="center"]
|
||||
image::images/Planner_OC_deco.png["FIGURE: Planning a dive: setup",align="center"]
|
||||
|
||||
Once the above steps have been completed, save by clicking the _Save_ button
|
||||
towards the top middle of the planner. The saved dive plan will appear
|
||||
in the *Dive List* panel of _Subsurface_.
|
||||
in the _Dive List_ panel of _Subsurface_.
|
||||
|
||||
*The dive plan details*
|
||||
|
||||
|
@ -4238,7 +4242,7 @@ are specified for pSCR dives. Below is a dive plan for a pSCR dive. The dive is
|
|||
to that of the CCR dive below, but note the longer ascent duration due to the lower oxygen
|
||||
in the loop due to the oxygen drop across the mouthpiece of the pSCR equipment.
|
||||
|
||||
image::images/Planner_pSCR.jpg["FIGURE: Planning a pSCR dive: setup",align="center"]
|
||||
image::images/Planner_pSCR.png["FIGURE: Planning a pSCR dive: setup",align="center"]
|
||||
|
||||
==== Planning for pSCR bailout
|
||||
|
||||
|
@ -4283,7 +4287,7 @@ columns, as in the cave example, above. See the example of bailout for a CCR div
|
|||
=== Planning CCR dives
|
||||
|
||||
To plan a dive using a closed circuit rebreather, select the _CCR_ option in the dropdown
|
||||
list, circled in blue in the image below.
|
||||
list.
|
||||
|
||||
*Available gases*: In the _Available gases_ table, enter the cylinder information for the
|
||||
diluent cylinder and for any bail-out cylinders. Do NOT enter the information for the oxygen
|
||||
|
@ -4292,14 +4296,9 @@ cylinder since it is implied when the _CCR_ dropdown selection is made.
|
|||
*Entering setpoints*: Specify a default setpoint in the Preferences tab, by selecting _File -> Preferences -> Tech setup_ from
|
||||
the main menu. All user-entered segments in the _Dive planner points_ table
|
||||
use the default setpoint value. Then, different setpoints can be specified for dive segments
|
||||
in the _Dive planner points_ table. A zero setpoint
|
||||
means the diver bails out to open circuit mode for that segment. Decompression is always calculated
|
||||
using the setpoint of the last manually entered segment. So, to plan a bail out ascent for a
|
||||
CCR dive, add a one-minute dive segment to the end with a setpoint value of 0. The decompression
|
||||
algorithm does not switch deco-gases automatically while in CCR mode (i.e. when a positive setpoint is specified) but
|
||||
this is calculated for bail out ascents.
|
||||
in the _Dive planner points_ table.
|
||||
|
||||
If you want the setpoint to change during the planned ascent at a specified depth, you can do this
|
||||
If you want the setpoint to change during the planned ascent at a specified depth, you can do this
|
||||
using a "fake" cylinder that you add to the gas list: Give that cylinder a name of "SP 1.4" (or use
|
||||
a different number) and set the "Deco switch value" to the depth at which you want to set the new
|
||||
setpoint. This will make the planner stop at the specified depth and use the new setpoint from
|
||||
|
@ -4307,36 +4306,30 @@ there on.
|
|||
|
||||
The dive profile for a CCR dive may look something like the image below.
|
||||
|
||||
image::images/Planner_CCR.jpg["FIGURE: Planning a CCR dive: setup",align="center"]
|
||||
image::images/Planner_CCR.png["FIGURE: Planning a CCR dive: setup",align="center"]
|
||||
|
||||
Note that, in the _Dive plan details_, the gas consumption for a CCR segment is not calculated,
|
||||
so gas consumptions of 0 liters are the norm.
|
||||
|
||||
==== Planning for CCR bailout
|
||||
|
||||
[icon="images/CCR_b1.jpg"]
|
||||
[NOTE]
|
||||
image::images/CCR_b1.png["FIGURE: Planning a CCR dive: closed circuit deco",align="center"]
|
||||
|
||||
It is often necessary to plan for a worst-case bailout event in order to ensure sufficient bailout gas to reach the
|
||||
surface, taking into account decompression. This is done by 1) checking the _Bailout_ checkbox of the dive planner
|
||||
(bailout will be calculated starting at the last segment of the dive specified in the _Dive planner points_ table);
|
||||
2) defining a 1-minute segment at the end of the bottom part
|
||||
of the dive, as in the image on the left where a CCR dive to 40m for 21 minutes is planned;
|
||||
3) changing to an OC-gas during any segment in the _Dive planner points_ table.
|
||||
surface, taking into account decompression. This is done by checking the _Rebreather: Bailout / Deco on OC_ checkbox of the dive planner
|
||||
(bailout will be calculated starting at the last segment of the dive specified in the _Dive planner points_ table):
|
||||
|
||||
image::images/CCR_b2.png["FIGURE: Planning a CCR dive: open circuit bailout",align="center"]
|
||||
|
||||
[icon="images/CCR_b2.jpg"]
|
||||
[NOTE]
|
||||
In the _Dive planner points
|
||||
table_, change the _Dive mode_ of this 1-minute segment to _OC_. This signifies bailout. In this case there is bailout to
|
||||
the existing diluent cylinder (assuming this cylinder has sufficient gas). The appropriate pO~2~ and cylinder pressure
|
||||
graphs are shown in the dive profile, as in the image on the left. Note that the setpoint drops to zero after bailout, since
|
||||
this value does not apply to breathed bailout gas.
|
||||
In the _Available gases_
|
||||
table, change the _Use_ of the gas used for the last segment to _OC-gas_. This signifies bailout.
|
||||
The appropriate pO~2~ and cylinder pressure
|
||||
graphs are shown in the dive profile:
|
||||
|
||||
image::images/CCR_b3.png["FIGURE: Planning a CCR dive: open circuit bailout by cylinder selection",align="center"]
|
||||
|
||||
[icon="images/CCR_b3.jpg"]
|
||||
[NOTE]
|
||||
In order to plan for bailout to an external bailout cylinder, change the _Used gas_ for the 1-minute segment to the
|
||||
appropriate cylinder, as in the example on the left. Note that the cylinder change as well as the bailout are indicated with
|
||||
appropriate cylinder, as in the example above. Note that the cylinder change as well as the bailout are indicated with
|
||||
overlapping icons.
|
||||
|
||||
The volumes of gases required for bailout can be found at the bottom of the *Dive plan details* panel.
|
||||
|
|
|
@ -1260,7 +1260,7 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
|
|||
setText(Command::Base::tr("Edit cylinder (%n dive(s))", "", dives.size()));
|
||||
|
||||
// The base class copied the cylinders for us, let's edit them
|
||||
for (int i = 0; i < (int)indexes.size(); ++i) {
|
||||
for (int i = 0; i < (int)cyl.size(); ++i) {
|
||||
switch (type) {
|
||||
case EditCylinderType::TYPE:
|
||||
cyl[i].type = cylIn.type;
|
||||
|
|
|
@ -1625,6 +1625,35 @@ static bool cylinder_in_use(const struct dive *dive, int idx)
|
|||
return cylinder_has_data(dive->cylinders[idx]);
|
||||
}
|
||||
|
||||
bool is_cylinder_use_appropriate(const struct divecomputer &dc, const cylinder_t &cyl, bool allowNonUsable)
|
||||
{
|
||||
switch (cyl.cylinder_use) {
|
||||
case OC:
|
||||
if (dc.divemode == FREEDIVE)
|
||||
return false;
|
||||
|
||||
break;
|
||||
case OXYGEN:
|
||||
if (!allowNonUsable)
|
||||
return false;
|
||||
|
||||
case DILUENT:
|
||||
if (dc.divemode != CCR)
|
||||
return false;
|
||||
|
||||
break;
|
||||
case NOT_USED:
|
||||
if (!allowNonUsable)
|
||||
return false;
|
||||
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merging cylinder information is non-trivial, because the two dive computers
|
||||
* may have different ideas of what the different cylinder indexing is.
|
||||
|
@ -2451,7 +2480,7 @@ int dive::mbar_to_depth(int mbar) const
|
|||
|
||||
if (!surface_pressure.mbar)
|
||||
surface_pressure.mbar = SURFACE_PRESSURE;
|
||||
|
||||
|
||||
return rel_mbar_to_depth(mbar - surface_pressure.mbar);
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@ struct dive_or_trip {
|
|||
|
||||
extern void cylinder_renumber(struct dive &dive, int mapping[]);
|
||||
extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
|
||||
extern bool is_cylinder_use_appropriate(const struct divecomputer &dc, const cylinder_t &cyl, bool allowNonUsable);
|
||||
|
||||
/* Data stored when copying a dive */
|
||||
struct dive_paste_data {
|
||||
|
|
|
@ -35,7 +35,7 @@ struct divecomputer {
|
|||
pressure_t surface_pressure;
|
||||
enum divemode_t divemode = OC; // dive computer type: OC(default) or CCR
|
||||
uint8_t no_o2sensors = 0; // rebreathers: number of O2 sensors used
|
||||
int salinity = 0; // kg per 10000 l
|
||||
int salinity = 0; // kg per 10000 l
|
||||
std::string model, serial, fw_version;
|
||||
uint32_t deviceid = 0, diveid = 0;
|
||||
// Note: ve store samples, events and extra_data in std::vector<>s.
|
||||
|
|
|
@ -4,4 +4,6 @@
|
|||
|
||||
enum divemode_t {OC, CCR, PSCR, FREEDIVE, NUM_DIVEMODE, UNDEF_COMP_TYPE}; // Flags (Open-circuit and Closed-circuit-rebreather) for setting dive computer type
|
||||
|
||||
#define IS_REBREATHER_MODE(divemode) ((divemode) == CCR || (divemode) == PSCR)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -380,14 +380,17 @@ static int setpoint_change(struct dive *dive, int cylinderid)
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<gaschanges> analyze_gaslist(struct diveplan *diveplan, struct dive *dive, int depth, int *asc_cylinder, bool ccr)
|
||||
static std::vector<gaschanges> analyze_gaslist(struct diveplan *diveplan, struct dive *dive, int dcNr, int depth, int *asc_cylinder, bool ccr, bool &inappropriate_cylinder_use)
|
||||
{
|
||||
size_t nr = 0;
|
||||
std::vector<gaschanges> gaschanges;
|
||||
struct divedatapoint *dp = diveplan->dp;
|
||||
struct divedatapoint *best_ascent_dp = NULL;
|
||||
bool total_time_zero = true;
|
||||
const divecomputer *dc = dive->get_dc(dcNr);
|
||||
while (dp) {
|
||||
inappropriate_cylinder_use = inappropriate_cylinder_use || !is_cylinder_use_appropriate(*dc, *dive->get_cylinder(dp->cylinderid), false);
|
||||
|
||||
if (dp->time == 0 && total_time_zero && (ccr == (bool) setpoint_change(dive, dp->cylinderid))) {
|
||||
if (dp->depth.mm <= depth) {
|
||||
int i = 0;
|
||||
|
@ -661,7 +664,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
|||
bool o2break_next = false;
|
||||
int break_cylinder = -1, breakfrom_cylinder = 0;
|
||||
bool last_segment_min_switch = false;
|
||||
bool error = false;
|
||||
planner_error_t error = PLAN_OK;
|
||||
bool decodive = false;
|
||||
int first_stop_depth = 0;
|
||||
int laststoptime = timestep;
|
||||
|
@ -744,7 +747,11 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
|||
|
||||
/* Find the gases available for deco */
|
||||
|
||||
std::vector<gaschanges> gaschanges = analyze_gaslist(diveplan, dive, depth, &best_first_ascend_cylinder, divemode == CCR && !prefs.dobailout);
|
||||
bool inappropriate_cylinder_use = false;
|
||||
std::vector<gaschanges> gaschanges = analyze_gaslist(diveplan, dive, dcNr, depth, &best_first_ascend_cylinder, divemode == CCR && !prefs.dobailout, inappropriate_cylinder_use);
|
||||
if (inappropriate_cylinder_use) {
|
||||
error = PLAN_ERROR_INAPPROPRIATE_GAS;
|
||||
}
|
||||
|
||||
/* Find the first potential decostopdepth above current depth */
|
||||
for (stopidx = 0; stopidx < decostoplevelcount; stopidx++)
|
||||
|
@ -880,7 +887,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
|||
current_cylinder = 0;
|
||||
}
|
||||
reset_regression(ds);
|
||||
while (1) {
|
||||
while (error == PLAN_OK) {
|
||||
/* We will break out when we hit the surface */
|
||||
do {
|
||||
/* Ascend to next stop depth */
|
||||
|
@ -1005,7 +1012,8 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
|||
laststoptime = new_clock - clock;
|
||||
/* Finish infinite deco */
|
||||
if (laststoptime >= 48 * 3600 && depth >= 6000) {
|
||||
error = true;
|
||||
error = PLAN_ERROR_TIMEOUT;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1070,7 +1078,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
|
|||
* if the ascent rate is slower, which is completely nonsensical.
|
||||
* Assume final ascent takes 20s, which is the time taken to ascend at 9m/min from 3m */
|
||||
ds->deco_time = clock - bottom_time - (M_OR_FT(3,10) * ( prefs.last_stop ? 2 : 1)) / last_ascend_rate + 20;
|
||||
} while (!is_final_plan);
|
||||
} while (!is_final_plan && error == PLAN_OK);
|
||||
decostoptable[decostopcounter].depth = 0;
|
||||
|
||||
plan_add_segment(diveplan, clock - previous_point_time, 0, current_cylinder, po2, false, divemode);
|
||||
|
@ -1112,24 +1120,31 @@ static int get_decimals(const char *begin, const char **endp, const unsigned dec
|
|||
return -1;
|
||||
|
||||
/* Fraction? We only look at the first digit */
|
||||
if (*end == '.') {
|
||||
unsigned fraction = 0;
|
||||
for (unsigned i = 0; i < decimals; i++) {
|
||||
value *= 10;
|
||||
if (*end == '.')
|
||||
end++;
|
||||
|
||||
unsigned fraction = 0;
|
||||
for (unsigned i = 0; i < decimals; i++) {
|
||||
value *= 10;
|
||||
|
||||
unsigned digit = 0;
|
||||
if (isdigit(*end)) {
|
||||
digit = *end - '0';
|
||||
|
||||
end++;
|
||||
|
||||
if (!isdigit(*end))
|
||||
return -1;
|
||||
|
||||
fraction = 10 * fraction + (*end - '0');
|
||||
} else if (*end != '\0') {
|
||||
return -1;
|
||||
}
|
||||
value += fraction;
|
||||
|
||||
do {
|
||||
end++;
|
||||
} while (isdigit(*end));
|
||||
fraction = 10 * fraction + digit;
|
||||
|
||||
}
|
||||
value += fraction;
|
||||
|
||||
do {
|
||||
end++;
|
||||
} while (isdigit(*end));
|
||||
|
||||
*endp = end;
|
||||
return value;
|
||||
}
|
||||
|
@ -1209,5 +1224,9 @@ int validate_po2(const char *text, int *mbar_po2)
|
|||
return 0;
|
||||
|
||||
*mbar_po2 = po2 * 10;
|
||||
|
||||
if (*mbar_po2 < 160)
|
||||
*mbar_po2 = 160;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -34,11 +34,17 @@ struct diveplan {
|
|||
|
||||
struct deco_state_cache;
|
||||
|
||||
typedef enum {
|
||||
PLAN_OK,
|
||||
PLAN_ERROR_TIMEOUT,
|
||||
PLAN_ERROR_INAPPROPRIATE_GAS,
|
||||
} planner_error_t;
|
||||
|
||||
extern int validate_gas(const char *text, struct gasmix *gas);
|
||||
extern int validate_po2(const char *text, int *mbar_po2);
|
||||
extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time);
|
||||
extern bool diveplan_empty(struct diveplan *diveplan);
|
||||
extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, bool error);
|
||||
extern void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error);
|
||||
extern const char *get_planner_disclaimer();
|
||||
|
||||
extern void free_dps(struct diveplan *diveplan);
|
||||
|
|
|
@ -96,7 +96,7 @@ extern std::string get_planner_disclaimer_formatted()
|
|||
return format_string_std(get_planner_disclaimer(), deco);
|
||||
}
|
||||
|
||||
void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, bool error)
|
||||
void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, planner_error_t error)
|
||||
{
|
||||
std::string buf;
|
||||
std::string icdbuf;
|
||||
|
@ -122,12 +122,31 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
|
|||
if (!dp)
|
||||
return;
|
||||
|
||||
if (error) {
|
||||
if (error != PLAN_OK) {
|
||||
const char *message;
|
||||
switch (error) {
|
||||
case PLAN_ERROR_TIMEOUT:
|
||||
message = translate("gettextFromC", "Decompression calculation aborted due to excessive time");
|
||||
|
||||
break;
|
||||
case PLAN_ERROR_INAPPROPRIATE_GAS:
|
||||
message = translate("gettextFromC", "One or more tanks with a tank use type inappropriate for the selected dive mode are included in the dive plan. "
|
||||
"Please change them to appropriate tanks to enable the generation of a dive plan.");
|
||||
|
||||
break;
|
||||
default:
|
||||
message = translate("gettextFromC", "An error occurred during dive plan generation");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
buf += format_string_std("<span style='color: red;'>%s </span> %s<br/>",
|
||||
translate("gettextFromC", "Warning:"),
|
||||
translate("gettextFromC", "Decompression calculation aborted due to excessive time"));
|
||||
translate("gettextFromC", "Warning:"), message);
|
||||
|
||||
// TODO: avoid copy
|
||||
dive->notes = buf;
|
||||
dive->notes = strdup(buf.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ preferences::preferences() :
|
|||
vpmb_conservatism(3),
|
||||
zoomed_plot(false),
|
||||
infobox(true),
|
||||
allowOcGasAsDiluent(false),
|
||||
coordinates_traditional(true),
|
||||
unit_system(METRIC),
|
||||
units(SI_UNITS)
|
||||
|
|
|
@ -201,6 +201,7 @@ struct preferences {
|
|||
int vpmb_conservatism;
|
||||
bool zoomed_plot;
|
||||
bool infobox;
|
||||
bool allowOcGasAsDiluent;
|
||||
|
||||
// ********** Units **********
|
||||
bool coordinates_traditional;
|
||||
|
|
|
@ -1151,19 +1151,51 @@ QString get_gas_string(struct gasmix gas)
|
|||
return result;
|
||||
}
|
||||
|
||||
QStringList get_dive_gas_list(const struct dive *d)
|
||||
QString get_dive_gas(const struct dive *d, int dcNr, int cylinderId)
|
||||
{
|
||||
QStringList list;
|
||||
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
|
||||
/* Check if we have the same gasmix two or more times
|
||||
* If yes return more verbose string */
|
||||
int same_gas = same_gasmix_cylinder(cyl, i, d, true);
|
||||
if (same_gas == -1)
|
||||
list.push_back(get_gas_string(cyl.gasmix));
|
||||
else
|
||||
list.push_back(get_gas_string(cyl.gasmix) + QStringLiteral(" (%1 %2 ").arg(gettextFromC::tr("cyl.")).arg(i + 1) +
|
||||
QString::fromStdString(cyl.type.description) + ")");
|
||||
const cylinder_t *cyl = d->get_cylinder(cylinderId);
|
||||
const divecomputer *dc = d->get_dc(dcNr);
|
||||
|
||||
bool showUse = (dc->divemode == CCR) | !is_cylinder_use_appropriate(*dc, *cyl, false);
|
||||
|
||||
QString gasType = get_gas_string(cyl->gasmix);
|
||||
QString gasName;
|
||||
/* Check if we have the same gasmix two or more times
|
||||
* If yes return more verbose string */
|
||||
int same_gas = same_gasmix_cylinder(*cyl, cylinderId, d, true);
|
||||
if (same_gas != -1) {
|
||||
gasType += QString(" (%1 %2").arg(gettextFromC::tr("cyl.")).arg(cylinderId + 1);
|
||||
gasName = QString::fromStdString(d->get_cylinder(cylinderId)->type.description);
|
||||
}
|
||||
|
||||
if (showUse) {
|
||||
if (gasName.isNull())
|
||||
gasType += " (";
|
||||
else
|
||||
gasType += ", ";
|
||||
gasType += gettextFromC::tr(cylinderuse_text[d->get_cylinder(cylinderId)->cylinder_use]);
|
||||
}
|
||||
|
||||
if (!gasName.isNull())
|
||||
gasType += QString(", %1").arg(gasName);
|
||||
|
||||
if (!gasName.isNull() || showUse)
|
||||
gasType += ")";
|
||||
|
||||
return gasType;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, QString>> get_dive_gas_list(const struct dive *d, int dcNr, bool showOnlyAppropriate)
|
||||
{
|
||||
const divecomputer *dc = d->get_dc(dcNr);
|
||||
std::vector<std::pair<int, QString>> list;
|
||||
for (unsigned int i = 0; i < d->cylinders.size(); i++) {
|
||||
if (showOnlyAppropriate && !is_cylinder_use_appropriate(*dc, *d->get_cylinder(i), false))
|
||||
continue;
|
||||
|
||||
list.push_back(std::pair(i, get_dive_gas(d, dcNr, i)));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ enum watertypes {FRESHWATER, BRACKISHWATER, EN13319WATER, SALTWATER, DC_WATERTYP
|
|||
QString distance_string(int distanceInMeters);
|
||||
bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_text, bool *parsed_out = 0);
|
||||
QString get_gas_string(struct gasmix gas);
|
||||
QStringList get_dive_gas_list(const struct dive *d);
|
||||
QString get_dive_gas(const struct dive *d, int dcNr, int cylinderId);
|
||||
std::vector<std::pair<int, QString>> get_dive_gas_list(const struct dive *d, int dcNr, bool showOnlyAppropriate);
|
||||
QStringList stringToList(const QString &s);
|
||||
void read_hashes();
|
||||
void write_hashes();
|
||||
|
|
|
@ -14,6 +14,7 @@ qPrefTechnicalDetails *qPrefTechnicalDetails::instance()
|
|||
|
||||
void qPrefTechnicalDetails::loadSync(bool doSync)
|
||||
{
|
||||
disk_allowOcGasAsDiluent(doSync);
|
||||
disk_calcalltissues(doSync);
|
||||
disk_calcceiling(doSync);
|
||||
disk_calcceiling3m(doSync);
|
||||
|
@ -100,6 +101,8 @@ void qPrefTechnicalDetails::disk_gflow(bool doSync)
|
|||
}
|
||||
}
|
||||
|
||||
HANDLE_PREFERENCE_BOOL(TechnicalDetails, "allowOcGasAsDiluent", allowOcGasAsDiluent);
|
||||
|
||||
HANDLE_PREFERENCE_BOOL(TechnicalDetails, "gf_low_at_maxdepth", gf_low_at_maxdepth);
|
||||
|
||||
HANDLE_PREFERENCE_BOOL(TechnicalDetails, "InfoBox", infobox);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
class qPrefTechnicalDetails : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool allowOcGasAsDiluent READ allowOcGasAsDiluent WRITE set_allowOcGasAsDiluent NOTIFY allowOcGasAsDiluentChanged)
|
||||
Q_PROPERTY(bool calcalltissues READ calcalltissues WRITE set_calcalltissues NOTIFY calcalltissuesChanged)
|
||||
Q_PROPERTY(bool calcceiling READ calcceiling WRITE set_calcceiling NOTIFY calcceilingChanged)
|
||||
Q_PROPERTY(bool calcceiling3m READ calcceiling3m WRITE set_calcceiling3m NOTIFY calcceiling3mChanged)
|
||||
|
@ -44,6 +45,7 @@ public:
|
|||
static void sync() { loadSync(true); }
|
||||
|
||||
public:
|
||||
static bool allowOcGasAsDiluent() { return prefs.allowOcGasAsDiluent; }
|
||||
static bool calcalltissues() { return prefs.calcalltissues; }
|
||||
static bool calcceiling() { return prefs.calcceiling; }
|
||||
static bool calcceiling3m() { return prefs.calcceiling3m; }
|
||||
|
@ -73,6 +75,7 @@ public:
|
|||
static bool infobox() { return prefs.infobox; }
|
||||
|
||||
public slots:
|
||||
static void set_allowOcGasAsDiluent(bool value);
|
||||
static void set_calcalltissues(bool value);
|
||||
static void set_calcceiling(bool value);
|
||||
static void set_calcceiling3m(bool value);
|
||||
|
@ -102,6 +105,7 @@ public slots:
|
|||
static void set_infobox(bool value);
|
||||
|
||||
signals:
|
||||
void allowOcGasAsDiluentChanged(bool value);
|
||||
void calcalltissuesChanged(bool value);
|
||||
void calcceilingChanged(bool value);
|
||||
void calcceiling3mChanged(bool value);
|
||||
|
@ -133,6 +137,7 @@ signals:
|
|||
private:
|
||||
qPrefTechnicalDetails() {}
|
||||
|
||||
static void disk_allowOcGasAsDiluent(bool doSync);
|
||||
static void disk_calcalltissues(bool doSync);
|
||||
static void disk_calcceiling(bool doSync);
|
||||
static void disk_calcceiling3m(bool doSync);
|
||||
|
|
|
@ -23,27 +23,32 @@
|
|||
#include <QBuffer>
|
||||
#endif
|
||||
|
||||
DivePlannerWidget::DivePlannerWidget(dive &planned_dive, int dcNr, PlannerWidgets *parent)
|
||||
DivePlannerWidget::DivePlannerWidget(const dive &planned_dive, int &dcNr, PlannerWidgets *parent)
|
||||
{
|
||||
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
|
||||
CylindersModel *cylinders = DivePlannerPointsModel::instance()->cylindersModel();
|
||||
|
||||
ui.setupUi(this);
|
||||
|
||||
// should be the same order as in dive_comp_type!
|
||||
QStringList divemodes = QStringList();
|
||||
for (int i = 0; i < FREEDIVE; i++)
|
||||
divemodes.append(gettextFromC::tr(divemode_text_ui[i]));
|
||||
ui.divemode->insertItems(0, divemodes);
|
||||
|
||||
ui.tableWidget->setTitle(tr("Dive planner points"));
|
||||
ui.tableWidget->setBtnToolTip(tr("Add dive data point"));
|
||||
ui.tableWidget->setModel(plannerModel);
|
||||
connect(ui.tableWidget, &TableView::itemClicked, plannerModel, &DivePlannerPointsModel::remove);
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new AirTypesDelegate(planned_dive, this));
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DIVEMODE, new DiveTypesDelegate(this));
|
||||
connect(ui.tableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addDefaultStop);
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::GAS, new GasTypesDelegate(planned_dive, dcNr, this));
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DIVEMODE, new DiveTypesDelegate(planned_dive, dcNr, this));
|
||||
|
||||
ui.cylinderTableWidget->setTitle(tr("Available gases"));
|
||||
ui.cylinderTableWidget->setBtnToolTip(tr("Add cylinder"));
|
||||
ui.cylinderTableWidget->setModel(cylinders);
|
||||
connect(ui.cylinderTableWidget, &TableView::itemClicked, cylinders, &CylindersModel::remove);
|
||||
ui.waterType->setItemData(0, FRESHWATER_SALINITY);
|
||||
ui.waterType->setItemData(1, SEAWATER_SALINITY);
|
||||
ui.waterType->setItemData(2, EN13319_SALINITY);
|
||||
waterTypeUpdateTexts();
|
||||
|
||||
QTableView *view = ui.cylinderTableWidget->view();
|
||||
connect(ui.cylinderTableWidget, &TableView::itemClicked, cylinders, &CylindersModel::remove);
|
||||
view->setColumnHidden(CylindersModel::START, true);
|
||||
view->setColumnHidden(CylindersModel::END, true);
|
||||
view->setColumnHidden(CylindersModel::DEPTH, false);
|
||||
|
@ -52,18 +57,22 @@ DivePlannerWidget::DivePlannerWidget(dive &planned_dive, int dcNr, PlannerWidget
|
|||
view->setColumnHidden(CylindersModel::SENSORS, true);
|
||||
view->setItemDelegateForColumn(CylindersModel::TYPE, new TankInfoDelegate(this));
|
||||
auto tankUseDelegate = new TankUseDelegate(this);
|
||||
tankUseDelegate->setCurrentDC(planned_dive.get_dc(dcNr));
|
||||
tankUseDelegate->setDiveDc(planned_dive, dcNr);
|
||||
view->setItemDelegateForColumn(CylindersModel::USE, tankUseDelegate);
|
||||
connect(ui.cylinderTableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addCylinder_clicked);
|
||||
connect(ui.tableWidget, &TableView::addButtonClicked, plannerModel, &DivePlannerPointsModel::addDefaultStop);
|
||||
connect(cylinders, &CylindersModel::dataChanged, plannerModel, &DivePlannerPointsModel::emitDataChanged);
|
||||
connect(cylinders, &CylindersModel::dataChanged, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
|
||||
connect(cylinders, &CylindersModel::rowsInserted, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
|
||||
connect(cylinders, &CylindersModel::rowsRemoved, plannerModel, &DivePlannerPointsModel::cylinderModelEdited);
|
||||
|
||||
ui.tableWidget->setBtnToolTip(tr("Add dive data point"));
|
||||
ui.waterType->setItemData(0, FRESHWATER_SALINITY);
|
||||
ui.waterType->setItemData(1, SEAWATER_SALINITY);
|
||||
ui.waterType->setItemData(2, EN13319_SALINITY);
|
||||
waterTypeUpdateTexts();
|
||||
|
||||
connect(ui.startTime, &QDateEdit::timeChanged, plannerModel, &DivePlannerPointsModel::setStartTime);
|
||||
connect(ui.dateEdit, &QDateEdit::dateChanged, plannerModel, &DivePlannerPointsModel::setStartDate);
|
||||
connect(ui.divemode, QOverload<int>::of(&QComboBox::currentIndexChanged), parent, &PlannerWidgets::setDiveMode);
|
||||
connect(ui.ATMPressure, QOverload<int>::of(&QSpinBox::valueChanged), this, &DivePlannerWidget::atmPressureChanged);
|
||||
connect(ui.atmHeight, QOverload<int>::of(&QSpinBox::valueChanged), this, &DivePlannerWidget::heightChanged);
|
||||
connect(ui.waterType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DivePlannerWidget::waterTypeChanged);
|
||||
|
@ -77,14 +86,14 @@ DivePlannerWidget::DivePlannerWidget(dive &planned_dive, int dcNr, PlannerWidget
|
|||
QShortcut *closeKey = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||
connect(closeKey, &QShortcut::activated, plannerModel, &DivePlannerPointsModel::cancelPlan);
|
||||
|
||||
// This makes shure the spinbox gets a setMinimum(0) on it so we can't have negative time or depth.
|
||||
// This makes sure the spinbox gets a setMinimum(0) on it so we can't have negative time or depth.
|
||||
// Limit segments to a depth of 1000 m/3300 ft and a duration of 100 h. Setting the limit for
|
||||
// the depth will be done in settingChanged() since this depends on the chosen units.
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::RUNTIME, new SpinBoxDelegate(0, INT_MAX, 1, this));
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::DURATION, new SpinBoxDelegate(0, 6000, 1, this));
|
||||
ui.tableWidget->view()->setItemDelegateForColumn(DivePlannerPointsModel::CCSETPOINT, new DoubleSpinBoxDelegate(0, 2, 0.01, this));
|
||||
|
||||
connect(&diveListNotifier, &DiveListNotifier::settingsChanged, this, &DivePlannerWidget::settingsChanged);
|
||||
connect(&diveListNotifier, &DiveListNotifier::settingsChanged, parent, &PlannerWidgets::settingsChanged);
|
||||
|
||||
/* set defaults. */
|
||||
ui.ATMPressure->setValue(1013);
|
||||
|
@ -116,11 +125,6 @@ void DivePlannerWidget::setSurfacePressure(int surface_pressure)
|
|||
ui.ATMPressure->setValue(surface_pressure);
|
||||
}
|
||||
|
||||
void PlannerSettingsWidget::setDiveMode(int mode)
|
||||
{
|
||||
ui.rebreathermode->setCurrentIndex(mode);
|
||||
}
|
||||
|
||||
void DivePlannerWidget::setSalinity(int salinity)
|
||||
{
|
||||
bool mapped = false;
|
||||
|
@ -212,7 +216,23 @@ void DivePlannerWidget::customSalinityChanged(double density)
|
|||
}
|
||||
}
|
||||
|
||||
void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t rebreathermode)
|
||||
void DivePlannerWidget::setDiveMode(int mode)
|
||||
{
|
||||
ui.divemode->setCurrentIndex(mode);
|
||||
}
|
||||
|
||||
void DivePlannerWidget::setColumnVisibility(int mode)
|
||||
{
|
||||
ui.tableWidget->view()->setColumnHidden(DivePlannerPointsModel::CCSETPOINT, mode != CCR);
|
||||
ui.tableWidget->view()->setColumnHidden(DivePlannerPointsModel::DIVEMODE, mode == OC || (mode == CCR && !prefs.allowOcGasAsDiluent));
|
||||
|
||||
// This is needed as Qt sets the column width to 0 when hiding a column
|
||||
ui.tableWidget->view()->setVisible(false); // This will cause the resize to include rows outside the current viewport
|
||||
ui.tableWidget->view()->resizeColumnsToContents();
|
||||
ui.tableWidget->view()->setVisible(true);
|
||||
}
|
||||
|
||||
void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t divemode)
|
||||
{
|
||||
if (mode == RECREATIONAL) {
|
||||
ui.label_gflow->setDisabled(false);
|
||||
|
@ -265,7 +285,7 @@ void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t rebreatherm
|
|||
ui.backgasBreaks->setChecked(false);
|
||||
ui.backgasBreaks->blockSignals(false);
|
||||
}
|
||||
ui.bailout->setDisabled(!(rebreathermode == CCR || rebreathermode == PSCR));
|
||||
ui.bailout->setDisabled(!IS_REBREATHER_MODE(divemode));
|
||||
ui.bottompo2->setDisabled(false);
|
||||
ui.decopo2->setDisabled(false);
|
||||
ui.safetystop->setDisabled(true);
|
||||
|
@ -277,7 +297,7 @@ void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t rebreatherm
|
|||
ui.min_switch_duration->setDisabled(false);
|
||||
ui.surface_segment->setDisabled(false);
|
||||
ui.label_min_switch_duration->setDisabled(false);
|
||||
ui.sacfactor->setDisabled(false);
|
||||
ui.sacfactor->setDisabled(IS_REBREATHER_MODE(divemode));
|
||||
ui.problemsolvingtime->setDisabled(false);
|
||||
ui.sacfactor->setValue(PlannerShared::sacfactor());
|
||||
ui.problemsolvingtime->setValue(prefs.problemsolvingtime);
|
||||
|
@ -299,7 +319,7 @@ void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t rebreatherm
|
|||
ui.backgasBreaks->setChecked(false);
|
||||
ui.backgasBreaks->blockSignals(false);
|
||||
}
|
||||
ui.bailout->setDisabled(!(rebreathermode == CCR || rebreathermode == PSCR));
|
||||
ui.bailout->setDisabled(!IS_REBREATHER_MODE(divemode));
|
||||
ui.bottompo2->setDisabled(false);
|
||||
ui.decopo2->setDisabled(false);
|
||||
ui.safetystop->setDisabled(true);
|
||||
|
@ -311,7 +331,7 @@ void PlannerSettingsWidget::disableDecoElements(int mode, divemode_t rebreatherm
|
|||
ui.min_switch_duration->setDisabled(false);
|
||||
ui.surface_segment->setDisabled(false);
|
||||
ui.label_min_switch_duration->setDisabled(false);
|
||||
ui.sacfactor->setDisabled(false);
|
||||
ui.sacfactor->setDisabled(IS_REBREATHER_MODE(divemode));
|
||||
ui.problemsolvingtime->setDisabled(false);
|
||||
ui.sacfactor->setValue(PlannerShared::sacfactor());
|
||||
ui.problemsolvingtime->setValue(prefs.problemsolvingtime);
|
||||
|
@ -359,7 +379,6 @@ PlannerSettingsWidget::PlannerSettingsWidget(PlannerWidgets *parent)
|
|||
ui.decopo2->setValue(PlannerShared::decopo2());
|
||||
ui.backgasBreaks->setChecked(prefs.doo2breaks);
|
||||
PlannerShared::set_dobailout(false);
|
||||
setBailoutVisibility(false);
|
||||
ui.o2narcotic->setChecked(prefs.o2narcotic);
|
||||
ui.drop_stone_mode->setChecked(prefs.drop_stone_mode);
|
||||
ui.switch_at_req_stop->setChecked(prefs.switch_at_req_stop);
|
||||
|
@ -370,12 +389,6 @@ PlannerSettingsWidget::PlannerSettingsWidget(PlannerWidgets *parent)
|
|||
ui.vpmb_deco->setChecked(prefs.planner_deco_mode == VPMB);
|
||||
disableDecoElements((int) prefs.planner_deco_mode, OC);
|
||||
|
||||
// should be the same order as in dive_comp_type!
|
||||
QStringList rebreather_modes = QStringList();
|
||||
for (int i = 0; i < FREEDIVE; i++)
|
||||
rebreather_modes.append(gettextFromC::tr(divemode_text_ui[i]));
|
||||
ui.rebreathermode->insertItems(0, rebreather_modes);
|
||||
|
||||
connect(ui.recreational_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(RECREATIONAL); });
|
||||
connect(ui.buehlmann_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(BUEHLMANN); });
|
||||
connect(ui.vpmb_deco, &QAbstractButton::clicked, [] { PlannerShared::set_planner_deco_mode(VPMB); });
|
||||
|
@ -404,12 +417,10 @@ PlannerSettingsWidget::PlannerSettingsWidget(PlannerWidgets *parent)
|
|||
connect(ui.switch_at_req_stop, &QAbstractButton::toggled, plannerModel, &DivePlannerPointsModel::setSwitchAtReqStop);
|
||||
connect(ui.min_switch_duration, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_min_switch_duration);
|
||||
connect(ui.surface_segment, QOverload<int>::of(&QSpinBox::valueChanged), &PlannerShared::set_surface_segment);
|
||||
connect(ui.rebreathermode, QOverload<int>::of(&QComboBox::currentIndexChanged), plannerModel, &DivePlannerPointsModel::setRebreatherMode);
|
||||
connect(ui.rebreathermode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PlannerSettingsWidget::setBailoutVisibility);
|
||||
|
||||
connect(ui.recreational_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(RECREATIONAL, parent->getRebreatherMode()); });
|
||||
connect(ui.buehlmann_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(BUEHLMANN, parent->getRebreatherMode()); });
|
||||
connect(ui.vpmb_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(VPMB, parent->getRebreatherMode()); });
|
||||
connect(ui.recreational_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(RECREATIONAL, parent->getDiveMode()); });
|
||||
connect(ui.buehlmann_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(BUEHLMANN, parent->getDiveMode()); });
|
||||
connect(ui.vpmb_deco, &QAbstractButton::clicked, [this, parent] { disableDecoElements(VPMB, parent->getDiveMode()); });
|
||||
|
||||
connect(ui.sacfactor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), &PlannerShared::set_sacfactor);
|
||||
connect(ui.problemsolvingtime, QOverload<int>::of(&QSpinBox::valueChanged), plannerModel, &DivePlannerPointsModel::setProblemSolvingTime);
|
||||
|
@ -519,8 +530,9 @@ void PlannerSettingsWidget::setBackgasBreaks(bool dobreaks)
|
|||
|
||||
void PlannerSettingsWidget::setBailoutVisibility(int mode)
|
||||
{
|
||||
ui.bailout->setDisabled(!(mode == CCR || mode == PSCR));
|
||||
ui.sacFactor->setDisabled(mode == CCR);
|
||||
bool isRebreatherMode = IS_REBREATHER_MODE(mode);
|
||||
ui.bailout->setDisabled(!isRebreatherMode);
|
||||
ui.sacfactor->setDisabled(isRebreatherMode);
|
||||
}
|
||||
|
||||
PlannerDetails::PlannerDetails(QWidget *parent) : QWidget(parent)
|
||||
|
@ -561,7 +573,7 @@ int PlannerWidgets::getDcNr()
|
|||
return dcNr;
|
||||
}
|
||||
|
||||
divemode_t PlannerWidgets::getRebreatherMode() const
|
||||
divemode_t PlannerWidgets::getDiveMode() const
|
||||
{
|
||||
return planned_dive->get_dc(dcNr)->divemode;
|
||||
}
|
||||
|
@ -575,13 +587,14 @@ void PlannerWidgets::preparePlanDive(const dive *currentDive, int currentDcNr)
|
|||
|
||||
// plan the dive in the same mode as the currently selected one
|
||||
if (currentDive) {
|
||||
plannerSettingsWidget.setDiveMode(currentDive->get_dc(currentDcNr)->divemode);
|
||||
plannerSettingsWidget.setBailoutVisibility(currentDive->get_dc(currentDcNr)->divemode);
|
||||
planned_dive->get_dc(dcNr)->divemode = currentDive->get_dc(currentDcNr)->divemode;
|
||||
if (currentDive->salinity)
|
||||
plannerWidget.setSalinity(currentDive->salinity);
|
||||
else // No salinity means salt water
|
||||
plannerWidget.setSalinity(SEAWATER_SALINITY);
|
||||
}
|
||||
|
||||
setDiveMode(getDiveMode());
|
||||
}
|
||||
|
||||
void PlannerWidgets::planDive()
|
||||
|
@ -589,6 +602,7 @@ void PlannerWidgets::planDive()
|
|||
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
|
||||
|
||||
plannerWidget.setReplanButton(false);
|
||||
|
||||
plannerWidget.setupStartTime(timestampToDateTime(planned_dive->when)); // This will reload the profile!
|
||||
}
|
||||
|
||||
|
@ -596,6 +610,8 @@ void PlannerWidgets::prepareReplanDive(const dive *currentDive, int currentDcNr)
|
|||
{
|
||||
copy_dive(currentDive, planned_dive.get());
|
||||
dcNr = currentDcNr;
|
||||
|
||||
setDiveMode(getDiveMode());
|
||||
}
|
||||
|
||||
void PlannerWidgets::replanDive()
|
||||
|
@ -609,6 +625,7 @@ void PlannerWidgets::replanDive()
|
|||
plannerWidget.setSurfacePressure(planned_dive->surface_pressure.mbar);
|
||||
if (planned_dive->salinity)
|
||||
plannerWidget.setSalinity(planned_dive->salinity);
|
||||
|
||||
reset_cylinders(planned_dive.get(), true);
|
||||
DivePlannerPointsModel::instance()->cylindersModel()->updateDive(planned_dive.get(), dcNr);
|
||||
}
|
||||
|
@ -657,3 +674,16 @@ void PlannerWidgets::printDecoPlan()
|
|||
plannerDetails.divePlanOutput()->setHtml(origPlan); // restore original plan
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlannerWidgets::setDiveMode(int mode)
|
||||
{
|
||||
DivePlannerPointsModel::instance()->setDiveMode(mode);
|
||||
plannerWidget.setColumnVisibility(mode);
|
||||
plannerSettingsWidget.setBailoutVisibility(mode);
|
||||
}
|
||||
|
||||
void PlannerWidgets::settingsChanged()
|
||||
{
|
||||
plannerWidget.settingsChanged();
|
||||
setDiveMode(getDiveMode());
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ struct dive;
|
|||
class DivePlannerWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DivePlannerWidget(dive &planned_dive, int dcNr, PlannerWidgets *parent);
|
||||
explicit DivePlannerWidget(const dive &planned_dive, int &dcNr, PlannerWidgets *parent);
|
||||
~DivePlannerWidget();
|
||||
void setReplanButton(bool replan);
|
||||
void setColumnVisibility(int mode);
|
||||
void setDiveMode(int mode);
|
||||
public
|
||||
slots:
|
||||
void setupStartTime(QDateTime startTime);
|
||||
|
@ -48,9 +50,8 @@ public
|
|||
slots:
|
||||
void settingsChanged();
|
||||
void setBackgasBreaks(bool dobreaks);
|
||||
void disableDecoElements(int mode, divemode_t rebreathermode);
|
||||
void disableDecoElements(int mode, divemode_t divemode);
|
||||
void disableBackgasBreaks(bool enabled);
|
||||
void setDiveMode(int mode);
|
||||
void setBailoutVisibility(int mode);
|
||||
|
||||
private:
|
||||
|
@ -86,10 +87,12 @@ public:
|
|||
void replanDive();
|
||||
struct dive *getDive() const;
|
||||
int getDcNr();
|
||||
divemode_t getRebreatherMode() const;
|
||||
divemode_t getDiveMode() const;
|
||||
void settingsChanged();
|
||||
public
|
||||
slots:
|
||||
void printDecoPlan();
|
||||
void setDiveMode(int mode);
|
||||
private:
|
||||
std::unique_ptr<dive> planned_dive;
|
||||
int dcNr;
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
|
@ -98,7 +98,30 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="2">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dive mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="divemode">
|
||||
<property name="currentText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxVisibleItems">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -112,20 +135,20 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Altitude</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>ATM pressure</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Altitude</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Water type</string>
|
||||
|
@ -133,6 +156,25 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QSpinBox" name="ATMPressure">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>689</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="atmHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -154,26 +196,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="ATMPressure">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>mbar</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>689</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<item row="3" column="3">
|
||||
<widget class="QComboBox" name="waterType">
|
||||
<item>
|
||||
<property name="text">
|
||||
|
@ -197,7 +220,7 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<item row="3" column="4">
|
||||
<widget class="QDoubleSpinBox" name="customSalinity">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
|
@ -237,7 +260,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="4">
|
||||
<item row="4" column="0" colspan="5">
|
||||
<widget class="TableView" name="cylinderTableWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
|
@ -253,7 +276,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<item row="5" column="0" colspan="5">
|
||||
<widget class="TableView" name="tableWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
|
@ -285,6 +308,7 @@
|
|||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>startTime</tabstop>
|
||||
<tabstop>divemode</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
</tabstops>
|
||||
|
|
|
@ -688,6 +688,7 @@ void MainWindow::on_actionDivePlanner_triggered()
|
|||
setApplicationState(ApplicationState::PlanDive);
|
||||
|
||||
disableShortcuts(true);
|
||||
profile->exitEditMode();
|
||||
plannerWidgets->preparePlanDive(current_dive, profile->dc);
|
||||
profile->setPlanState(plannerWidgets->getDive(), plannerWidgets->getDcNr());
|
||||
plannerWidgets->planDive();
|
||||
|
|
|
@ -246,24 +246,32 @@ void TankInfoDelegate::editorClosed(QWidget *, QAbstractItemDelegate::EndEditHin
|
|||
mymodel->setData(IDX(CylindersModel::TYPE), currCombo.activeText, CylindersModel::COMMIT_ROLE);
|
||||
}
|
||||
|
||||
TankUseDelegate::TankUseDelegate(QObject *parent) : QStyledItemDelegate(parent), currentdc(nullptr)
|
||||
TankUseDelegate::TankUseDelegate(QObject *parent) : QStyledItemDelegate(parent), currentDive(nullptr), currentDcNr(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TankUseDelegate::setCurrentDC(divecomputer *dc)
|
||||
void TankUseDelegate::setDiveDc(const dive &d, int &dcNr)
|
||||
{
|
||||
currentdc = dc;
|
||||
currentDive = &d;
|
||||
currentDcNr = &dcNr;
|
||||
}
|
||||
|
||||
QWidget *TankUseDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const
|
||||
{
|
||||
QComboBox *comboBox = new QComboBox(parent);
|
||||
if (!currentdc)
|
||||
const divecomputer *dc = currentDive->get_dc(*currentDcNr);
|
||||
if (!dc)
|
||||
return comboBox;
|
||||
bool isCcrDive = currentdc->divemode == CCR;
|
||||
bool isCcrDive = dc->divemode == CCR;
|
||||
bool isFreeDive = dc->divemode == FREEDIVE;
|
||||
for (int i = 0; i < NUM_GAS_USE; i++) {
|
||||
if (isCcrDive || (i != DILUENT && i != OXYGEN))
|
||||
comboBox->addItem(gettextFromC::tr(cylinderuse_text[i]));
|
||||
if (isFreeDive && i != NOT_USED)
|
||||
continue;
|
||||
|
||||
if (!isCcrDive && (i == DILUENT || i == OXYGEN))
|
||||
continue;
|
||||
|
||||
comboBox->addItem(gettextFromC::tr(cylinderuse_text[i]));
|
||||
}
|
||||
return comboBox;
|
||||
}
|
||||
|
@ -350,21 +358,20 @@ WSInfoDelegate::WSInfoDelegate(QObject *parent) : ComboBoxDelegate(&createWSInfo
|
|||
{
|
||||
}
|
||||
|
||||
void AirTypesDelegate::editorClosed(QWidget *, QAbstractItemDelegate::EndEditHint)
|
||||
void GasTypesDelegate::editorClosed(QWidget *, QAbstractItemDelegate::EndEditHint)
|
||||
{
|
||||
}
|
||||
|
||||
void AirTypesDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
void GasTypesDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
QComboBox *combo = qobject_cast<QComboBox *>(editor);
|
||||
model->setData(index, QVariant(combo->currentIndex()));
|
||||
model->setData(index, combo->currentData(Qt::UserRole));
|
||||
}
|
||||
|
||||
AirTypesDelegate::AirTypesDelegate(const dive &d, QObject *parent) :
|
||||
ComboBoxDelegate([&d] (QWidget *parent) { return new GasSelectionModel(d, parent); },
|
||||
parent, false)
|
||||
GasTypesDelegate::GasTypesDelegate(const dive &d, int &dcNr, QObject *parent) :
|
||||
ComboBoxDelegate([&d, &dcNr] (QWidget *parent) { return new GasSelectionModel(d, dcNr, parent); }, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -377,15 +384,11 @@ void DiveTypesDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
|||
if (!index.isValid())
|
||||
return;
|
||||
QComboBox *combo = qobject_cast<QComboBox *>(editor);
|
||||
model->setData(index, QVariant(combo->currentIndex()));
|
||||
model->setData(index, combo->currentData(Qt::UserRole));
|
||||
}
|
||||
|
||||
static QAbstractItemModel *createDiveTypeSelectionModel(QWidget *parent)
|
||||
{
|
||||
return new DiveTypeSelectionModel(parent);
|
||||
}
|
||||
|
||||
DiveTypesDelegate::DiveTypesDelegate(QObject *parent) : ComboBoxDelegate(&createDiveTypeSelectionModel, parent, false)
|
||||
DiveTypesDelegate::DiveTypesDelegate(const dive &d, int &dcNr, QObject *parent) :
|
||||
ComboBoxDelegate([&d, &dcNr] (QWidget *parent) { return new DiveTypeSelectionModel(d, dcNr, parent); }, parent, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -75,12 +75,13 @@ class TankUseDelegate : public QStyledItemDelegate {
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit TankUseDelegate(QObject *parent = 0);
|
||||
void setCurrentDC(divecomputer *dc);
|
||||
void setDiveDc(const dive &d, int &dcNr);
|
||||
private:
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
divecomputer *currentdc;
|
||||
const dive *currentDive;
|
||||
int *currentDcNr;
|
||||
};
|
||||
|
||||
class SensorDelegate : public QStyledItemDelegate {
|
||||
|
@ -103,10 +104,10 @@ private:
|
|||
void editorClosed(QWidget *widget, QAbstractItemDelegate::EndEditHint hint) override;
|
||||
};
|
||||
|
||||
class AirTypesDelegate : public ComboBoxDelegate {
|
||||
class GasTypesDelegate : public ComboBoxDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AirTypesDelegate(const dive &d, QObject *parent = 0);
|
||||
explicit GasTypesDelegate(const dive &d, int &dcNr, QObject *parent = 0);
|
||||
private:
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
void editorClosed(QWidget *widget, QAbstractItemDelegate::EndEditHint hint) override;
|
||||
|
@ -115,7 +116,7 @@ private:
|
|||
class DiveTypesDelegate : public ComboBoxDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DiveTypesDelegate(QObject *parent = 0);
|
||||
explicit DiveTypesDelegate(const dive &d, int &dcNr, QObject *parent = 0);
|
||||
private:
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
|
||||
void editorClosed(QWidget *widget, QAbstractItemDelegate::EndEditHint hint) override;
|
||||
|
|
|
@ -255,7 +255,7 @@
|
|||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="4" column="2">
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="reserve_gas">
|
||||
<property name="suffix">
|
||||
<string>bar</string>
|
||||
|
@ -274,7 +274,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="5" column="1">
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -287,7 +287,7 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="22" column="1" colspan="2">
|
||||
<item row="21" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="switch_at_req_stop">
|
||||
<property name="toolTip">
|
||||
<string>Postpone gas change if a stop is not required</string>
|
||||
|
@ -297,14 +297,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1" colspan="2">
|
||||
<item row="17" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="lastStop">
|
||||
<property name="text">
|
||||
<string>Last stop at 6m</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="2">
|
||||
<item row="14" column="2">
|
||||
<widget class="QSpinBox" name="vpmb_conservatism">
|
||||
<property name="prefix">
|
||||
<string>+</string>
|
||||
|
@ -314,7 +314,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="2">
|
||||
<item row="11" column="2">
|
||||
<widget class="QSpinBox" name="gfhigh">
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
|
@ -327,7 +327,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="23" column="2">
|
||||
<item row="22" column="2">
|
||||
<widget class="QSpinBox" name="min_switch_duration">
|
||||
<property name="suffix">
|
||||
<string>min</string>
|
||||
|
@ -346,14 +346,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="1" colspan="2">
|
||||
<item row="19" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="backgasBreaks">
|
||||
<property name="text">
|
||||
<string>Plan backgas breaks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="25" column="1">
|
||||
<item row="24" column="1">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -366,21 +366,21 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="23" column="1">
|
||||
<item row="22" column="1">
|
||||
<widget class="QLabel" name="label_min_switch_duration">
|
||||
<property name="text">
|
||||
<string>Min. switch duration O₂% below 100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1" colspan="2">
|
||||
<item row="16" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="drop_stone_mode">
|
||||
<property name="text">
|
||||
<string>Drop to first depth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="2">
|
||||
<item row="10" column="2">
|
||||
<widget class="QSpinBox" name="gflow">
|
||||
<property name="suffix">
|
||||
<string>%</string>
|
||||
|
@ -393,7 +393,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QLabel" name="label_gflow">
|
||||
<property name="text">
|
||||
<string>GFLow</string>
|
||||
|
@ -403,7 +403,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QLabel" name="label_gfhigh">
|
||||
<property name="text">
|
||||
<string>GFHigh</string>
|
||||
|
@ -413,7 +413,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="recreational_deco">
|
||||
<property name="toolTip">
|
||||
<string>Maximize bottom time allowed by gas and no decompression limits</string>
|
||||
|
@ -423,7 +423,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QLabel" name="label_vpmb_conservatism">
|
||||
<property name="text">
|
||||
<string>Conservatism level</string>
|
||||
|
@ -440,7 +440,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" alignment="Qt::AlignHCenter">
|
||||
<item row="4" column="1" alignment="Qt::AlignHCenter">
|
||||
<widget class="QCheckBox" name="safetystop">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
|
@ -453,7 +453,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="12" column="1">
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -466,7 +466,7 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="15" column="1">
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -479,24 +479,7 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QComboBox" name="rebreathermode">
|
||||
<property name="currentText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="maxVisibleItems">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_dive_type">
|
||||
<property name="text">
|
||||
<string>Dive mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="buehlmann_deco">
|
||||
<property name="text">
|
||||
<string>Bühlmann deco</string>
|
||||
|
@ -506,7 +489,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_reserve_gas">
|
||||
<property name="text">
|
||||
<string>Reserve gas</string>
|
||||
|
@ -516,21 +499,21 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="bailout">
|
||||
<property name="text">
|
||||
<string>Bailout: Deco on OC</string>
|
||||
<string>Rebreather: Bailout / Deco on OC</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="24" column="1">
|
||||
<item row="23" column="1">
|
||||
<widget class="QLabel" name="label_surface_segment">
|
||||
<property name="text">
|
||||
<string>Surface segment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="24" column="2">
|
||||
<item row="23" column="2">
|
||||
<widget class="QSpinBox" name="surface_segment">
|
||||
<property name="suffix">
|
||||
<string>min</string>
|
||||
|
@ -777,7 +760,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="sacFactor">
|
||||
<widget class="QLabel" name="label_sacfactor">
|
||||
<property name="text">
|
||||
<string>SAC factor</string>
|
||||
</property>
|
||||
|
@ -857,7 +840,7 @@
|
|||
<tabstop>ascRateStops</tabstop>
|
||||
<tabstop>ascRateLast6m</tabstop>
|
||||
<tabstop>descRate</tabstop>
|
||||
<tabstop>rebreathermode</tabstop>
|
||||
<tabstop>divemode</tabstop>
|
||||
<tabstop>recreational_deco</tabstop>
|
||||
<tabstop>reserve_gas</tabstop>
|
||||
<tabstop>safetystop</tabstop>
|
||||
|
|
|
@ -50,6 +50,7 @@ void PreferencesGraph::refreshSettings()
|
|||
ui->pscrfactor->setValue(lrint(1000.0 / prefs.pscr_ratio));
|
||||
|
||||
ui->show_icd->setChecked(prefs.show_icd);
|
||||
ui->allowOcGasAsDiluent->setChecked(prefs.allowOcGasAsDiluent);
|
||||
}
|
||||
|
||||
void PreferencesGraph::syncSettings()
|
||||
|
@ -75,6 +76,7 @@ void PreferencesGraph::syncSettings()
|
|||
qPrefTechnicalDetails::set_show_scr_ocpo2(ui->show_scr_ocpo2->isChecked());
|
||||
qPrefTechnicalDetails::set_show_icd(ui->show_icd->isChecked());
|
||||
qPrefTechnicalDetails::set_display_deco_mode(ui->vpmb->isChecked() ? VPMB : BUEHLMANN);
|
||||
qPrefTechnicalDetails::set_allowOcGasAsDiluent(ui->allowOcGasAsDiluent->isChecked());
|
||||
}
|
||||
|
||||
static const char *danger_gf(int gf)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<property name="title">
|
||||
<string>Gas pressure display setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QGridLayout" name="gridLayout_1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="enabled">
|
||||
|
@ -125,21 +125,30 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Rebreather setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>CCR options:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_27">
|
||||
<property name="text">
|
||||
<string>Dive planner default setpoint</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<item row="0" column="2">
|
||||
<widget class="QDoubleSpinBox" name="defaultSetpoint">
|
||||
<property name="suffix">
|
||||
<string>bar</string>
|
||||
|
@ -155,38 +164,35 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="show_ccr_sensors">
|
||||
<property name="text">
|
||||
<string>Show O₂ sensor values when viewing pO₂</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="show_ccr_setpoint">
|
||||
<property name="text">
|
||||
<string>Show CCR setpoints when viewing pO₂</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="pSCR">
|
||||
<property name="text">
|
||||
<string>pSCR options:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="MetabolicRate">
|
||||
<property name="text">
|
||||
<string>pSCR metabolic rate O₂</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<item row="3" column="2">
|
||||
<widget class="QDoubleSpinBox" name="psro2rate">
|
||||
<property name="suffix">
|
||||
<string>ℓ/min</string>
|
||||
|
@ -196,7 +202,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="3">
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>Dilution ratio</string>
|
||||
|
@ -206,7 +212,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="4">
|
||||
<item row="3" column="4">
|
||||
<widget class="QSpinBox" name="pscrfactor">
|
||||
<property name="suffix">
|
||||
<string/>
|
||||
|
@ -216,29 +222,45 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="show_scr_ocpo2">
|
||||
<property name="text">
|
||||
<string>Show equivalent OC pO₂ with pSCR pO₂</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QCheckBox" name="show_icd">
|
||||
<property name="text">
|
||||
<string>Show warnings for isobaric counterdiffusion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Planner setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="show_icd">
|
||||
<property name="text">
|
||||
<string>Show warnings for isobaric counterdiffusion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="allowOcGasAsDiluent">
|
||||
<property name="text">
|
||||
<string>Allow open circuit gas to be used as diluent for CCR</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_7">
|
||||
<property name="title">
|
||||
<string>Ceiling display setup</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_GFhigh">
|
||||
<property name="text">
|
||||
|
|
|
@ -306,7 +306,6 @@ void ProfileWidget::cylindersChanged(struct dive *changed, int pos)
|
|||
|
||||
void ProfileWidget::setPlanState(const struct dive *d, int dcNr)
|
||||
{
|
||||
exitEditMode();
|
||||
dc = dcNr;
|
||||
view->setPlanState(d, dcNr);
|
||||
setDive(d, dcNr);
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
void setEnabledToolbar(bool enabled);
|
||||
void nextDC();
|
||||
void prevDC();
|
||||
void exitEditMode();
|
||||
dive *d;
|
||||
int dc;
|
||||
private
|
||||
|
@ -45,7 +46,6 @@ private:
|
|||
QStackedWidget *stack;
|
||||
void setDive(const struct dive *d, int dcNr);
|
||||
void editDive();
|
||||
void exitEditMode();
|
||||
void rotateDC(int dir);
|
||||
std::unique_ptr<dive> editedDive;
|
||||
bool placingCommand;
|
||||
|
|
|
@ -143,7 +143,7 @@ void TabDiveEquipment::updateData(const std::vector<dive *> &, dive *currentDive
|
|||
cylindersModel->updateDive(currentDive, currentDC);
|
||||
weightModel->updateDive(currentDive);
|
||||
sensorDelegate.setCurrentDC(dc);
|
||||
tankUseDelegate.setCurrentDC(dc);
|
||||
tankUseDelegate.setDiveDc(*currentDive, currentDC);
|
||||
|
||||
if (currentDive && !currentDive->suit.empty())
|
||||
ui.suit->setText(QString::fromStdString(currentDive->suit));
|
||||
|
|
|
@ -235,7 +235,7 @@ public slots:
|
|||
void set_ascrate75(int value) { DivePlannerPointsModel::instance()->setAscrate75Display(value); }
|
||||
void set_descrate(int value) { DivePlannerPointsModel::instance()->setDescrateDisplay(value); }
|
||||
|
||||
void set_dive_mode(DIVE_MODE value) { DivePlannerPointsModel::instance()->setRebreatherMode((int)value); }
|
||||
void set_dive_mode(DIVE_MODE value) { DivePlannerPointsModel::instance()->setDiveMode((int)value); }
|
||||
void set_planner_deco_mode(DECO_MODE value) { PlannerShared::set_planner_deco_mode((deco_mode)value); }
|
||||
void set_reserve_gas(int value) { PlannerShared::set_reserve_gas(value); }
|
||||
void set_safetystop(bool value) { DivePlannerPointsModel::instance()->setSafetyStop(value); }
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QSettings>
|
||||
|
||||
DiveHandler::DiveHandler(const struct dive *d) : dive(d)
|
||||
DiveHandler::DiveHandler(const struct dive *d, int currentDcNr) : dive(d), dcNr(currentDcNr)
|
||||
{
|
||||
setRect(-5, -5, 10, 10);
|
||||
setFlags(ItemIgnoresTransformations | ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges);
|
||||
|
@ -31,14 +31,15 @@ void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
|
|||
QMenu m;
|
||||
// Don't have a gas selection for the last point
|
||||
emit released();
|
||||
|
||||
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
|
||||
QModelIndex index = plannerModel->index(parentIndex(), DivePlannerPointsModel::GAS);
|
||||
if (index.sibling(index.row() + 1, index.column()).isValid()) {
|
||||
QStringList gases = get_dive_gas_list(dive);
|
||||
for (int i = 0; i < gases.size(); i++) {
|
||||
std::vector<std::pair<int, QString>> gases = get_dive_gas_list(dive, dcNr, true);
|
||||
for (unsigned i = 0; i < gases.size(); i++) {
|
||||
QAction *action = new QAction(&m);
|
||||
action->setText(gases[i]);
|
||||
action->setData(i);
|
||||
action->setText(gases[i].second);
|
||||
action->setData(gases[i].first);
|
||||
connect(action, &QAction::triggered, this, &DiveHandler::changeGas);
|
||||
m.addAction(action);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ struct dive;
|
|||
class DiveHandler : public QObject, public QGraphicsEllipseItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DiveHandler(const struct dive *d);
|
||||
DiveHandler(const struct dive *d, int currentDcNr);
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
|
||||
|
@ -29,6 +29,7 @@ slots:
|
|||
void changeGas();
|
||||
private:
|
||||
const struct dive *dive;
|
||||
int dcNr;
|
||||
QElapsedTimer t;
|
||||
};
|
||||
|
||||
|
|
|
@ -656,7 +656,7 @@ void DiveGasPressureItem::plotGasValue(double mbar, double sec, const cylinder_t
|
|||
QString gas = get_gas_string(cylinder->gasmix);
|
||||
QString label;
|
||||
if (showDescription)
|
||||
label = QStringLiteral("(%1) %2").arg(QString::fromStdString(cylinder->type.description), gas);
|
||||
label = QStringLiteral("(%1) %2").arg(QString::fromStdString(cylinder->type.description), std::move(gas));
|
||||
else
|
||||
label = gas;
|
||||
auto text = std::make_unique<DiveTextItem>(dpr, 1.0, align, this);
|
||||
|
|
|
@ -500,16 +500,6 @@ struct int ProfileWidget2::getEntryFromPos(QPointF pos)
|
|||
#endif
|
||||
|
||||
#ifndef SUBSURFACE_MOBILE
|
||||
/// Prints cylinder information for display.
|
||||
/// eg : "Cyl 1 (AL80 EAN32)"
|
||||
static QString printCylinderDescription(int i, const cylinder_t &cylinder)
|
||||
{
|
||||
QString label = gettextFromC::tr("Cyl") + QString(" %1").arg(i+1);
|
||||
QString mix = get_gas_string(cylinder.gasmix);
|
||||
label += QString(" (%2 %3)").arg(QString::fromStdString(cylinder.type.description)).arg(mix);
|
||||
return label;
|
||||
}
|
||||
|
||||
static bool isDiveTextItem(const QGraphicsItem *item, const DiveTextItem *textItem)
|
||||
{
|
||||
while (item) {
|
||||
|
@ -520,6 +510,16 @@ static bool isDiveTextItem(const QGraphicsItem *item, const DiveTextItem *textIt
|
|||
return false;
|
||||
}
|
||||
|
||||
void ProfileWidget2::addGasChangeMenu(QMenu &m, QString menuTitle, const struct dive &d, int dcNr, int changeTime)
|
||||
{
|
||||
QMenu *gasChange = m.addMenu(menuTitle);
|
||||
std::vector<std::pair<int, QString>> gases = get_dive_gas_list(&d, dcNr, true);
|
||||
for (unsigned i = 0; i < gases.size(); i++) {
|
||||
int cylinderIndex = gases[i].first;
|
||||
gasChange->addAction(gases[i].second, [this, cylinderIndex, changeTime] { addGasSwitch(cylinderIndex, changeTime); });
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
if (currentState == EDIT || currentState == PLAN) {
|
||||
|
@ -558,19 +558,10 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
|
|||
|
||||
// Add or edit Gas Change
|
||||
if (d && item && item->ev.is_gaschange()) {
|
||||
int eventTime = item->ev.time.seconds;
|
||||
QMenu *gasChange = m.addMenu(tr("Edit Gas Change"));
|
||||
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
|
||||
QString label = printCylinderDescription(i, cyl);
|
||||
gasChange->addAction(label, [this, idx = i, eventTime] { addGasSwitch(idx, eventTime); });
|
||||
}
|
||||
addGasChangeMenu(m, tr("Edit Gas Change"), *d, dc, item->ev.time.seconds);
|
||||
} else if (d && d->cylinders.size() > 1) {
|
||||
// if we have more than one gas, offer to switch to another one
|
||||
QMenu *gasChange = m.addMenu(tr("Add gas change"));
|
||||
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
|
||||
QString label = printCylinderDescription(i, cyl);
|
||||
gasChange->addAction(label, [this, idx = i, seconds] { addGasSwitch(idx, seconds); });
|
||||
}
|
||||
addGasChangeMenu(m, tr("Add gas change"), *d, dc, seconds);
|
||||
}
|
||||
m.addAction(tr("Add setpoint change"), [this, seconds]() { ProfileWidget2::addSetpointChange(seconds); });
|
||||
m.addAction(tr("Add bookmark"), [this, seconds]() { addBookmark(seconds); });
|
||||
|
@ -837,7 +828,7 @@ int ProfileWidget2::handleIndex(const DiveHandler *h) const
|
|||
|
||||
DiveHandler *ProfileWidget2::createHandle()
|
||||
{
|
||||
DiveHandler *item = new DiveHandler(d);
|
||||
DiveHandler *item = new DiveHandler(d, dc);
|
||||
scene()->addItem(item);
|
||||
connect(item, &DiveHandler::moved, this, &ProfileWidget2::divePlannerHandlerMoved);
|
||||
connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked);
|
||||
|
|
|
@ -104,6 +104,7 @@ private:
|
|||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void addGasChangeMenu(QMenu &m, QString menuTitle, const struct dive &d, int dcNr, int changeTime);
|
||||
#endif
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
|
|
|
@ -156,25 +156,34 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
|
|||
|
||||
const cylinder_t *cyl = index.row() == tempRow ? &tempCyl : d->get_cylinder(index.row());
|
||||
|
||||
bool isInappropriateUse = !is_cylinder_use_appropriate(*d->get_dc(dcNr), *cyl, true);
|
||||
switch (role) {
|
||||
case Qt::BackgroundRole: {
|
||||
case Qt::BackgroundRole:
|
||||
switch (index.column()) {
|
||||
// mark the cylinder start / end pressure in red if the values
|
||||
// seem implausible
|
||||
case START:
|
||||
case END:
|
||||
pressure_t startp, endp;
|
||||
startp = cyl->start.mbar ? cyl->start : cyl->sample_start;
|
||||
endp = cyl->end.mbar ? cyl->end : cyl->sample_end;
|
||||
if ((startp.mbar && !endp.mbar) ||
|
||||
(endp.mbar && startp.mbar <= endp.mbar))
|
||||
{
|
||||
pressure_t startp = cyl->start.mbar ? cyl->start : cyl->sample_start;
|
||||
pressure_t endp = cyl->end.mbar ? cyl->end : cyl->sample_end;
|
||||
if ((startp.mbar && !endp.mbar) ||
|
||||
(endp.mbar && startp.mbar <= endp.mbar))
|
||||
return REDORANGE1_HIGH_TRANS;
|
||||
}
|
||||
|
||||
break;
|
||||
case USE:
|
||||
if (isInappropriateUse)
|
||||
return REDORANGE1_HIGH_TRANS;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Qt::FontRole: {
|
||||
QFont font = defaultModelFont();
|
||||
|
||||
switch (index.column()) {
|
||||
// if we don't have manually set pressure data use italic font
|
||||
case START:
|
||||
|
@ -184,6 +193,9 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
|
|||
font.setItalic(!cyl->end.mbar);
|
||||
break;
|
||||
}
|
||||
|
||||
font.setItalic(isInappropriateUse);
|
||||
|
||||
return font;
|
||||
}
|
||||
case Qt::TextAlignmentRole:
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include "diveplannermodel.h"
|
||||
#include "core/color.h"
|
||||
#include "core/dive.h"
|
||||
#include "core/divelist.h"
|
||||
#include "core/divelog.h"
|
||||
#include "core/event.h"
|
||||
#include "core/subsurface-string.h"
|
||||
#include "qt-models/cylindermodel.h"
|
||||
#include "qt-models/models.h" // For defaultModelFont().
|
||||
#include "core/metrics.h" // For defaultModelFont().
|
||||
#include "core/planner.h"
|
||||
#include "core/device.h"
|
||||
#include "core/qthelper.h"
|
||||
|
@ -88,12 +89,12 @@ void DivePlannerPointsModel::createSimpleDive(struct dive *dIn)
|
|||
// If we're in drop_stone_mode, don't add a first point.
|
||||
// It will be added implicitly.
|
||||
if (!prefs.drop_stone_mode)
|
||||
addStop(M_OR_FT(15, 45), 1 * 60, cylinderid, 0, true, UNDEF_COMP_TYPE);
|
||||
addStop(M_OR_FT(15, 45), 1 * 60, cylinderid, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
|
||||
addStop(M_OR_FT(15, 45), 20 * 60, 0, 0, true, UNDEF_COMP_TYPE);
|
||||
addStop(M_OR_FT(15, 45), 20 * 60, 0, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
if (!isPlanner()) {
|
||||
addStop(M_OR_FT(5, 15), 42 * 60, 0, cylinderid, true, UNDEF_COMP_TYPE);
|
||||
addStop(M_OR_FT(5, 15), 45 * 60, 0, cylinderid, true, UNDEF_COMP_TYPE);
|
||||
addStop(M_OR_FT(5, 15), 42 * 60, cylinderid, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
addStop(M_OR_FT(5, 15), 45 * 60, cylinderid, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
}
|
||||
updateDiveProfile();
|
||||
}
|
||||
|
@ -260,13 +261,40 @@ int DivePlannerPointsModel::columnCount(const QModelIndex&) const
|
|||
return COLUMNS; // to disable CCSETPOINT subtract one
|
||||
}
|
||||
|
||||
static divemode_t get_local_divemode(struct dive *d, int dcNr, const divedatapoint &p)
|
||||
{
|
||||
divemode_t divemode;
|
||||
switch (d->get_dc(dcNr)->divemode) {
|
||||
case OC:
|
||||
default:
|
||||
divemode = OC;
|
||||
|
||||
break;
|
||||
case CCR:
|
||||
divemode = d->get_cylinder(p.cylinderid)->cylinder_use == DILUENT ? CCR : OC;
|
||||
if (prefs.allowOcGasAsDiluent && d->get_cylinder(p.cylinderid)->cylinder_use == OC_GAS && p.divemode == CCR)
|
||||
divemode = CCR;
|
||||
|
||||
break;
|
||||
case PSCR:
|
||||
divemode = p.divemode == PSCR ? PSCR : OC;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return divemode;
|
||||
}
|
||||
|
||||
QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
divedatapoint p = divepoints.at(index.row());
|
||||
const divedatapoint p = divepoints.at(index.row());
|
||||
bool isInappropriateCylinder = !is_cylinder_use_appropriate(*d->get_dc(dcNr), *d->get_cylinder(p.cylinderid), false);
|
||||
divemode_t divemode = get_local_divemode(d, dcNr, p);
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
||||
|
||||
switch (index.column()) {
|
||||
case CCSETPOINT:
|
||||
return (double)p.setpoint / 1000;
|
||||
return (divemode == CCR) ? (double)(p.setpoint / 1000.0) : QVariant();
|
||||
case DEPTH:
|
||||
return (int) lrint(get_depth_units(p.depth.mm, NULL, NULL));
|
||||
case RUNTIME:
|
||||
|
@ -277,18 +305,9 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
|
|||
else
|
||||
return p.time / 60;
|
||||
case DIVEMODE:
|
||||
return gettextFromC::tr(divemode_text_ui[p.divemode]);
|
||||
return gettextFromC::tr(divemode_text_ui[divemode]);
|
||||
case GAS:
|
||||
/* Check if we have the same gasmix two or more times
|
||||
* If yes return more verbose string */
|
||||
const cylinder_t &cyl = d->cylinders[p.cylinderid];
|
||||
int same_gas = same_gasmix_cylinder(cyl, p.cylinderid, d, true);
|
||||
if (same_gas == -1)
|
||||
return get_gas_string(cyl.gasmix);
|
||||
else
|
||||
return get_gas_string(cyl.gasmix) +
|
||||
QString(" (%1 %2 ").arg(tr("cyl.")).arg(p.cylinderid + 1) +
|
||||
QString::fromStdString(cyl.type.description) + ")";
|
||||
return get_dive_gas(d, dcNr, p.cylinderid);
|
||||
}
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
switch (index.column()) {
|
||||
|
@ -307,14 +326,28 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
|
|||
return trashForbiddenIcon().size();
|
||||
}
|
||||
} else if (role == Qt::FontRole) {
|
||||
if (divepoints.at(index.row()).entered) {
|
||||
return defaultModelFont();
|
||||
} else {
|
||||
QFont font = defaultModelFont();
|
||||
font.setBold(true);
|
||||
return font;
|
||||
QFont font = defaultModelFont();
|
||||
|
||||
font.setBold(!p.entered);
|
||||
|
||||
font.setItalic(isInappropriateCylinder);
|
||||
|
||||
return font;
|
||||
} else if (role == Qt::BackgroundRole) {
|
||||
switch (index.column()) {
|
||||
case GAS:
|
||||
if (isInappropriateCylinder)
|
||||
return REDORANGE1_HIGH_TRANS;
|
||||
|
||||
break;
|
||||
case CCSETPOINT:
|
||||
if (divemode != CCR)
|
||||
return MED_GRAY_HIGH_TRANS;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
@ -377,7 +410,6 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
|
|||
case DIVEMODE:
|
||||
if (value.toInt() < FREEDIVE) {
|
||||
p.divemode = (enum divemode_t) value.toInt();
|
||||
p.setpoint = p.divemode == CCR ? prefs.defaultsetpoint : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -416,7 +448,7 @@ QVariant DivePlannerPointsModel::headerData(int section, Qt::Orientation orienta
|
|||
case GAS:
|
||||
return tr("Used gas");
|
||||
case CCSETPOINT:
|
||||
return tr("CC setpoint");
|
||||
return tr("Setpoint");
|
||||
case DIVEMODE:
|
||||
return tr("Dive mode");
|
||||
}
|
||||
|
@ -428,10 +460,29 @@ QVariant DivePlannerPointsModel::headerData(int section, Qt::Orientation orienta
|
|||
|
||||
Qt::ItemFlags DivePlannerPointsModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (index.column() != REMOVE)
|
||||
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
|
||||
else
|
||||
if (!index.isValid())
|
||||
return QAbstractItemModel::flags(index);
|
||||
|
||||
if (index.column() == REMOVE)
|
||||
return Qt::ItemIsEnabled;
|
||||
|
||||
const divedatapoint p = divepoints.at(index.row());
|
||||
switch (index.column()) {
|
||||
case REMOVE:
|
||||
return QAbstractItemModel::flags(index);
|
||||
case CCSETPOINT:
|
||||
if (get_local_divemode(d, dcNr, p) != CCR)
|
||||
return QAbstractItemModel::flags(index) & ~Qt::ItemIsEditable & ~Qt::ItemIsEnabled;
|
||||
|
||||
break;
|
||||
case DIVEMODE:
|
||||
if (!((d->get_dc(dcNr)->divemode == CCR && prefs.allowOcGasAsDiluent && d->get_cylinder(p.cylinderid)->cylinder_use == OC_GAS) || d->get_dc(dcNr)->divemode == PSCR))
|
||||
return QAbstractItemModel::flags(index) & ~Qt::ItemIsEditable & ~Qt::ItemIsEnabled;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
int DivePlannerPointsModel::rowCount(const QModelIndex&) const
|
||||
|
@ -537,14 +588,16 @@ int DivePlannerPointsModel::gfLow() const
|
|||
return diveplan.gflow;
|
||||
}
|
||||
|
||||
void DivePlannerPointsModel::setRebreatherMode(int mode)
|
||||
void DivePlannerPointsModel::setDiveMode(int mode)
|
||||
{
|
||||
d->get_dc(dcNr)->divemode = (divemode_t) mode;
|
||||
for (int i = 0; i < rowCount(); i++) {
|
||||
divepoints[i].setpoint = mode == CCR ? prefs.defaultsetpoint : 0;
|
||||
divepoints[i].divemode = (enum divemode_t) mode;
|
||||
}
|
||||
struct divecomputer *dc = d->get_dc(dcNr);
|
||||
if (dc)
|
||||
dc->divemode = (divemode_t) mode;
|
||||
|
||||
cylinders.updateDive(d, dcNr);
|
||||
|
||||
emitDataChanged();
|
||||
cylinders.emitDataChanged();
|
||||
}
|
||||
|
||||
void DivePlannerPointsModel::setVpmbConservatism(int level)
|
||||
|
@ -753,13 +806,13 @@ int DivePlannerPointsModel::lastEnteredPoint() const
|
|||
void DivePlannerPointsModel::addDefaultStop()
|
||||
{
|
||||
removeDeco();
|
||||
addStop(0, 0, -1, 0, true, UNDEF_COMP_TYPE);
|
||||
addStop(0, 0, -1, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
}
|
||||
|
||||
void DivePlannerPointsModel::addStop(int milimeters, int seconds)
|
||||
{
|
||||
removeDeco();
|
||||
addStop(milimeters, seconds, -1, 0, true, UNDEF_COMP_TYPE);
|
||||
addStop(milimeters, seconds, -1, prefs.defaultsetpoint, true, UNDEF_COMP_TYPE);
|
||||
updateDiveProfile();
|
||||
}
|
||||
|
||||
|
@ -775,18 +828,20 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, int cylinderid_
|
|||
usePrevious = true;
|
||||
|
||||
int row = divepoints.count();
|
||||
if (seconds == 0 && milimeters == 0 && row != 0) {
|
||||
/* this is only possible if the user clicked on the 'plus' sign on the DivePoints Table */
|
||||
const divedatapoint t = divepoints.at(lastEnteredPoint());
|
||||
milimeters = t.depth.mm;
|
||||
seconds = t.time + 600; // 10 minutes.
|
||||
cylinderid = t.cylinderid;
|
||||
ccpoint = t.setpoint;
|
||||
} else if (seconds == 0 && milimeters == 0 && row == 0) {
|
||||
milimeters = M_OR_FT(5, 15); // 5m / 15ft
|
||||
seconds = 600; // 10 min
|
||||
// Default to the first cylinder
|
||||
cylinderid = 0;
|
||||
if (seconds == 0 && milimeters == 0) {
|
||||
if (row == 0) {
|
||||
milimeters = M_OR_FT(5, 15); // 5m / 15ft
|
||||
seconds = 600; // 10 min
|
||||
// Default to the first cylinder
|
||||
cylinderid = 0;
|
||||
} else {
|
||||
/* this is only possible if the user clicked on the 'plus' sign on the DivePoints Table */
|
||||
const divedatapoint t = divepoints.at(lastEnteredPoint());
|
||||
milimeters = t.depth.mm;
|
||||
seconds = t.time + 600; // 10 minutes.
|
||||
cylinderid = t.cylinderid;
|
||||
ccpoint = t.setpoint;
|
||||
}
|
||||
}
|
||||
|
||||
// check if there's already a new stop before this one:
|
||||
|
@ -1037,16 +1092,17 @@ void DivePlannerPointsModel::createTemporaryPlan()
|
|||
|
||||
int lastIndex = -1;
|
||||
for (int i = 0; i < rowCount(); i++) {
|
||||
divedatapoint p = at(i);
|
||||
const divedatapoint p = at(i);
|
||||
divemode_t divemode = get_local_divemode(d, dcNr, p);
|
||||
int deltaT = lastIndex != -1 ? p.time - at(lastIndex).time : p.time;
|
||||
lastIndex = i;
|
||||
if (i == 0 && mode == PLAN && prefs.drop_stone_mode) {
|
||||
/* Okay, we add a first segment where we go down to depth */
|
||||
plan_add_segment(&diveplan, p.depth.mm / prefs.descrate, p.depth.mm, p.cylinderid, p.setpoint, true, p.divemode);
|
||||
plan_add_segment(&diveplan, p.depth.mm / prefs.descrate, p.depth.mm, p.cylinderid, divemode == CCR ? p.setpoint : 0, true, divemode);
|
||||
deltaT -= p.depth.mm / prefs.descrate;
|
||||
}
|
||||
if (p.entered)
|
||||
plan_add_segment(&diveplan, deltaT, p.depth.mm, p.cylinderid, p.setpoint, true, p.divemode);
|
||||
plan_add_segment(&diveplan, deltaT, p.depth.mm, p.cylinderid, divemode == CCR ? p.setpoint : 0, true, divemode);
|
||||
}
|
||||
|
||||
#if DEBUG_PLAN
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
|
||||
void loadFromDive(dive *d, int dcNr);
|
||||
void addStop(int millimeters, int seconds);
|
||||
void setDiveMode(int mode);
|
||||
public
|
||||
slots:
|
||||
void addDefaultStop();
|
||||
|
@ -96,7 +97,6 @@ slots:
|
|||
void removeDeco();
|
||||
void deleteTemporaryPlan();
|
||||
void emitDataChanged();
|
||||
void setRebreatherMode(int mode);
|
||||
void setReserveGas(int reserve);
|
||||
void setSwitchAtReqStop(bool value);
|
||||
void setMinSwitchDuration(int duration);
|
||||
|
|
|
@ -13,44 +13,84 @@
|
|||
#include <QDir>
|
||||
#include <QLocale>
|
||||
|
||||
Qt::ItemFlags GasSelectionModel::flags(const QModelIndex&) const
|
||||
GasSelectionModel::GasSelectionModel(const dive &d, int dcNr, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
GasSelectionModel::GasSelectionModel(const dive &d, QObject *parent)
|
||||
: QStringListModel(parent)
|
||||
{
|
||||
setStringList(get_dive_gas_list(&d));
|
||||
gasNames = get_dive_gas_list(&d, dcNr, true);
|
||||
}
|
||||
|
||||
QVariant GasSelectionModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::FontRole)
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
switch (role) {
|
||||
case Qt::FontRole:
|
||||
return defaultModelFont();
|
||||
return QStringListModel::data(index, role);
|
||||
case Qt::DisplayRole:
|
||||
return gasNames.at(index.row()).second;
|
||||
case Qt::UserRole:
|
||||
return gasNames.at(index.row()).first;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int GasSelectionModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return gasNames.size();
|
||||
}
|
||||
|
||||
// Dive Type Model for the divetype combo box
|
||||
|
||||
Qt::ItemFlags DiveTypeSelectionModel::flags(const QModelIndex&) const
|
||||
DiveTypeSelectionModel::DiveTypeSelectionModel(const dive &d, int dcNr, QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
divemode_t mode = d.get_dc(dcNr)->divemode;
|
||||
for (int i = 0; i < FREEDIVE; i++) {
|
||||
switch (mode) {
|
||||
case OC:
|
||||
default:
|
||||
if (i != OC)
|
||||
continue;
|
||||
|
||||
DiveTypeSelectionModel::DiveTypeSelectionModel(QObject *parent) : QStringListModel(parent)
|
||||
{
|
||||
QStringList modes;
|
||||
for (int i = 0; i < FREEDIVE; i++)
|
||||
modes.append(gettextFromC::tr(divemode_text_ui[i]));
|
||||
setStringList(modes);
|
||||
break;
|
||||
case CCR:
|
||||
if (i != OC && i != CCR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
case PSCR:
|
||||
if (i != OC && i != PSCR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
diveTypes.push_back(std::pair(i, gettextFromC::tr(divemode_text_ui[i])));
|
||||
}
|
||||
}
|
||||
|
||||
QVariant DiveTypeSelectionModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::FontRole)
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
switch (role) {
|
||||
case Qt::FontRole:
|
||||
return defaultModelFont();
|
||||
return QStringListModel::data(index, role);
|
||||
case Qt::DisplayRole:
|
||||
return diveTypes.at(index.row()).second;
|
||||
case Qt::UserRole:
|
||||
return diveTypes.at(index.row()).first;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int DiveTypeSelectionModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return diveTypes.size();
|
||||
}
|
||||
|
||||
// Language Model, The Model to populate the list of possible Languages.
|
||||
|
|
|
@ -21,20 +21,24 @@
|
|||
|
||||
struct dive;
|
||||
|
||||
class GasSelectionModel : public QStringListModel {
|
||||
class GasSelectionModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GasSelectionModel(const dive &d, QObject *parent);
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
GasSelectionModel(const dive &d, int dcNr, QObject *parent);
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
private:
|
||||
std::vector<std::pair<int, QString>> gasNames;
|
||||
};
|
||||
|
||||
class DiveTypeSelectionModel : public QStringListModel {
|
||||
class DiveTypeSelectionModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DiveTypeSelectionModel(QObject *parent);
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
DiveTypeSelectionModel(const dive &d, int dcNr, QObject *parent);
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
private:
|
||||
std::vector<std::pair<int, QString>> diveTypes;
|
||||
};
|
||||
|
||||
class LanguageModel : public QAbstractListModel {
|
||||
|
|
|
@ -113,6 +113,11 @@ TestCase {
|
|||
var x27 = PrefTechnicalDetails.zoomed_plot
|
||||
PrefTechnicalDetails.zoomed_plot = true
|
||||
compare(PrefTechnicalDetails.zoomed_plot, true)
|
||||
|
||||
var x28 = PrefTechnicalDetails.allowOcGasAsDiluent
|
||||
PrefTechnicalDetails.allowOcGasAsDiluent = true
|
||||
compare(PrefTechnicalDetails.allowOcGasAsDiluent, true)
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -204,6 +209,7 @@ TestCase {
|
|||
PrefTechnicalDetails.tankbar = ! PrefTechnicalDetails.tankbar
|
||||
PrefTechnicalDetails.vpmb_conservatism = -127
|
||||
PrefTechnicalDetails.zoomed_plot = ! PrefTechnicalDetails.zoomed_plot
|
||||
PrefTechnicalDetails.allowOcGasAsDiluent = ! PrefTechnicalDetails.allowOcGasAsDiluent
|
||||
|
||||
compare(spyCatcher.spy1, true)
|
||||
compare(spyCatcher.spy2, true)
|
||||
|
|