/****************************************************************************
**
** Copyright (C) 2019 Minnesota Department of Transportation
** Office of Materials & Road Research
** 1400 Gervais Avenue
** Saint Paul, Minnesota 55109-2044
** USA
** http://www.dot.state.mn.us/materials/pvmtdesign/software.html
**
**
** $QT_BEGIN_LICENSE:GPL$
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** If you did not receive a copy of the GNU General Public License
** see http://www.gnu.org/licenses
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "mnpave.h"
#include "ui_mnpave.h"
#include "globals.h"
#include "calc.h"
#include "aboutdlg.h"
#include "climatedlg.h"
#include "helpdlg.h"
#include "layerdlg.h"
#include "mapdlg.h"
#include "mydoublespinbox.h"
#include "notesdlg.h"
#include "outputdlg.h"
#include "trafficdlg.h"
#include "weslea.h"

mnpave::mnpave(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::mnpave)
{
    ui->setupUi(this);
    calc c;
    this->setWindowTitle(newWinTitle(tName));
    setMouseTracking(true);
    nCount = 0;
    double tt = c.airT(45., 2);
    quint64 ntst = 0;
    QString ttst = bas2bas54("10111100100011", "01", A32RFC4648, &ntst);

    int i, j;

    int k = A64.indexOf("4");
    QString a = A64.at(k);
//    qDebug() << a;

    QFont font;
    font.setBold(true);
    ui->infoGroup->setFont(font);
    font.setBold(false);
    ui->infoGroup->setFont(font);
    // Initialize lists (serialized)
    bList.reserve(89);      // expected number of items in the list
    bList.append(false);    //  0 units (False = English, True = SI)
    bList.append(true);     //  1 show thickness warnings
    bList.append(true);     //  2 show binder warnings
    bList.append(false);    //  3 always show allowable stress
    bList.append(true);     //  4 only show if failed
    bList.append(false);    //  5 design (false) or research (true) mode
    bList.append(false);    //  6 ESAL (false) or spectrum (true)
    bList.append(false);    //  7 simple (false) or compound (true) growth
    bList.append(false);    //  8 Perpetual Pavement all strains (false) or ignore low (true)
    bList.append(false);    //  9 user entered climate data
    bList.append(true);     // 10 Tpave (false) or Tair (true)
    bList.append(false);    // 11 Use same temperature depth for all HMA lifts
    bList.append(false);    // 12 User depth for temperature calculation
    bList.append(false);    // 13 life ESALs (false) or 1st year (true)
    bList.append(true);     // 14 spectrum: interpolate strains
    bList.append(false);    // 15 MnDOT vehicles (false) or FHWA (true)
    bList.append(false);    // 16 Use HCADT in Spectrum estimate (false = ADT)
    bList.append(false);    // 17 seasonal spectra
    bList.append(false);    // 18 Use WIM data to calculate spectrum
    bList.append(false);    // 19 User changed Structure (don't set default layers)
    bList.append(false);    // 20 Use mean H & E values (instead of reduced for confidence)
    bList.append(false);    // 21 Show rutting for overlay design
    bList.append(false);    // 22 Mill & Overlay
    bList.append(false);    // 23 SI units in FWDSim
    bList.append(true);     // 24 SI units in LWDSim
    bList.append(false);    // 25 use BELLS3 temperature calculation in FWDSim
    bList.append(true);     // 26 Use overburden in simulations
    bList.append(false);    // 27 Show pavement life in years (true = damage factor)
    bList.append(false);    // 28 Define z location by percent
    bList.append(false);    // 29 batch damage limit
    for(i = 0; i < 5; ++i) {bList.append(false);} // 30-34 are agg test check boxes
    for(i = 0; i < 5; ++i) {bList.append(false);} // 35-39 are soil test check boxes
    // Research Mode
    for(i = 0; i < 5; ++i) {bList.append(true);} // 40-44 are season check boxes
    for(i = 0; i < 7; ++i) {bList.append(i < 4 ? true : false);} // 47-51 are axle check boxes
    for(i = 0; i < 35; ++i) {bList.append(false);} // 52-86 indicate if there are at least 3 load categories for strain interpolation
// end BOOL imports from MnPAVE 6.4
    bList.append(false);    // 87 widened outer lane
    bList.append(false);    // 88 tied PCC shoulder

    iList.reserve(4931);
    iList.append(20);       //  0 HMA Design Life
    iList.append(3);        //  1 HMA layers (number of layers = index + 1)
    iList.append(0);        //  2 Struc Mode (basic)
    iList.append(2);        //  3 Agg Test (E, R-Value, DCP, CBR)
    iList.append(1);        //  4 Soil Test (E, R-Value, DCP, SiltClay
    iList.append(5000);     //  5 MC Cycles
    iList.append(1);        //  6 Spectrum Mode (1 = Intermediate)
    iList.append(1);        //  7 Witczak Version (1 = 2002)
    iList.append(0);        //  8 ESAL axle selection (Old: 0=Dual,1=DTan,2=DTri,3=Single..., New: 0=ESAL, 1=Dual...)
    iList.append(3);        //  9 Spectrum Road Type (3 = Rural Highway)
    for(i = 0; i < 3; ++i) {iList.append(0);}    // 10-12 number of lifts in 1st 3 layers
    for(i = 0; i < 5; ++i) {iList.append(-1);}   // 13-17 materials in each layer
    for(i = 0; i < 4; ++i) {iList.append(25);}   // 18-21 % depth in each layer
    for(i = 0; i < 4; ++i) {iList.append(0);}    // 22-25 eval responses (NormStress, ShearStress, NormStrain, Deflection, Prin. Stress)
    for(i = 0; i < 4; ++i) {iList.append(0);}    // 26-29 eval directions (X, Y, Z)
    for(i = 0; i < 4; ++i) {iList.append(0);}    // 30-33 eval locations (top, middle, bottom)
    for(i = 0; i < 6; ++i) {iList.append(0);}    // 34-39 number of load categories for each season
    for(i = 0; i < 360; ++i) {iList.append(0);}  // 40-399 all load classes [axle type][load class]
    for(i = 0; i < 2160; ++i) {iList.append(0);} // 400-2559 seasonal life reps (Fall, Winter..., All)
    for(i = 0; i < 2160; ++i) {iList.append(0);} // 2560-4719 seasonal life reps (Fall, Winter..., All)
    for(i = 0; i < 180; ++i) {iList.append(-1);} // 4720-4899 material subtypes for each material type
    for(i = 0; i < 6; ++i) {iList.append(0);}    // 4900-4905 binder spec, nom max size for 3 lifts
    for(i = 0; i < 3; ++i) {iList.append(0);}    // 4906-4908 temperature depth selections for 3 lifts (0 = 1/3, 1 = 1/2, 2 = constant depth)
    for(i = 0; i < 3; ++i) {iList.append(0);}    // 4909-4911 nFWDSIM (season, layer, sensors)
    iList.append(3);        // 4912 nLWDLayer (selected layer)
    for(i = 0; i < 5; ++i) {iList.append(2);}    // 4913-4917 nLWDMoist (selected moisture column)
    iList.append(0);        // 4918 Bituminous Sublayer (0 = Old HMA, 1 = CIR, 2 = SFDR)
    iList.append(0);        // 4919 Fatigue Model Selected
    iList.append(0);        // 4920 Rutting Model Selected
    iList.append(-1);       // 4921 Agg layer containing geogrid (-1: no geogrid)
    // End of int imported from MnPAVE 6.4
    iList.append(35);       // 4922 PCC life
    iList.append(0);        // 4923 number of lanes (two-way)
    iList.append(0);        // 4924 axle load spectrum selection
    iList.append(0);        // 4925 joint spacing
    iList.append(0);        // 4926 pcc base material (CL5S, CL5Q, OGAB)
    iList.append(0);        // 4927 pcc base thickness (4 or 12")
    iList.append(3);        // 4928 rigid layers index (number of layers = index + 1)
    iList.append(1);        // 4929 soil type
    iList.append(2);        // 4930  wheels per half axle (custom axle type)
    iList.append(1);       // 4931 construction type (HMA or PCC) 20180725 temporarily select PCC

    dList.reserve(452);
    dList.append(0.0);      // 0 ESALs (millions)
    for(i = 0; i < 12; ++i) {dList.append(0.0);} // 1-12 sublayer thickness (3 per layer)
    for(i = 0; i < 4; ++i) {dList.append(0.0);} // 13-16 layer thickness COV
    for(i = 0; i < 20; ++i) {dList.append(0.0);} // 17-36 aggregate test values
    for(i = 0; i < 20; ++i) {dList.append(0.0);} // 37-56 soil test values
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 57-61 other test values
    for(i = 0; i < 25; ++i) {dList.append(0.0);} // 62-86 user moduli
    for(i = 0; i < 25; ++i) {dList.append(0.0);} // 87-111 user Poissons ratios
    for(i = 0; i < 25; ++i) {dList.append(0.0);} // 112-136 user modulus COVs
    for(i = 0; i < 42; ++i) {dList.append(0.0);} // 137-178 Witczak values
    dList.append(1.0); // 179 ipct traffic growth rate (%)
    dList.append(8.0); // 180 Va air voids at bottom of HMA (%)
    dList.append(60); // 181 mph traffic speed
    dList.append(18); // 182 thawDepth early spring
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 183-187 user season durations
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 188-192 user seasonal air temperatures
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 193-197 user seasonal pavement temperatures
    dList.append(0.0); // 198 AADT
    dList.append(70.0); // 199 Confidence
    for(i = 0; i < 42; ++i) {dList.append(0.0);} // 200-241 user Witczak a values
    for(i = 0; i < 6; ++i) {dList.append(0.0);} // 242-247 user Witczak b values
    for(i = 0; i < 10; ++i) {dList.append(100.0);} // 248-257 Tire pressure for each axle type (8 is for ESAL, 9 is for custom)
    for(i = 0; i < 10; ++i) {dList.append(13.5);} // 258-267 xSpace lateral tire spacing
    for(i = 0; i < 10; ++i) {dList.append(54.0);} // 268-277 ySpace longitudinal tire spacing
    dList.append(1.9); // 278 MnDOT Class 4
    dList.append(0.9); // 279 MnDOT Class 5
    dList.append(0.1); // 280 MnDOT Class 6
    dList.append(0.2); // 281 MnDOT Class 7
    dList.append(4.5); // 282 MnDOT Class 8 (new: 5+ Axle Semi)
    dList.append(0.0); // 283 MnDOT Class 9a (new: 5+ Max)
    dList.append(0.0); // 284 MnDOT Class 9b (new: 5+ Other)
    dList.append(0.4); // 285 MnDOT Class 10
    dList.append(0.8); // 286 MnDOT Class 11
    dList.append(0.0); // 287 unused
    for(i = 0; i < 10; ++i) {dList.append(0.0);} // 288-297 vFHWA % vehicle classes
    for(i = 0; i < 6; ++i) {dList.append(0.0);} // 298-303 WIMDays (time of WIM testing for each axle type)
    for(i = 0; i < 48; ++i) {dList.append(0.0);} // 304-351 Mohr Weight [Fall, Winter, ... All][Axle]
    for(i = 0; i < 12; ++i) {dList.append(0.0);} // 352-363 C, Phi AggBase
    for(i = 0; i < 12; ++i) {dList.append(0.0);} // 364-375 C, Phi Subbase
    dList.append(22.0); // 376 Mohr Weight 1 (kips)
    dList.append(28.0); // 377 Mohr Weight 2 (kips)
    dList.append(100.0); // 378 Mohr Pressure 1 (psi)
    dList.append(100.0); // 379 Mohr Pressure 2 (psi)
    dList.append(0.0); // 380 Mohr lateral spacing 1 (in)
    dList.append(13.5); // 381 Mohr lateral spacing 2 (in)
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 382-386 Intermediate Poisson's Ratios
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 387-391 Intermediate COV
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 392-396 Intermediate Resistance Factors
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 397-401 Other Poisson's Ratios
    for(i = 0; i < 3; ++i) {dList.append(0.0);} // 402-404 User A values (viscosity)
    for(i = 0; i < 3; ++i) {dList.append(0.0);} // 405-407 User VTS
    for(i = 0; i < 3; ++i) {dList.append(0.0);} // 408-410 User Kinematic Viscosity
    for(i = 0; i < 4; ++i) {dList.append(0.0);} // 411-414 User Gamma (unit weight, pcf)
    for(i = 0; i < 4; ++i) {dList.append(0.0);} // 415-418 User Ko (coef of earth pressure at rest)
    for(i = 0; i < 6; ++i) {dList.append(0.0);} // 419-424 FWD dia, kips, TLo, THi, hour, Temp F
    for(i = 0; i < 10; ++i) {dList.append(0.0);} // 425-434 FWD sensor offset
    for(i = 0; i < 3; ++i) {dList.append(0.0);} // 435-437 LWD dia, load, resistance factor
    for(i = 0; i < 5; ++i) {dList.append(0.0);} // 438-442 LWDmils
    dList.append(-70.0); // 443 HMA Threshold
    dList.append(300.0); // 444 Soil Threshold
    dList.append(2.5); // 445 Pt, AASHTO terminal serviceability for LEF
    dList.append(0.0); // 446 effective geogrid modulus
    dList.append(0.0); // 447 FatMCRel
    dList.append(0.0); // 448 RutMCRel
    dList.append(18.0); // 449 Custom Axle Wtj (kips)
    // End of double imported from MnPAVE 6.4
    dList.append(0.0); // 450 HCADT
    dList.append(0.0); // 451 HPCC

    sList.reserve(14);
    sList.append("");       //  0 District
    sList.append("");       //  1 County
    sList.append("");       //  2 City
    sList.append("");       //  3 SP
    sList.append("");       //  4 Hwy
    sList.append("");       //  5 RP1
    sList.append("");       //  6 RP2
    sList.append("");       //  7 ConstType
    sList.append("");       //  8 Designer
    sList.append("");       //  9 SoilsEngineer
    sList.append("");       // 10 Notes
    for(i = 0; i < 3; ++i) {sList.append("User Defined " + QString::number(i+1));} // 11-13 custom HMA spec names

    assignPointers();

    // hide research mode for now
    *bResearch = false;
    HCADTadj = 1.0; // (rigid) adjusts HCADT for very heavy loads
    ui->actionResearch->setVisible(false);
    ui->menuWarnings->setEnabled(false);
    ui->menuTraffic->setEnabled(false);
    ui->menuPerpetual_Pavement->setEnabled(false);
    if(PAVEMENT < BOTH)
    {
        *nConstType = PAVEMENT;
        ui->constCombo->setEnabled(false);
        if(PAVEMENT == RIGID)
        {
            *nRigidLayer = 3;
            *nSoil = 15;
            ui->distCombo->removeItem(8); // Remove "All"
            ui->coLabel->setVisible(false);
            ui->coCombo->setVisible(false);
            ui->mapButton->setVisible(false);
            ui->climateButton->setVisible(false);
            ui->outGroup->setTitle(tr("Calculate"));
            ui->calcButton->setText(tr("Calculate thickness"));
        }

    }

    *pTire[ESAL] = 80.; // reset ESAL tire pressure to 80 psi

    vList.reserve(2);
    vList.append(QDate());   // 0 let date
    vList.append(QPointF()); // 1 location (lon, lat)

    pAction[0] = ui->action1;
    pAction[1] = ui->action2;
    pAction[2] = ui->action3;
    pAction[3] = ui->action4;
    pAction[4] = ui->action5;
    pAction[5] = ui->action6;

    for(i = 0; i < MaxRecentFiles; ++i)
    {
        pAction[i]->setVisible(false);
    }

    pButton[0] = ui->layerButton1;
    pButton[1] = ui->layerButton2;
    pButton[2] = ui->layerButton3;
    pButton[3] = ui->layerButton4;
    pButton[4] = ui->layerButton5;

    pSpin[0] = ui->layerSpin1;
    pSpin[1] = ui->layerSpin2;
    pSpin[2] = ui->layerSpin3;
    pSpin[3] = ui->layerSpin4;

    loadW(); // load widget pointers & geometries

    // Initialize other variables
    bdefault = false;
    bspin = false;
    bopen = false;
    bxml = false;
    nDistrict = 8; // no district selected
    nCounty = -1; // no county selected
    nHlab = 0; // "Thickness"

    vList[0] = QDate::currentDate();
    vList[1] = QPointF(-1,-1);

    nVersion = QApplication::applicationVersion().toInt();
    tFile = "";

    // initialize variables for temporary user data
    for(i = 0; i < 8; ++i) bedit[i] = false;
    for(i = 0; i < 4; ++i) val[i] = 0.0;
    for(i = 0; i < 5; ++i) tval[i] = "";

    mpSettings("", READBOOL);

    updateView();
    bmodified = false;
    tDisclaimer = tr("Disclaimer: The Minnesota Department of Transportation makes no guarantee or warranty, either express or implied, with respect to the reuse of the data provided herewith, regardless of its format or means of its transmission. The user accepts the data \"as is\", and assumes all risks associated with its use. By accepting of this data, the user agrees not to transmit this data or provide access to it or any part of it to another party unless the user shall include with the data a copy of this disclaimer. The Minnesota Department of Transportation assumes no responsibility, actual or consequential, for damage that results from any user's reliance on this data.");
}
mnpave::~mnpave()
{
    delete ui;
}

void mnpave::assignPointers()
{
    // assign pointers to clarify code
    int i, j, k;
    bsi = &bList[0]; // SI or English units
    bHWarn = &bList[1]; // Warn if HMA is too thin for critical stress
    bBWarn = &bList[2]; // Warn if -34 binder is required
    bMohrAlways = &bList[3]; // Always show Mohr window
    bMohrFail = &bList[4]; // only show Mohr window if critical stress test fails
    bResearch = &bList[5]; // research mode
    bSpectrum = &bList[6]; // load spectrum traffic
    bCompound = &bList[7]; // traffic growth mode
    bPerpetual = &bList[8]; // ignore strains below perpetual pavement threshold
    bUserClimate = &bList[9]; // user climate data instead of weather station
    bPaveT = &bList[10]; // user Pavement temperatures (false = Air)
    bzTSame = &bList[11]; // Use the same depth for all HMA lifts
    bMNTABLE = &bList[12]; // include load spectra from MNTABLE for comparison
    bFirstYearESAL = &bList[13]; // First year ESALS (false = design life ESALs)
    bInterpSpec = &bList[14]; // Interpolate spectrum strains to speed calc
    bFHWA = &bList[15]; // Use FHWA vehicle types
    bHCADT = &bList[16]; // Use HCADT in Spectrum estimate (false = ADT)
    bSeasSpec = &bList[17]; // Seasonal Spectra
    bWIM2Spec = &bList[18]; // Use WIM data to calculate Spectrum
    bUserStruc = &bList[19]; // User changed Structure (don't set default layers)
    bMeanHE = &bList[20]; // Use mean H & E values (instead of reduced for confidence)
    bOverlayRut = &bList[21]; // Show rutting for overlay design
    bOverlayMill = &bList[22]; // Enter milled thickness
    bSIFWD = &bList[23]; // SI units in FWD SIM
    bSILWD = &bList[24]; // SI units in LWD SIM
    bBELLS = &bList[25]; // use BELLS3 calculation for FWD pavement temperature
    bOverBurden = &bList[26]; // use overburden values in simulations
    bOutDamage = &bList[27]; // show damage factor (true = Life)
    bOutZPct = &bList[28]; // specify depth percent for layer simulation results
    bBatchLimits = &bList[29]; // eliminate extreme damage values from batch results
    for(i = 0; i < 5; ++i) {bAggtest[i] = &bList[30+i];}
    for(i = 0; i < 5; ++i) {bSoiltest[i] = &bList[35+i];}
    for(i = 0; i < 5; ++i) {bSeason[i] = &bList[40+i];}
    for(i = 0; i < 7; ++i) {bAxle[i] = &bList[45+i];}
    for(i = 0; i < 5; ++i) {for(j = 0; j < 7; ++j) {bSpecEst[i][j] = &bList[52+i*7+j];}}
    bWidened = &bList[87];
    bTied = &bList[88];

    nFlexLife = &iList[0];
    nFlexLayer = &iList[1];
    nStrucMode = &iList[2];
    nAggTest = &iList[3];
    nSoilTest = &iList[4];
    nCycles = &iList[5];
    nSpecMode = &iList[6];
    nWitczak = &iList[7];
    nCustWheel = &iList[4930];
    nCustAxle = &iList[8];
    nSpecRoad = &iList[9];
    for(i = 0; i < 3; ++i) {nLifts[i] = &iList[10+i];}
    for(i = 0; i < 5; ++i) {nMat[i] = &iList[13+i];}
    for(i = 0; i < 4; ++i) {nEvalZ[i] = &iList[18+i];}
    for(i = 0; i < 4; ++i) {nResponse[i] = &iList[22+i];}
    for(i = 0; i < 4; ++i) {nDirection[i] = &iList[26+i];}
    for(i = 0; i < 4; ++i) {nLocation[i] = &iList[30+i];}
    for(i = 0; i < 6; ++i) {nLoads[i] = &iList[34+i];}
    for(i = 0; i < 8; ++i) {for(j = 0; j < 45; ++j) {nLoadRange[i][j] = &iList[40+i*45+j];}}
    for(k = 0; k < 6; ++k) {for(i = 0; i < 8; ++i) {for(j = 0; j < 45; ++j) {nSeasRange[k][i][j] = &iList[400+k*8*45+i*45+j];}}}
    for(k = 0; k < 6; ++k) {for(i = 0; i < 8; ++i) {for(j = 0; j < 45; ++j) {nWIMRange[k][i][j] = &iList[2560+k*8*45+i*45+j];}}}
    for(k = 0; k < 3; ++k) {for(i = 0; i < 5; ++i) {for(j = 0; j < 12; ++j) {nDet[k][i][j] = &iList[4720+k*5*12+i*12+j];}}} // additional sublayers assigned below
    for(i = 0; i < 3; ++i) {nSpec[i] = &iList[4900+i];}
    for(i = 0; i < 3; ++i) {nNomMax[i] = &iList[4903+i];}
    for(i = 0; i < 3; ++i) {nzT[i] = &iList[4906+i];}
    for(i = 0; i < 3; ++i) {nFWDSIM[i] = &iList[4909+i];}
    nLWDLayer = &iList[4912];
    for(i = 0; i < 5; ++i) {nLWDMoist[i] = &iList[4913+i];}
    nGeogrid = &iList[4918]; // aggregate layer containing geogrid (-1: no geogrid)
    nOtherBit = &iList[4919]; // Bituminous Sublayer (0 = Old HMA, 1 = CIR, 2 = SFDR)
    nFatSel = &iList[4920]; // selected fatigue model (mnpave is the only default model)
    nRutSel = &iList[4921]; // selected rutting model (mnpave is the only default model)
    // End of int imported from MnPAVE 6.4
    nRigidLife = &iList[4922];
    nLanes = &iList[4923];
    nRigidSpec = &iList[4924];
    nJoint = &iList[4925];
    nRigidBase = &iList[4926];
    nRigidHBase = &iList[4927];
    nRigidLayer = &iList[4928];
    nSoil = &iList[4929];
    nConstType = &iList[4931];

    esal = &dList[0]; // ESALs / 1,000,000
    for(i = 0; i < 4; ++i) {for(j = 0; j < 3; ++j) {H[i][j] = &dList[1+i*3+j];}} // next index = 13
    for(i = 0; i < 4; ++i) {HCOV[i] = &dList[13+i];} // next index = 17
    for(i = 0; i < 4; ++i) {for(j = 0; j < 5; ++j) {aggTest[i][j] = &dList[17+i*5+j];}} // next index = 37
    for(i = 0; i < 4; ++i) {for(j = 0; j < 5; ++j) {soilTest[i][j] = &dList[37+i*5+j];}} // next index = 57
    for(i = 0; i < 5; ++i) {otherTest[i] = &dList[57+i];} // next index = 62
    for(i = 0; i < 5; ++i) {for(j = 0; j < 5; ++j) {userE[i][j] = &dList[62+i*5+j];}} // next index = 87
    for(i = 0; i < 5; ++i) {for(j = 0; j < 5; ++j) {userU[i][j] = &dList[87+i*5+j];}} // next index = 112
    for(i = 0; i < 5; ++i) {for(j = 0; j < 5; ++j) {userECOV[i][j] = &dList[112+i*5+j];}} // next index = 137
    for(i = 0; i < 3; ++i) {for(j = 0; j < 14; ++j) {Wit[i][j] = &dList[137+i*14+j];}} // next index = 179
    ipct = &dList[179]; // traffic growth rate
    Va = &dList[180]; // air voids at bottom of HMA (%)
    mph = &dList[181]; // traffic speed
    thawDepth = &dList[182]; // early spring thaw depth
    for(i = 0; i < 5; ++i) {userDur[i] = &dList[183+i];} // next index = 188
    for(i = 0; i < 5; ++i) {userAirT[i] = &dList[188+i];} // next index = 193
    for(i = 0; i < 5; ++i) {userPaveT[i] = &dList[193+i];} // next index = 198
    AADT = &dList[198];
    simConf = &dList[199];
    for(i = 0; i < 3; ++i) {for(j = 0; j < 14; ++j){aWit[i][j] = &dList[200+i*14+j];}} // next index = 242
    for(i = 0; i < 3; ++i) {for(j = 0; j < 2; ++j){bWit[i][j] = &dList[242+i*2+j];}} // next index = 248
    for(i = 0; i < 10; ++i) {pTire[i] = &dList[248+i];} // next index = 258
    for(i = 0; i < 10; ++i) {xSpace[i] = &dList[258+i];} // next index = 268
    for(i = 0; i < 10; ++i) {ySpace[i] = &dList[268+i];} // next index = 278
    for(i = 0; i < 10; ++i) {vMnDOT[i] = &dList[278+i];} // next index = 288
    for(i = 0; i < 10; ++i) {vFHWA[i] = &dList[288+i];} // next index = 298
    for(i = 0; i < 6; ++i) {WIMdays[i] = &dList[298+i];} // next index = 304
    for(i = 0; i < 6; ++i) {for(j = 0; j < 8; ++j) {MohrWtS[i][j] = &dList[304+i*8+j];}} // next index = 352
    for(i = 0; i < 6; ++i) {for(j = 0; j < 2; ++j) {CPhiAggBase[i][j] = &dList[352+i*2+j];}} // next index = 364
    for(i = 0; i < 6; ++i) {for(j = 0; j < 2; ++j) {CPhiSubbase[i][j] = &dList[364+i*2+j];}} // next index = 376
    MohrWt[0] = &dList[376];
    MohrWt[1] = &dList[377];
    MohrP[0] = &dList[378];
    MohrP[1] = &dList[379];
    MohrX[0] = &dList[380];
    MohrX[1] = &dList[381];
    for(i = 0; i < 5; ++i) {UInter[i] = &dList[382+i];} // next index = 387
    for(i = 0; i < 5; ++i) {COVInter[i] = &dList[387+i];} // next index = 392
    for(i = 0; i < 5; ++i) {RFInter[i] = &dList[392+i];} // next index = 397
    for(i = 0; i < 5; ++i) {UOther[i] = &dList[397+i];} // next index = 402
    for(i = 0; i < 3; ++i) {userA[i] = &dList[402+i];} // next index = 405
    for(i = 0; i < 3; ++i) {userVTS[i] = &dList[405+i];} // next index = 408
    for(i = 0; i < 3; ++i) {userKV[i] = &dList[408+i];} // next index = 411
    for(i = 0; i < 4; ++i) {Gamma[i] = &dList[411+i];} // next index = 415
    for(i = 0; i < 4; ++i) {Ko[i] = &dList[415+i];} // next index = 419
    for(i = 0; i < 6; ++i) {FWDSIM[i] = &dList[419+i];} // next index = 425
    for(i = 0; i < 10; ++i) {FWDOffset[i] = &dList[425+i];} // next index = 435
    for(i = 0; i < 3; ++i) {LWDSIM[i] = &dList[435+i];} // next index = 438
    for(i = 0; i < 5; ++i) {LWDmils[i] = &dList[438+i];} // next index = 443
    HMAThreshold = &dList[443];
    SoilThreshold = &dList[444];
    Pt = &dList[445]; //AASHTO terminal serviceability for LEF
    EGeogrid = &dList[446];
    FatMCRel = &dList[447];
    RutMCRel = &dList[448];
    custWt = &dList[449];
    HCADT = &dList[450]; // rigid design
    HPCC = &dList[451];

    tDistrict = &sList[0];
    tCounty = &sList[1];
    tCity = &sList[2];
    tSP = &sList[3];
    tHwy = &sList[4];
    tRP1 = &sList[5];
    tRP2 = &sList[6];
    tConstType = &sList[7];
    tDesigner = &sList[8];
    tSoilsEngineer = &sList[9];
    tNotes = &sList[10];
    for(i = 0; i < 3; ++i) {tSpec[i] = &sList[11+i];} // next index = 14

}

void mnpave::mpSettings(const QString &fileName, const int &nMode)
{
    int i;
    QSettings settings;
    QStringList files = settings.value(RECENT_FILES_KEY).toStringList();

    switch (nMode)
    {
        case READREG:
        {
            tPath = settings.value(DEFAULT_DIR_KEY).toString();
        }
        break;
        case SETREG:
        {
            settings.setValue(DEFAULT_DIR_KEY, QFileInfo(fileName).absolutePath());
            files.removeAll(fileName);
            files.prepend(fileName);
            while (files.size() > MaxRecentFiles)
                files.removeLast();
            settings.setValue(RECENT_FILES_KEY, files);
        }
        break;
        case NOFILE:
        {
            files.removeAll(fileName);
            settings.setValue(RECENT_FILES_KEY, files);
        }
        break;
        case SETBOOL:
        {
            QString tbool = bList[2] ? "1" : "0";
            //qDebug() << tbool;
            settings.setValue(UNITS_SI_KEY, *bsi ? "1" : "0");  //  0 units (False = English, True = SI)
            settings.setValue(WARN_H_KEY, bList[1] ? "1" : "0");    //  1 show thickness warnings
            settings.setValue(WARN_B_KEY, bList[2] ? "1" : "0");    //  2 show binder warnings
            settings.setValue(STRESS_ALWAYS, bList[3] ? "1" : "0"); //  3 always show allowable stress
            settings.setValue(STRESS_FAILED, bList[4] ? "1" : "0"); //  4 only show if failed
            settings.setValue(STRAIN_PERPET, bList[5] ? "1" : "0"); //  5 use all strains (false) or ignore low (true)
            settings.setValue(FWD_E_MEAN, bList[6] ? "1" : "0");    //  6 FWD Emean -2SD (false) or Emean (true)
        }
        case READBOOL:
        {
            *bsi = settings.value(UNITS_SI_KEY).toInt();
            bList[1] = settings.value(WARN_H_KEY).toInt();
            bList[2] = settings.value(WARN_B_KEY).toInt();
            bList[3] = settings.value(STRESS_ALWAYS).toInt();
            bList[4] = settings.value(STRESS_FAILED).toInt();
            bList[5] = settings.value(STRAIN_PERPET).toInt();
            bList[6] = settings.value(FWD_E_MEAN).toInt();
            updateView();
        }
        break;
    }
    // populate recent files in ui
    int nRecentFiles = qMin(files.size(), (int)MaxRecentFiles);

    for(i = 0; i < nRecentFiles; ++i)
    {
        QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName());
        pAction[i]->setText(text);
        pAction[i]->setData(files[i]);
        pAction[i]->setVisible(true);
    }
    for (i = nRecentFiles; i < MaxRecentFiles; ++i)
        pAction[i]->setVisible(false);
}
void mnpave::openRecent()
{
    QAction *action = qobject_cast<QAction *>(sender());
    if(action)
    {
        if(!tName.isEmpty())
        {
            mnpave *other = new mnpave;
            if(other->Read(action->data().toString()))
            {
                other->resize(this->size());
                other->move(this->pos() + QPoint(40,40));
                other->show();
            }
            else
            {
                other->destroy();
                mpSettings(action->data().toString(), NOFILE);
            }
        }
        else
        {
            if(!Read(action->data().toString()))
                mpSettings(action->data().toString(), NOFILE);
        }
    }
}

void mnpave::launchTraffic(int nMode)
{// nMode 0: return spectrum only; 1: launch rigid; 2: launch ESALs; 3: launch flex spec
    int i;
    TrafficDlg tdlg(this);
    tdlg.bsi = *bsi;
    tdlg.bResearch = *bResearch;
    tdlg.bCompound = *bCompound;
    tdlg.bFirstYearESAL = *bFirstYearESAL;
    tdlg.bFHWA = *bFHWA;
    tdlg.nMode = nMode;
    tdlg.nFlexLife = *nFlexLife;
    tdlg.nCustWheel = *nCustWheel;
    tdlg.nCustAxle = *nCustAxle;
    tdlg.ipct = *ipct;
    tdlg.esal = *esal;
    tdlg.esal1 = tdlg.calcESAL(false, *esal);
    tdlg.esalP = *pTire[ESAL];
    tdlg.esalX = *xSpace[ESAL];
    tdlg.HCADT = *HCADT;
    tdlg.custP = *pTire[CUSTOM];
    tdlg.custX = *xSpace[CUSTOM];
    tdlg.custY = *ySpace[CUSTOM];
    tdlg.custWt = *custWt;
    for(i = 0; i < 2; ++i)
    {
        tdlg.mohrP[i] = *MohrP[i];
        tdlg.mohrWt[i] = *MohrWt[i];
        tdlg.mohrX[i] = *MohrX[i];
    }
    for(i = 0; i < 10; ++i)
    {
        tdlg.mndot[i] = *vMnDOT[i];
        tdlg.fhwa[i] = *vFHWA[i];
    }
    tdlg.setWidgets();
    tdlg.setValues();
    *nRigidSpec = tdlg.calcTraffic(-1);
    ui->trafButton1->setText(SPECTXT[*nRigidSpec]);
    if(nMode < 4)
    {
        tdlg.resize(mnpave::size());
        if(tdlg.exec())
        {
            *bCompound = tdlg.bCompound;
            *bFirstYearESAL = tdlg.bFirstYearESAL;
            *bFHWA = tdlg.bFHWA;
            *nCustWheel = tdlg.nCustWheel;
            *nCustAxle = tdlg.nCustAxle;
            *nRigidSpec = tdlg.nRigidSpec;
            *esal = tdlg.esal;
            *pTire[ESAL] = tdlg.esalP;
            *xSpace[ESAL] = tdlg.esalX;
            *pTire[CUSTOM] = tdlg.custP;
            *xSpace[CUSTOM] = tdlg.custX;
            *ySpace[CUSTOM] = tdlg.custY;
            *custWt = tdlg.custWt;
            for(i = 0; i < 2; ++i)
            {
                *MohrP[i] = tdlg.mohrP[i];
                *MohrWt[i] = tdlg.mohrWt[i];
                *MohrX[i] = tdlg.mohrX[i];
            }
            for(i = 0; i < 10; ++i)
            {
                *vMnDOT[i] = tdlg.mndot[i];
                *vFHWA[i] = tdlg.fhwa[i];
            }
            bmodified = true;
        }
    }
}

void mnpave::resizeEvent(QResizeEvent *e)
{// proportional widget resizing
    int ew = e->size().width(); // MainWindow
    int eh = e->size().height();
    int i, nw, nh;
    double ht;
    if(ew >= eh)
    { // Landscape
        nw = LANDW;
        nh = LANDH;
        wRect[61] = QRect(428,10,208,47);   // mptextFrame
        wRect[62] = QRect(428,200,208,200); // outGroup
    }
    else
    { // Portrait
        nw = PORTW;
        nh = PORTH;
        wRect[61] = QRect(4,406,208,47); // relocate mptextFrame
        wRect[62] = QRect(216,406,208,200); // relocate outGroup
    }
    for(i = 0; i < 64; ++i) // resize widgets
        pW[i]->setGeometry(wRect[i].x()*ew/nw, wRect[i].y()*eh/nh, wRect[i].width()*ew/nw, wRect[i].height()*eh/nh);

    // test height/width ratio
    if((double) eh / (double) ew < 0.75) ht = (double) ew * 0.75 / (double) nw * 8.; // new font size
    else ht = (double) eh / (double) nh * 8.; // new font size
    eh = nint(ht);

    QFont newFont = ui->projLabel->font();
    if(eh != newFont.pointSize())
    {
        newFont.setPointSize(eh);
        QApplication::setFont(newFont);
        for(i = 0; i < 5; ++i) pButton[i]->setFont(newFont);
    }
    QMainWindow::resizeEvent(e);
}

void mnpave::paintEvent(QPaintEvent *)
{
    QFont fontmn(mnpave::font().family(), mnpave::font().pointSize(), QFont::Bold);
    QImage mptxt(*bResearch ? ":/images/mptxtRM.png" : ":/images/mptxt.png");
    QImage mn(":/images/mn72.png");
    QPainter painter(this);
    QPen pen, penmn;
    tVersion = QString::number(VERSION-RIGADJ);
    tVersion.insert(1,'.');
    pen.setBrush(Qt::black);
    pen.setWidth(1);
    penmn.setBrush(MNBLUE); // MnDOT blue
    penmn.setWidth(1);
    painter.setPen(pen);
    painter.setBrush(Qt::white);

    // adjust rectangle to fit inside frame
    QPoint mb(ui->menuBar->rect().bottomRight());
    QPoint tb(ui->mainToolBar->rect().bottomRight());
    int gx = ui->mptxtFrame->x();
    int gy = ui->mptxtFrame->y();
    int gw = ui->mptxtFrame->width();
    int gh = ui->mptxtFrame->height();
    int sp = mnpave::font().pointSize();
    gy += mb.y() + tb.y();
    painter.drawImage(gx,gy,mptxt.scaled(gw, gh, Qt::KeepAspectRatio));
    gy += gh;
    gh = 2*sp;
    QRect sr(gx, gy, gw, gh);
    painter.setFont(fontmn);
    painter.drawText(sr, tr("MnDOT %1 Pavement Design").arg(PAVETXT[PAVEMENT]));
    gy += gh;
    sr = QRect(gx, gy, gw, gh);
    painter.setFont(mnpave::font());
    painter.drawText(sr, tr(BETA ? "Beta Version %1, %2 %3" : "Version %1, %2 %3")
                     .arg(BETA ? tVersion: tVersion.left(3), QDate::longMonthName(MONTH), QString::number(YEAR)));
    gy += gh;
    sr = QRect(gx, gy, gw, gh);
    painter.drawText(sr, tr("%1 2001-%2").arg(COPYRIGHT, QString::number(YEAR)));
    gy += sp*7/3;
    painter.drawImage(gx,gy,mn.scaled(sp*6, sp*3, Qt::KeepAspectRatio));
    gx += sp*7;
    gy -= sp/2;
    sr = QRect(gx, gy, sp*18, gh*2); // control text wrapping
    painter.setFont(fontmn);
    painter.setPen(penmn);
    painter.drawText(sr, tr("Department of Transportation"));
}

void mnpave::closeEvent(QCloseEvent *event)
{
    if(bmodified)
    {
        if(askSave())
        {
            mpSettings("", SETBOOL);
            event->accept();
        }
        else event->ignore();
    }
    else
    {
        mpSettings("", SETBOOL);
        event->accept();
    }
}

void mnpave::ctrlkey(int nkey)
{
    QWidget* focused = QApplication::focusWidget();
    if( focused != 0 )
    {
        QApplication::postEvent( focused,
                                 new QKeyEvent( QEvent::KeyPress,
                                                nkey,
                                                Qt::ControlModifier ));
    }
}

void mnpave::updateView()
{   // This will show and hide widgets
    updateMenu();
    updateInfo();
    updateClimate();
    updateTraffic();
    updateStruc();
    updateOutput();
}
void mnpave::updateMenu()
{
    ui->actionEnglish->setChecked(!*bsi);
    ui->actionSI->setChecked(*bsi);
    ui->actionShow_Thickness_Warnings->setChecked(*bHWarn);
    ui->actionShow_Binder_Warnings->setChecked((bBWarn));
    ui->actionAlways_Show_Allowable_Stress->setChecked(*bMohrAlways);
    ui->actionShow_Allowable_Stress_if_Failed->setChecked(*bMohrFail);
    ui->actionDesign->setChecked(!*bResearch);
    ui->actionResearch->setChecked(*bResearch);
    ui->actionESAL->setChecked(!*bSpectrum);
    ui->actionSpectrum->setChecked(*bSpectrum);
    ui->actionUse_All_Strains->setChecked(!*bPerpetual);
    ui->actionPerpetual_Mode->setChecked(*bPerpetual);
}

void mnpave::updateInfo()
{
    ui->constCombo->setCurrentIndex(*nConstType);
    switch(*nConstType)
    {
        case FLEXIBLE: // HMA
        {
            ui->lifeEdit->setText(QString::number(*nFlexLife));
        }
        break;
        case RIGID: // PCC
        {
            ui->lifeEdit->setText(QString::number(*nRigidLife));
        }
        break;
    }
    ui->projEdit->setText(*tSP);
    ui->dateEdit->setDate(vList[0].toDate());
    ui->routeEdit->setText(*tHwy);
    ui->rp1Edit->setText(*tRP1);
    ui->rp2Edit->setText(*tRP2);
    ui->distCombo->setCurrentIndex(nDistrict);
    ui->coCombo->setCurrentIndex(loadCoCombo(nDistrict, nCounty));
    ui->desEdit->setText(*tDesigner);
    ui->senEdit->setText(*tSoilsEngineer);
}
void mnpave::updateClimate()
{
    MapDlg mapd;
    if(*nConstType == FLEXIBLE && *nSoil >= 0 && *nSoil <= 14)
    {
        QString ts = mapd.tSoilClass[*nSoil];
        if(*nSoil == 3)
        {
            ts.remove("ightly");
            ts.remove("astic");
        }
        ui->layerButton4->setText(ts);
        ui->layerButton5->setText(mapd.tSoilClass[*nSoil]);
    }
}
void mnpave::updateTraffic()
{
    if(!*bResearch)
    {
        *bCompound = false;
        *bSpectrum = false;
        *nCustWheel = 2; //dual tire
        *nCustAxle = 0; // ESAL
    }
    ui->trafEdit2->setText(txtdbl(*ipct,1)); // growth rate
    ui->trafCombo3->setItemText(0,*bsi ? "3.7" : "12");
    ui->trafCombo3->setItemText(1,*bsi ? "4.6" : "15");
    ui->trafLabel5u->setText(txtll(*bsi));
    switch(*nConstType)
    {
        case FLEXIBLE: // HMA
        {
            ui->trafEdit1->setEnabled(true);
            ui->trafEdit2->setEnabled(true);
            ui->trafLabel3->setVisible(false);
            ui->trafLabel4->setVisible(false);
            ui->trafLabel5->setVisible(false);
            ui->trafLabel5u->setVisible(false);
            ui->trafCombo1->setVisible(false);
            ui->trafCombo2->setVisible(false);
            ui->trafCombo3->setVisible(false);
            ui->axleButton->setVisible(true);
            ui->axleButton->setText(*bSpectrum ? tr("Load Spectrum") : *nCustAxle == 0 ? tr("ESAL Details") : tr("Axle Details"));
            ui->trafCheck1->setVisible(false);
            ui->trafCheck2->setVisible(false);
            ui->trafLabel1->setText(*nCustAxle == 0 ? tr("Design ESALs") : tr("Repetitions"));
            ui->trafLabel1u->setText("million");
            if(*esal == 0) ui->trafEdit1->setText("");
            else ui->trafEdit1->setText(txtdbl(*esal,3,false,true)); // ESAL
            ui->trafButton1->setVisible(false); // may not be needed
            //ui->trafEdit2->setText(QString::number(*nFlexLife)); // life
        }
        break;
        case RIGID: // PCC
        {
            ui->trafEdit1->setEnabled(true);
            ui->trafEdit2->setEnabled(true);
            ui->trafLabel3->setVisible(true);
            ui->trafLabel4->setVisible(true);
            ui->trafLabel5->setVisible(true);
            ui->trafLabel5u->setVisible(true);
            ui->trafCombo1->setVisible(true);
            ui->trafCombo2->setVisible(*bResearch);
            ui->trafCombo3->setVisible(true);
            ui->axleButton->setVisible(!*bResearch);
            ui->trafCombo2->setCurrentIndex(*nRigidSpec);
            ui->axleButton->setText(ui->trafCombo2->currentText());
            ui->trafCheck1->setVisible(true);
            ui->trafCheck2->setVisible(true);
            ui->trafLabel1->setText("HCADT");
            ui->trafLabel1u->setText("");
            if(*HCADT == 0) ui->trafEdit1->setText("");
            else ui->trafEdit1->setText(txtdbl(*HCADT,3,false,true)); // HCADT
            ui->trafCombo1->setCurrentIndex(*nLanes); // axle load spectra
            ui->trafCombo2->setCurrentIndex(*nRigidSpec); // axle load spectra
            ui->trafCombo3->setCurrentIndex(*nJoint); // joint spacing
            ui->trafCheck1->setChecked(*bWidened); // widened outer lane
            ui->trafCheck2->setChecked(*bTied); // tied PCC shoulder
            ui->trafButton1->setVisible(false); // may not be needed
            calcRigid(false);
        }
        break;
        case 2: // nothing
        {
            ui->trafLabel1->setText("");
            ui->trafLabel1u->setText("");
            ui->trafEdit1->setText("");
            ui->trafEdit2->setText("");
//            ui->trafEdit3->setText("");
            ui->trafEdit1->setEnabled(false);
            ui->trafEdit2->setEnabled(false);
//            ui->trafEdit3->setEnabled(false);
            ui->trafLabel4->setVisible(false);
            ui->trafLabel5->setVisible(false);
            ui->trafLabel5u->setVisible(false);
            ui->trafCombo2->setVisible(false);
            ui->trafCombo3->setVisible(false);
            ui->trafCheck1->setVisible(false);
            ui->trafCheck2->setVisible(false);
        }
        break;
    }
}
void mnpave::updateStruc()
{
    calc c; //enable special functions in calc
    bspin = false; // only check increment for user input
    bool bhma = *nConstType == FLEXIBLE; // true if flexible
    bool bmulti;
    int i, j;
    double min, max, incr, htot;
    ui->strucLabel2->setText(txtl(*bsi));
    pButton[1]->setStyleSheet(c.getPBColor(NYELLOW, 4));
    pButton[2]->setStyleSheet(c.getPBColor(NRED, 4));
    pButton[3]->setStyleSheet(c.getPBColor(NCYAN, 4));
    pButton[4]->setStyleSheet(c.getPBColor(NCYAN, 2));
    switch(*nConstType)
    {
        case FLEXIBLE: // HMA
        {
            ui->strucCombo1->setVisible(true);
            ui->strucButton1->setVisible(true);
            ui->strucCombo1->setCurrentIndex(*nFlexLayer-1);
            pSpin[0]->setVisible(true);
            ui->layerEdit1->setVisible(false);
            pButton[0]->setText("PG 58-34"); // Button text will be automated later
            pButton[0]->setStyleSheet(c.getPBColor(NGRAY, 1));
            pButton[0]->setEnabled(true);
            pButton[1]->setVisible(true);
            ui->layerCombo2->setVisible(false);
            pButton[2]->setEnabled(true);
            pButton[3]->setEnabled(true);
            for(i = 1; i < 4; ++i)
            {
                if(i < *nFlexLayer)
                {
                    pButton[i+1]->setVisible(true);
                    pSpin[i]->setVisible(true);
                }
                else
                {
                    pButton[i+1]->setVisible(false);
                    pSpin[i]->setVisible(false);
                }
            }
            if(nHlab == 2) // COV
            {
                for(i = 0; i < 4; ++i)
                {
                    pSpin[i]->setDecimals(0);
                    pSpin[i]->setValue(rnd2dec(*HCOV[i],0));
                    pSpin[i]->setMinimum(COV_MIN);
                    pSpin[i]->setMaximum(COV_MAX);
                    pSpin[i]->setSingleStep(1);
                    pSpin[i]->setReadOnly(false);
                }
            }
            else // H or adj H
            {
                calc c;
                for(i = 0; i < 4; ++i)
                {
                    pButton[i]->setEnabled(true);
                    if(i == 0) // HMA
                    {
                        min = rnd2dec(convl(false,H_MIN_IN1,*bsi),0);
                        max = rnd2dec(convl(false,H_MAX_IN1,*bsi),0);
                        incr = *bsi ? INCR_MM1 : INCR_IN1;
                    }
                    else
                    {
                        min = rnd2dec(convl(false,H_MIN_IN,*bsi),0);
                        max = rnd2dec(convl(false,H_MAX_IN,*bsi),0);
                        incr = *bsi ? INCR_MM : INCR_IN;
                    }
                    htot = 0;
                    for(j = 0; j < 3; ++j) // sublayers
                    {
                        htot += *H[i][j];
                    }
                    bmulti = htot > *H[i][0];
                    if(nHlab == 1) // adjusted
                    {
                        htot = c.ConfidenceValue(htot,*HCOV[i],*simConf,false);
                    }
                    pSpin[i]->setDecimals(decl(*bsi));
                    pSpin[i]->setMinimum(min);
                    pSpin[i]->setMaximum(max);
                    pSpin[i]->setSingleStep(incr);
                    pSpin[i]->setValue(rnd2dec(convl(false,htot,*bsi),decl(*bsi)));
                    pSpin[i]->setReadOnly(bmulti || nHlab == 1);
                }
            }
        }
        break;
        case RIGID: // PCC
        {
            ui->strucCombo1->setCurrentIndex(*nRigidLayer-1);
            for(i = 1; i < 4; ++i)
            {
                if(i < *nRigidLayer)
                {
                    pButton[i+1]->setVisible(true);
                    pSpin[i]->setVisible(true);
                }
                else
                {
                    pButton[i+1]->setVisible(false);
                    pSpin[i]->setVisible(false);
                }
            }
            pButton[0]->setText("PCC");
            ui->strucCombo1->setCurrentIndex(3);
            for(i = 0; i < 4; ++i)
            {
                pSpin[i]->setDecimals(*bsi ? 0 : 1);
                pSpin[i]->setMinimum(0);
                pSpin[i]->setMaximum(rnd2dec(convl(false,H_MAX_IN,*bsi),0));
                pSpin[i]->setSingleStep(*bsi ? INCR_MM : INCR_IN);
            }
            ui->strucCombo1->setVisible(false);
            ui->strucButton1->setVisible(false);
            nHlab = 0; // thickness only
            pButton[0]->setEnabled(false);
            pSpin[0]->setVisible(false);
            ui->layerEdit1->setVisible(true);
            pButton[1]->setVisible(false);
            ui->layerCombo2->setVisible(true);
            ui->layerCombo2->setEditable(true);
            ui->layerCombo2->lineEdit()->setAlignment(Qt::AlignHCenter);
            ui->layerCombo2->lineEdit()->setReadOnly(true);
            ui->layerCombo2->setCurrentIndex(*nRigidBase);
            pButton[2]->setEnabled(false);
            pButton[3]->setEnabled(false);
            pButton[0]->setStyleSheet(c.getPBColor(NGRAY, 7, true));;
            //pSpin[0]->setValue(rnd2dec(convl(false,*HPCC,*bsi),decl(*bsi,false)));
            switch(*nRigidHBase)
            {
                case 0:
                {
                    pSpin[1]->setValue(*bsi ? 100.0 : 4.0); // mm or in.
                    pSpin[2]->setValue(*bsi ? 300.0 : 12.0); // mm or in.
                }
                break;
                case 1:
                {
                    pSpin[1]->setValue(*bsi ? 300.0 : 12.0); // mm or in.
                    pSpin[2]->setValue(*bsi ? 100.0 : 4.0); // mm or in.
                }
                break;
            }
            pSpin[2]->setReadOnly(false);
            ui->layerSpin4->setVisible(false);
            ui->layerButton5->setVisible(false);
            //pSpin[3]->setReadOnly(true);
        }
        break;
        case 2: // nothing
        {
        }
        break;
    }
    switch(nHlab) // thickness output selection
    {
        case 0: // Thickness
        {
        }
        break;
        case 1: // Adjusted
        {
        }
        break;
        case 2: // COV
        {
        }
        break;
        default:
        {
        }
        break;
    }
    bspin = true;
}

void mnpave::updateOutput()
{
}

void mnpave::loadW()
{// pointers to all widgets for resizing
    pW[0] = ui->infoGroup;
    pW[1] = ui->constCombo;
    pW[2] = ui->lifeLabel;
    pW[3] = ui->lifeEdit;
    pW[4] = ui->lifeLabelu;
    pW[5] = ui->projLabel;
    pW[6] = ui->dateLabel;
    pW[7] = ui->projEdit;
    pW[8] = ui->dateEdit;
    pW[9] = ui->routeLabel;
    pW[10] = ui->routeEdit;
    pW[11] = ui->rpLabel;
    pW[12] = ui->rp1Edit;
    pW[13] = ui->toLabel;
    pW[14] = ui->rp2Edit;
    pW[15] = ui->distLabel;
    pW[16] = ui->coLabel;
    pW[17] = ui->distCombo;
    pW[18] = ui->coCombo;
    pW[19] = ui->mapButton;
    pW[20] = ui->climateButton;
    pW[21] = ui->desLabel;
    pW[22] = ui->desEdit;
    pW[23] = ui->senLabel;
    pW[24] = ui->senEdit;
    pW[25] = ui->notesButton;
    pW[26] = ui->trafGroup;
    pW[27] = ui->trafLabel1;
    pW[28] = ui->trafEdit1;
    pW[29] = ui->trafLabel1u;
    pW[30] = ui->trafLabel2;
    pW[31] = ui->trafEdit2;
    pW[32] = ui->trafLabel2u;
    pW[33] = ui->trafLabel3;
    pW[34] = ui->trafCombo1;
    pW[35] = ui->trafLabel4;
    pW[36] = ui->trafCombo2;
    pW[37] = ui->axleButton;
    pW[38] = ui->trafLabel5;
    pW[39] = ui->trafCombo3;
    pW[40] = ui->trafLabel5u;
    pW[41] = ui->trafCheck1;
    pW[42] = ui->trafCheck2;
    pW[43] = ui->trafButton1;
    pW[44] = ui->strucGroup;
    pW[45] = ui->strucCombo1;
    pW[46] = ui->strucButton1;
    pW[47] = ui->StrucHLabel;
    pW[48] = ui->strucLabel1;
    pW[49] = ui->strucLabel2;
    pW[50] = ui->layerButton1;
    pW[51] = ui->layerSpin1;
    pW[52] = ui->layerEdit1;
    pW[53] = ui->layerButton2;
    pW[54] = ui->layerCombo2;
    pW[55] = ui->layerSpin2;
    pW[56] = ui->layerButton3;
    pW[57] = ui->layerSpin3;
    pW[58] = ui->layerButton4;
    pW[59] = ui->layerSpin4;
    pW[60] = ui->layerButton5;
    pW[61] = ui->mptxtFrame;
    pW[62] = ui->outGroup;
    pW[63] = ui->calcButton;
// geometries
    wRect[0] = QRect(4,4,208,396);
    wRect[1] = QRect(9,18,190,22);
    wRect[2] = QRect(10,46,70,20);
    wRect[3] = QRect(86,46,54,20);
    wRect[4] = QRect(146,46,52,20);
    wRect[5] = QRect(10,69,100,16);
    wRect[6] = QRect(120,69,78,16);
    wRect[7] = QRect(8,88,104,20);
    wRect[8] = QRect(118,88,82,20);
    wRect[9] = QRect(10,114,60,20);
    wRect[10] = QRect(76,114,124,20);
    wRect[11] = QRect(10,140,188,16);
    wRect[12] = QRect(8,159,80,20);
    wRect[13] = QRect(94,159,20,20);
    wRect[14] = QRect(120,159,80,20);
    wRect[15] = QRect(10,185,56,16);
    wRect[16] = QRect(76,185,116,16);
    wRect[17] = QRect(9,208,60,22);
    wRect[18] = QRect(75,208,118,22);
    wRect[19] = QRect(8,240,72,24);
    wRect[20] = QRect(86,240,108,24);
    wRect[21] = QRect(10,272,188,16);
    wRect[22] = QRect(8,291,192,20);
    wRect[23] = QRect(10,317,188,16);
    wRect[24] = QRect(8,336,192,20);
    wRect[25] = QRect(8,364,192,24);
    wRect[26] = QRect(216,4,208,190);
    wRect[27] = QRect(10,18,80,20);
    wRect[28] = QRect(96,18,54,20);
    wRect[29] = QRect(156,18,42,20);
    wRect[30] = QRect(10,42,80,20);
    wRect[31] = QRect(96,42,54,20);
    wRect[32] = QRect(156,42,42,20);
    wRect[33] = QRect(10,66,142,22);
    wRect[34] = QRect(158,66,40,22);
    wRect[35] = QRect(10,92,64,22);
    wRect[36] = QRect(80,92,118,22);
    wRect[37] = QRect(80,92,114,22);
    wRect[38] = QRect(10,118,84,22);
    wRect[39] = QRect(100,118,46,22);
    wRect[40] = QRect(152,118,46,22);
    wRect[41] = QRect(10,144,124,16);
    wRect[42] = QRect(10,166,124,16);
    wRect[43] = QRect(140,142,60,40);
    wRect[44] = QRect(216,200,208,200);
    wRect[45] = QRect(10,18,100,22);
    wRect[46] = QRect(116,18,84,24);
    wRect[47] = QRect(130,22,60,16);
    wRect[48] = QRect(12,46,120,16);
    wRect[49] = QRect(142,46,52,16);
    wRect[50] = QRect(10,64,124,24);
    wRect[51] = QRect(140,64,58,24);
    wRect[52] = QRect(140,64,42,24);
    wRect[53] = QRect(10,90,124,24);
    wRect[54] = QRect(10,90,124,24);
    wRect[55] = QRect(140,90,58,24);
    wRect[56] = QRect(10,116,124,24);
    wRect[57] = QRect(140,116,58,24);
    wRect[58] = QRect(10,142,124,24);
    wRect[59] = QRect(140,142,58,24);
    wRect[60] = QRect(10,168,124,24);
    wRect[61] = QRect(428,10,208,47);
    wRect[62] = QRect(428,200,208,200);
    wRect[63] = QRect(10,20,120,40);
}

void mnpave::calcRigid(bool bmsg)
{
    QString ttmp = checkRigidData();
    if(ttmp != "")
    {
        *HPCC = 0.0;
        ui->layerEdit1->setText(*bsi ? "0" : "0.0");
        if(bmsg)
        {
            QMessageBox msg;
            msg.setText(ttmp);
            msg.exec();
        }
        return;
    }
    calc c;
    int i;
    QString ss, tmsg;
    TrafficDlg traf;
    int rign[7]; //index values to query data
    double rigd[4];
    if(nDistrict < 6) rign[0] = nDistrict; // climate = district
    else rign[0] = 6; // Dist 7 & 8 have RDF climate
    if(*nRigidSpec == 2) rign[1] = 0; // MEPDG
    else rign[1] = *nRigidSpec + 1; // load spectrum
    rign[2] = *bWidened ? 1 : 0; // widened outside lane
    rign[3] = *nJoint; // joint spacing (0=12, 1=15)
    rign[4] = *bTied ? 1 : 0; // tied PCC shoulders
    rign[5] = *nRigidBase; // Base
    rign[6] = *nRigidHBase; // HBase
    double mdtmp[9]; // array to pass into adjHCADT
    for(i = 0; i < 9; ++i) mdtmp[i] = *vMnDOT[i];
    HCADTadj = traf.adjHCADT(mdtmp, *HCADT);
    rigd[0] = *HCADT * HCADTadj; // hcadt, adjusted if necessary
    rigd[1] = desLane(*nLanes); // percent traffic in design lane
    rigd[2] = (double) *nRigidLife; // deslife
    rigd[3] = *ipct; // growth;
    *HPCC = c.calcRigid(rign, rigd, &trucks, &reliability, &cracked); // need trucks for MnPAVE-Rigid Design Summary
    //pSpin[0]->setValue(rnd2dec(convl(false,*HPCC,*bsi),decl(*bsi,false)));
    if(HCADTadj > 1.0)
    {
        ui->axleButton->setText(SPECTXT[2] + "*");
        ui->axleButton->setToolTip(tr("Effective HCADT = HCADT * %1 due to 5+ Axle Max vehicles.").arg(txtdbl(HCADTadj,3)));
    }
    else
    {
        ui->axleButton->setText(SPECTXT[*nRigidSpec]);
        ui->axleButton->setToolTip("");
    }
    ui->layerEdit1->setText(txtdbl(convl(false,*HPCC,*bsi),decl(*bsi,false)));
}

bool mnpave::Open()
{
    QString tOpenFile = QFileDialog::getOpenFileName(this, tr("Open %1 File").arg(APP),
                                          tPath, tr("%1 Files (*.%2)").arg(APP).arg(APPEXT));
    if (tOpenFile.isEmpty()) return false;
    else return Read(tOpenFile);
}

bool mnpave::askSave()
{
    QMessageBox::StandardButton ret;
    ret = QMessageBox::warning(this, QApplication::applicationName(),
        tr("The document has been modified.") + "\n"
        + tr("Do you want to save your changes?"),
        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    if(ret == QMessageBox::Yes) return Save(tFile);
    else if(ret == QMessageBox::Cancel) return false;
    else return true;
}

bool mnpave::Save(const QString &fileName)
{
    if(!fileName.isEmpty()) return Write(fileName);
    else return SaveAs(fileName);
}

bool mnpave::SaveAs(const QString &fileName)
{
    mpSettings("", READREG);
    QString newName = fileName;
    if(newName.isEmpty()) newName = tName;
    if(newName.isEmpty()) newName = sList[0].isEmpty() ? QApplication::applicationName() + "1" : sList[0];
    newName = QFileDialog::getSaveFileName(this, tr("Save %1 File").arg(APP),
                                 tPath + "/" + newName, tr("%1 Files (*.%2)").arg(APP).arg(APPEXT));
    if(!newName.isEmpty()) return Write(newName);
    else return false;
}

bool mnpave::Write(const QString &fileName)
{
    QSaveFile mFile(fileName);
    mFile.setFileName(fileName);
    mFile.setDirectWriteFallback(true);

    if(!mFile.open(QFile::WriteOnly))
    {
        QMessageBox msgBox;
        msgBox.setText(tr("File could not be saved."));
        msgBox.exec();
        return false;
    }
    QDataStream out(&mFile);

    // Keep datastream version consistent to prevent Read errors when Qt is updated
    out.setVersion(QDataStream::Qt_5_7); // this is consistent with the static version (5.7.1)
    // Create header with verification number and version number
    out << qint32(0xb0071ace);
    out << nVersion;

    out << bList; // QList of bool
    out << iList; // QList of int
    out << dList; // QList of double
    out << sList; // QList of QString
    out << vList; // QList of QVariant

    bool bcom = mFile.commit();
    if(bcom)
    {
        QFileInfo mInfo(fileName);
        tName = mInfo.fileName();
        tFile = fileName;
        updateView();
        bmodified = false;
        mpSettings(fileName, SETREG);
        mnpave::setWindowTitle(newWinTitle(tName));
    }
    return bcom;
}

bool mnpave::Read(const QString &fileName)
{// To do: update window title
    int i;
    int n = 0;
    QMessageBox msg;
    bopen = false;
    QFile mFile(fileName);
    if(!mFile.open(QFile::ReadOnly))
    {
        msg.setText(tr("File not found."));
        msg.exec();
        return false;
    }
    QDataStream in(&mFile);

    // Verify header information
    qint32 verify, version;
    in >> verify;
    if(verify == 0xb0071ace)
    {
        // Get Qt version
        int qver = in.version(); // binary serialization version

        in >> version;
        if(version > nVersion)
        {
            QMessageBox msgBox;
            msgBox.setTextFormat(Qt::RichText);
            msgBox.setText(tr("This file is from a newer version of mnpave."
                              "<br>Please update to the current version at"
                              "<br><a href=\"http://www.dot.state.mn.us/app/mnpave/\">"
                              "www.dot.state.mn.us/app/mnpave</a>"));
            msgBox.exec();
            return false;
        }
        if(version < nVersion)
        {// or if(version < 7000), if(version >= 7009)...
            // update values if necessary
        }

        in >> bList; // QList of bool
        in >> iList; // QList of int
        in >> dList; // QList of double
        in >> sList; // QList of QString
        in >> vList; // QList of QVariant

        mFile.close();
        assignPointers(); // pointers need to be reassigned after import
    }
    else
    {
        mFile.close();
        QFile txtFile(fileName);
        txtFile.open(QIODevice::ReadOnly);
        QXmlStreamReader xml(&txtFile);
        xml.readNext();
        i = 0;
        while(xml.name() != "verify" && i < 10)
        {
            i += 1;
            xml.readNext();
        }
        verify = xml.readElementText().toInt();
        if(verify == 0x0B501E7E)
        {// text file exported from MnPAVE 6.4
            while(xml.name() != "bList") xml.readNext();
            foreach(const QXmlStreamAttribute &attr, xml.attributes())
            {
                if(attr.name().toString() == QLatin1String("size"))
                {//note: QLatin1String is needed because the above const does not accept unicode.
                    n = attr.value().toInt(); // number of elements
                }
            }
           // qDebug() << QString::number(n);
            for(i = 0; i < n; ++i)
            {
                xml.readNextStartElement();
                bList[i] = xml.readElementText().toInt();
            } // xml code completed to here in MnPAVE 6.4
            while(xml.name() != "iList") xml.readNext();
            foreach(const QXmlStreamAttribute &attr, xml.attributes())
            {
                if(attr.name().toString() == QLatin1String("size"))
                {//note: QLatin1String is needed because the above const does not accept unicode.
                    n = attr.value().toInt(); // number of elements
                }
            }
            for(i = 0; i < n; ++i)
            {
                xml.readNextStartElement();
                iList[i] = xml.readElementText().toInt();
            }

            while(xml.name() != "dList") xml.readNext();
            foreach(const QXmlStreamAttribute &attr, xml.attributes())
            {
                if(attr.name().toString() == QLatin1String("size"))
                {//note: QLatin1String is needed because the above const does not accept unicode.
                    n = attr.value().toInt(); // number of elements
                }
            }
            for(i = 0; i < n; ++i)
            {
                xml.readNextStartElement();
                dList[i] = xml.readElementText().toDouble();
            }

            while(xml.name() != "sList") xml.readNext();
            foreach(const QXmlStreamAttribute &attr, xml.attributes())
            {
                if(attr.name().toString() == QLatin1String("size"))
                {//note: QLatin1String is needed because the above const does not accept unicode.
                    n = attr.value().toInt(); // number of elements
                }
            }
            for(i = 0; i < n; ++i)
            {
                xml.readNextStartElement();
                sList[i] = xml.readElementText();
            }

            while(xml.name() != "vList") xml.readNext();
            foreach(const QXmlStreamAttribute &attr, xml.attributes())
            {
                if(attr.name().toString() == QLatin1String("size"))
                {//note: QLatin1String is needed because the above const does not accept unicode.
                    n = attr.value().toInt(); // number of elements
                }
            }
            int ntmp[n];
            for(i = 0; i < n; ++i)
            {
                xml.readNextStartElement();
                ntmp[i] = xml.readElementText().toDouble();
            }
            vList[0] = QDate(ntmp[0], ntmp[1], ntmp[2]);
            vList[1] = QPointF(ntmp[5] + ntmp[6]/60., ntmp[3] + ntmp[4]/60.);
            if (xml.hasError())
            {
                QMessageBox msgBox;
                msgBox.setText(tr("xml error"));
                msgBox.exec();
                return false;
            }
            // Convert Custom Axle info
            if(*nCustAxle > 3)
            {
                *nCustAxle -= 3;
                *nCustWheel = 1; // custom axles 4-6 were super single, tandem & tridem
            }
            else *nCustWheel = 2; // dual tire
            *custWt *= EN3; // convert from lbs to kips
            if(*custWt == 0.) *custWt = 18.;
            // Import MnDOT vehicles into new format
            *vMnDOT[4] += *vMnDOT[5]; // old Classes 8 & 9 (5 & 6 axle semis) are now combined
            *vMnDOT[8] = *vMnDOT[7]; // Classes 10 & 11 are shifted to make room for new 9a & 9b
            *vMnDOT[7] = *vMnDOT[6];
            *vMnDOT[5] = *vMnDOT[6] = 0.0; // new Classes 9a & 9b (5+ Max & 5+ Other)
            tName = QFileInfo(fileName).fileName();
            QMessageBox msgBox;
            msgBox.setText(tr("File imported successfully."));
            msgBox.exec();
            txtFile.close();
            *nConstType = 0; // Flexible (Asphalt)
            bxml = true;
        }
        else
        {
            QMessageBox msgBox;
            msgBox.setText(tr("Incorrect file format.%1Code %2").arg("\n").arg(QString::number(verify)));
            msgBox.exec();
            txtFile.close();
            return false;
        }
    }
    QFileInfo mInfo(fileName);
    tName = mInfo.fileName();
    tFile = fileName;
    bopen = true;
    MapDlg mapd;
    QPoint xy = mapd.ll2xy(vList[1].toPointF());
    nDistrict = mapd.getDistrictIndex(MASKD.pixel(xy));
    nCounty = mapd.getCountyIndex(MASKC.pixel(xy));
    updateView();
    if(*nConstType == RIGID)
    {
        //pButton[1]->setText(RBASE[*nRigidBase]);
        ui->layerCombo2->setCurrentIndex(*nRigidBase);
        calcRigid(false);
    }
    bmodified = bxml; // prompt to save if xml was imported
    bxml = false;
    mpSettings(fileName, SETREG);
    mnpave::setWindowTitle(newWinTitle(tName));
    return true;
}

QString mnpave::newWinTitle(const QString &tTitle)
{
//    QString ttmp = QApplication::applicationName() + " " + txtdbl((double) nint((double) (nVersion*.01))*.1, 1);
    QString ttmp = APPTITLE + " " + PAVETXT[PAVEMENT] + " " + txtdbl((double) (VERSION-RIGADJ)*EN3,1);
    if(!tTitle.isEmpty())
    {
        ttmp = ttmp + " - " + tTitle;
    }
    return ttmp;
}

int mnpave::loadCoCombo(int ndist, int nco)
{
    int i, i87, imax;
    int i20 = -1; // indicates if a new index isn't assigned
    // fill county combo
    ui->coCombo->clear();
    MapDlg mnmap;
    if(ndist == 8) // no district selected
    {
        for(i = 0; i < 87; ++i)
        {
            ui->coCombo->addItem(mnmap.getCountyName(i));
        }
        return nco;
    }
    else
    {
        for(i = 0; i < 20; ++i)
        {
            i87 = mnmap.getCounty(ndist, i);
            if(i87 >= 0)
            {
                imax = i;
                ui->coCombo->addItem(mnmap.getCountyName(i87));
            }
            // get CurSel
            if(i87 == nco) i20 = i; // new index of the county already selected
        }
        if(i20 < 0) i20 = imax+1; // select blank selection if selected county isn't in the new district
    }
    return i20;
}

double mnpave::desLane(int nLanes)
{
    double pctTrucks[] = {100.,90.,70.,60.};
    return pctTrucks[nLanes];
}

QString mnpave::checkRigidData()
{
    QString tmsg = "";
    if(*nRigidLife <= 0) tmsg = ("Enter a value for Design Life.\n");
    if(nDistrict < 0 || nDistrict > 7) tmsg += tr("Select a District.\n");
    if(*HCADT <= 0.) tmsg += ("Enter a value for HCADT.");
    return tmsg;
}

// Private Slots

void mnpave::on_actionCreate_PDF_Report_triggered()
{   // font: 72 pts/in; pdf: 1200 pixels/in
    QString ttmp = checkRigidData();
    if(ttmp != "")
    {
        QMessageBox msg;
        msg.setText(ttmp);
        msg.exec();
        return;
    }
    else calcRigid(false);
    if(tName.isEmpty()) on_actionSave_triggered();
    mpSettings("", READREG);
    ttmp = tName.left(tName.length()-4);
    QString newName = ttmp + tr(" Report.pdf");
    // Use file dialog to prompt if file exists already
    if(tName.isEmpty()) newName = QApplication::applicationName() + QApplication::applicationVersion() + " Report";
    newName = QFileDialog::getSaveFileName(this, tr("Save") + " PDF " + tr("Report"),
                           tPath + "/" + newName, "PDF " + tr("Files") + " (*.pdf)");
     if(!newName.isEmpty())
     {
        QPdfWriter mpdf(newName);
        mpdf.setPageSize(QPagedPaintDevice::Letter);
        mpdf.setPageMargins(QMarginsF(72,54,54,54)); // L 1", R,T,B 0.75"
        mpdf.setTitle(newWinTitle("") + " " + tr("Report"));
        mpdf.newPage();
        QDateTime now;

        QPainter painter(&mpdf);
        QFont arial6("Arial"); //disclaimer
        arial6.setPointSize(6);
        QFont arial10("Arial");
        arial10.setPointSize(10);
        QFont arial14("Arial");
        arial14.setPointSize(14);
        QFont arial14B("Arial");
        arial14B.setPointSize(14);
        arial14B.setBold(true);
        QFont arial16("Arial");
        arial16.setPointSize(16);
        QFont arial16B("Arial");
        arial16B.setPointSize(16);
        arial16B.setBold(true);
        QFont arial18("Arial");
        arial18.setPointSize(18);
        arial18.setBold(true);
        QTextOption tleft, tcenter, tright;
        tleft.setAlignment(Qt::AlignLeft);
        tcenter.setAlignment(Qt::AlignCenter);
        tright.setAlignment(Qt::AlignRight);
        QPen pen;
        pen.setBrush(Qt::black);
        pen.setWidth(8);
        painter.setPen(pen);
        QPoint pt1, pt2;
        QRect txrect;
        int top, bot, wid, ht, h10, h14, h16, h18;
        top = 0;
        //wid = 8400; // 7"
        wid = 7800; // 6.5"
        ht = 11400; // 9.5"
        h10 = 200; // row height
        h14 = 300;
        h16 = 400;
        h18 = 500;

        top = pdfRect(&txrect,wid,top,h18,1,0);
        QImage mdlogo(":/images/mndotLogo.png");
        painter.drawImage(txrect.topLeft(),mdlogo.scaled(txrect.width(), txrect.height(), Qt::KeepAspectRatio));

        top += h10;

        painter.setFont(arial14B);
        bot = pdfRect(&txrect,wid,top,h16,1,0); // "bot" keeps the next section on the same line
        ttmp = tr("%1 %2 %3 Design Summary").arg(APPTITLE, PAVETXT[PAVEMENT], txtdbl((double) (VERSION-RIGADJ)*EN3,1));
        painter.drawText(txrect,ttmp,tleft);

        painter.setFont(arial10);
        ttmp = tr("Created %1").arg(now.currentDateTime().toLocalTime().toString(Qt::SystemLocaleShortDate));
        top = pdfRect(&txrect,wid,top,h16,3,2); // "top" advances the next section to a new line
        painter.drawText(txrect,ttmp,tright);

        top = pdfRect(&txrect,wid,top,h16,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2); // center vertically
        ttmp = tr("%1 %2 File%3").arg(APPTITLE, PAVETXT[PAVEMENT], ": "); // put punctuation & spaces outside of translation to avoid errors
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,tName);

        top = pdfRect(&txrect,wid,top,h18,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h18/2); // center vertically
        ttmp = tr("Calculated thickness%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = QString("%1 %2").arg(ui->layerEdit1->text(), txtl(*bsi));
        pt1 = mpText(&painter,arial16,pt1,ttmp);

        painter.setFont(arial16B);
        top = pdfRect(&txrect,wid,top,h18,1,0);
        painter.drawText(txrect,"Main Inputs",tleft);
        painter.drawLine(txrect.topLeft(), txrect.topRight());

        painter.setFont(arial14);
        bot = pdfRect(&txrect,wid,top,h16,9,40); // 9 columns, merge 1-5
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2); // center vertically
        ttmp = tr("Design life%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("%1 years").arg(QString::number(*nRigidLife));
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85); // 9 columns, merge 6-9
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2); // center vertically
        ttmp = tr("Climate (MnDOT district)%1").arg(":  ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,DISTRICT[ui->distCombo->currentIndex()]);

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2); // center vertically
        ttmp = tr("Initial 2-way traffic%1").arg(":  ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("%1 HCADT%2").arg(txtdbl(*HCADT,0), HCADTadj > 1.0 ? "*" : "");
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2); // center vertically
        ttmp = tr("Linear traffic growth%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,txtdbl(*ipct,1));

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Axle load spectra%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,SPECTXT[*nRigidSpec]);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Number of lanes (2-way)%1").arg(":  ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,ui->trafCombo1->currentText());

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Base material%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("%1 Aggregate").arg(ui->layerCombo2->currentText());
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Base thickness%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("%1 %2").arg(txtdbl(ui->layerSpin2->value(),decl(*bsi,false)), txtl(*bsi));
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Subbase material%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("Select Granular");
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Subbase thickness%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("%1 %2").arg(txtdbl(ui->layerSpin3->value(),decl(*bsi,false)), txtl(*bsi));
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Joint spacing%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = QString("%1 %2").arg(ui->trafCombo3->currentText(), txtll(*bsi));
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Widened lane%1").arg("? ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = *bWidened ? tr("Yes") : tr("No");
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        top = pdfRect(&txrect,wid,top,h16,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Shoulder type%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = *bTied ? tr("Tied PCC") : tr("HMA, Untied PCC, or Aggregate");
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        top += 200;

        painter.setFont(arial16B);
        top = pdfRect(&txrect,wid,top,h18,1,0);
        painter.drawText(txrect,"Defaults",tleft);
        painter.drawLine(txrect.topLeft(), txrect.topRight());

        top = pdfRect(&txrect,wid,top,h16,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Reliability analysis%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = tr("Monte Carlo (MnPAVE Flexible)");
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Allowable cracked slabs%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = QString("%1%").arg(cracked);
        pt1 = mpText(&painter,arial14,pt1,ttmp);
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Reliability level%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = QString("%1%").arg(reliability);
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        top = pdfRect(&txrect,wid,top,h16,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Flexural strength%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = *bsi ? "4480 kPa" : "650 psi";
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("COV, PCC thickness%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,"3.0%");
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("COV, Flexural strength%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,"8.6%");

        bot = pdfRect(&txrect,wid,top,h16,9,40);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("MEPDG coefficient 1%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,"0.90");
        top = pdfRect(&txrect,wid,top,h16,9,85);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("MEPDG coefficient 2%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,"-2.64");

        top = pdfRect(&txrect,wid,top,h16,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Calculated total trucks over service life%1").arg(":  ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        ttmp = txtdbl(trucks,0,false,false,true);
        pt1 = mpText(&painter,arial14,pt1,ttmp);

        top += 200;

        top = pdfRect(&txrect,wid,top,h10,1,0);
        painter.drawLine(txrect.topLeft(), txrect.topRight());

        top = pdfRect(&txrect,wid,top,h14,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Designer%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        pt1 = mpText(&painter,arial14,pt1,*tDesigner);

        top = pdfRect(&txrect,wid,top,h14,1,0);
        pt1 = QPoint(txrect.left(), txrect.top()+h16/2);
        ttmp = tr("Notes%1").arg(": ");
        pt1 = mpText(&painter,arial14B,pt1,ttmp);
        if(HCADTadj > 1.0) bot = ht-top-h18-h14; // reusing bot for notes height
        else bot = ht-top-h18; // no need to leave space for HCADT*
        top = pdfRect(&txrect,wid,top,bot,1,0);
        painter.setFont(arial10);
        painter.drawText(txrect,*tNotes,tleft);

// footer
        painter.setFont(arial6);
        top = pdfRect(&txrect,wid,ht-h18,h18,1,0);
        painter.drawText(txrect,tDisclaimer,tleft);

        painter.setFont(arial10);
        top = pdfRect(&txrect,wid,top-h18-h14,h10,1,0);
        if(HCADTadj > 1.0) ttmp = tr("%1Effective HCADT = %2 due to 5+ Axle Max vehicles (adjustment factor = %3)")
                .arg("*", txtdbl(*HCADT * HCADTadj, 0), txtdbl(HCADTadj, 3));
        else ttmp = "";
        painter.drawText(txrect,ttmp,tleft);
        painter.end();


        //Open file with default PDF application
        QDesktopServices::openUrl((QUrl("file:/" + newName)));
     }
}

void mnpave::on_constCombo_activated(int index)
{
    if(index != *nConstType)
    {
        *nConstType = index;
        updateView();
        bmodified = true;
    }
}

void mnpave::on_lifeEdit_textEdited(const QString &arg1)
{
    if(*nConstType == FLEXIBLE) *nFlexLife = arg1.toInt(); // HMA life
    else if(*nConstType == RIGID)
    {
        *nRigidLife = arg1.toInt(); // PCC life
        pSpin[0]->setValue(0.0);
    }
    bmodified = true;
}

void mnpave::on_lifeEdit_editingFinished()
{
    updateView();
}

void mnpave::on_projEdit_textEdited(const QString &arg1)
{
    *tSP = arg1;
    bmodified = true;
}

void mnpave::on_dateEdit_userDateChanged(const QDate &date)
{
    vList[0] = date;
    bmodified = true;
}

void mnpave::on_routeEdit_textEdited(const QString &arg1)
{
    *tHwy = arg1;
    bmodified = true;
}

void mnpave::on_rp1Edit_textEdited(const QString &arg1)
{
    *tRP1 = arg1;
    bmodified = true;
}

void mnpave::on_rp2Edit_textEdited(const QString &arg1)
{
    *tRP2 = arg1;
    bmodified = true;
}

void mnpave::on_distCombo_activated(int index)
{
    if(index != nDistrict && index < 8)
    {
        MapDlg mapd;
        nDistrict = index;
        if(*nConstType == RIGID)
        {// set default county
            nCounty = DISTCO[nDistrict];
            calcRigid(false);
        }
        vList[1] = mapd.xy2ll(mapd.getCountyPoint(nDistrict, nCounty));
        updateView();
        bmodified = true;
    }
}

void mnpave::on_coCombo_activated(int index)
{
    if(index != nCounty)
    {
        MapDlg mapd;
        if(nDistrict < 0 || nDistrict > 7) // no district selected
        {
            nCounty = index;
            nDistrict = mapd.getDistrict(nCounty,0);
            updateView();
        }
        else
        {
            nCounty = mapd.getCounty(nDistrict, index);
            updateView();
        }
        vList[1] = mapd.xy2ll(mapd.getCountyPoint(nDistrict, nCounty));
        bmodified = true;
    }
}

void mnpave::on_mapButton_clicked()
{
    MapDlg mapd(this);
    mapd.bClick = true;
    mapd.mapll = vList[1].toPointF();
    mapd.setvalues();
    mapd.resize(mnpave::size());
    mapd.setWindowTitle(tr("Map of Minnesota Districts and Counties"));
    if(mapd.exec() && (mapd.nDistrictSel != nDistrict || mapd.nCountySel != nCounty
                       || (mapd.bSoil && mapd.nSoilSel != *nSoil)))
    {
        if(mapd.nDistrictSel > -1 && mapd.nCountySel > -1)
        {
            nDistrict = mapd.nDistrictSel;
            nCounty = mapd.nCountySel;
            if(mapd.bSoil && mapd.nSoilSel >= 0 && mapd.nSoilSel <= 14) *nSoil = mapd.nSoilSel;
            else *nSoil = -1;
        }
        else
        {
            nDistrict = 8; // All
            nCounty = -1; // none
        }
        vList[1] = mapd.mapll;
        updateView();
        bmodified = true;
    }
}

void mnpave::on_climateButton_clicked()
{
    ClimateDlg cdlg(this);
    cdlg.resize(mnpave::size());
    if(cdlg.exec())
    {
        updateView();
        bmodified = true;
    }
}

void mnpave::on_desEdit_textEdited(const QString &arg1)
{
    *tDesigner = arg1;
    bmodified = true;
}

void mnpave::on_senEdit_textEdited(const QString &arg1)
{
    *tSoilsEngineer = arg1;
    bmodified = true;
}

void mnpave::on_notesButton_clicked()
{
    NotesDlg notes;
    notes.setWindowTitle(tr("%1 %2 Notes").arg(APPTITLE,PAVETXT[PAVEMENT]));
    notes.tNotes = *tNotes;
    notes.loadText();
    // set proportional size but keep aspect ratio
    notes.resize(QSize(ui->mptxtFrame->width()*1.6, ui->mptxtFrame->width()*1.2));
    if(notes.exec())
    {
        if(notes.tNotes != *tNotes)
        {
            *tNotes = notes.tNotes;
            bmodified = true;
        }
    }
}

void mnpave::on_trafEdit1_textEdited(const QString &arg1)
{
    if(*nConstType == FLEXIBLE) *esal = arg1.toDouble(); // ESAL
    else if(*nConstType == RIGID)
    {
        *HCADT = arg1.toDouble(); // HCADT
        *HPCC = 0.0;
        ui->layerEdit1->setText(*bsi ? "0" : "0.0");
    }
    bmodified = true;
}

void mnpave::on_trafEdit1_editingFinished()
{
    updateView();
    calcRigid(false);
}

void mnpave::on_trafEdit2_textEdited(const QString &arg1)
{
    *ipct = arg1.toDouble(); // traffic growth rate
    if(*nConstType == RIGID)
    {
        *HPCC = 0.0;
        ui->layerEdit1->setText(*bsi ? "0" : "0.0");
    }
    bmodified = true;
}

void mnpave::on_trafEdit2_editingFinished()
{
    updateView();
    calcRigid(false);
}

void mnpave::on_trafCombo1_activated(int index)
{
    if(index != *nLanes)
    {
        *nLanes = index;
        if(*nConstType == RIGID) calcRigid(false);
        bmodified = true;
    }
}

void mnpave::on_trafCombo2_activated(int index)
{
    if(index != *nRigidSpec)
    {
        *nRigidSpec = index;
        if(*nConstType == RIGID) calcRigid(false);
        bmodified = true;
    }
}

void mnpave::on_trafCombo3_activated(int index)
{
    if(index != *nJoint)
    {
        *nJoint = index;
        if(*nConstType == RIGID) calcRigid(false);
        bmodified = true;
    }
}

void mnpave::on_axleButton_clicked()
{
    if(*nConstType == FLEXIBLE) launchTraffic(*bSpectrum ? 3 : 2); // rigid spec not used in flexible design
    else launchTraffic(0);
    updateTraffic();
}

void mnpave::on_trafCheck1_clicked(bool checked)
{
    *bWidened = checked;
    if(*nConstType == RIGID) calcRigid(false);
    bmodified = true;
}

void mnpave::on_trafCheck2_clicked(bool checked)
{
    *bTied = checked;
    if(*nConstType == RIGID) calcRigid(false);
    bmodified = true;
}

void mnpave::on_trafButton1_clicked()
{// may not be needed
}

void mnpave::on_calcButton_clicked()
{
    switch(*nConstType)
    {
        case FLEXIBLE:
        {
        //    weslea w;
        //    w.calcwes();
        }
        break;
        case RIGID:
        {
            calcRigid(true);
        }
        break;
    }
    bmodified = true;

}

void mnpave::on_strucCombo1_currentIndexChanged(int index)
{
    if(*nConstType == 0) *nFlexLayer = index+1; // HMA layers
    else if(*nConstType == 1) *nRigidLayer = index+1; // PCC layers
    updateView();
    bmodified = true;
}

void mnpave::on_actionHelp_Topics_triggered()
{// create a modeless help window
    QFile hfile(DEFHELP);
    if(!hfile.exists())
    {
        QMessageBox msg;
        msg.setText(tr("Help file could not be located."));
        msg.exec();
    }
    else
    {
        HelpDlg *hlp = new HelpDlg(this);
        hlp->setWindowTitle(APPTITLE + " " + tr("Help"));
        hlp->resize(mnpave::size());
        hlp->show();
    }
}

void mnpave::on_strucButton1_clicked()
{
    QString lyrlab[3] = {"Thickness", "Adjusted", "COV"};
    nHlab = nHlab < 2 ? nHlab+1 : 0;
    ui->strucButton1->setText(lyrlab[nHlab]);
    updateStruc();
}

void mnpave::on_layerButton1_clicked()
{
    LayerDlg ldlg(this);
    ldlg.resize(mnpave::size());
    ldlg.bResearch = *bResearch;

    if(ldlg.exec())
    {
        updateStruc();
        bmodified = true;
    }
}

void mnpave::on_layerButton2_clicked()
{
	LayerDlg ldlg(this);
	if(ldlg.exec())
	{
		updateStruc();
		bmodified = true;
	}
}

void mnpave::on_layerCombo2_activated(int index)
{
    *nRigidBase = index;
    calcRigid(false);
}

void mnpave::on_layerButton3_clicked()
{
    LayerDlg ldlg(this);
    if(ldlg.exec())
    {
        updateStruc();
        bmodified = true;
    }
}

void mnpave::on_layerButton4_clicked()
{
    LayerDlg ldlg(this);
    if(ldlg.exec())
    {
        updateStruc();
        bmodified = true;
    }
}

void mnpave::on_layerButton5_clicked()
{
    LayerDlg ldlg(this);
    if(ldlg.exec())
    {
        updateStruc();
        bmodified = true;
    }
}

void mnpave::on_layerSpin1_valueChanged(double arg1)
{
    if(*nConstType == FLEXIBLE)
    {
        if(bspin)
        {
            switch(nHlab)
            {
                case 0:
                {
                    *H[0][0] = convl(*bsi,arg1);
                }
                break;
                case 2:
                {
                    *HCOV[0] = arg1;
                }
                break;
            }
            bmodified = true;
        }
    }
}

void mnpave::on_layerSpin2_valueChanged(double arg1)
{
    if(bspin)
    {
        switch(*nConstType)
        {
            case FLEXIBLE: // flexible
            {
                switch(nHlab)
                {
                    case 0:
                    {
                        *H[1][0] = convl(*bsi,arg1);
                    }
                    break;
                    case 2:
                    {
                        *HCOV[1] = arg1;
                    }
                    break;
                }
                bmodified = true;
            }
            break;
            case RIGID: // rigid
            {
                val[1] = rnd2dec(convl(*bsi,arg1),0); // switch values between 4 & 12"
                *nRigidHBase = val[1] == 4.0 || (val[1] > 8.0 && val[1] != 12.0) ? 0 : 1;
                updateStruc();
                calcRigid(false);
            }
            break;
        }
    }
}

void mnpave::on_layerSpin3_valueChanged(double arg1)
{
    if(bspin)
    {
        switch(*nConstType)
        {
            case FLEXIBLE: // flexible
            {
                switch(nHlab)
                {
                    case 0:
                    {
                        *H[2][0] = convl(*bsi,arg1);
                    }
                    break;
                    case 2:
                    {
                        *HCOV[2] = arg1;
                    }
                    break;
                }
                bmodified = true;
            }
            break;
            case RIGID: // rigid
            {
                val[2] = rnd2dec(convl(*bsi,arg1),0); // switch values between 4 & 12"
                *nRigidHBase = val[2] == 4.0 || (val[2] > 8.0 && val[2] != 12.0) ? 1 : 0;
                updateStruc();
                calcRigid(false);
            }
            break;
        }
    }
}

void mnpave::on_layerSpin4_valueChanged(double arg1)
{
    if(bspin)
    {
        switch(nHlab)
        {
            case 0:
            {
                *H[3][0] = convl(*bsi,arg1);
            }
            break;
            case 2:
            {
                *HCOV[3] = arg1;
            }
            break;
        }
        bmodified = true;
    }
}

void mnpave::on_actionNew_triggered()
{
    // Create a new window
        mpSettings("", SETBOOL); // make same settings as open document
        mnpave *other = new mnpave;
        other->resize(this->size());
        other->move(this->pos() + QPoint(40,40));
        other->show();
}

void mnpave::on_actionOpen_triggered()
{
    mpSettings("", READREG);
// File opens in a new window unless the old window is unmodified
    if(!tName.isEmpty())
    {
        mnpave *other = new mnpave;
        other->mpSettings("", READREG);
        if(other->Open())
        {
            other->resize(this->size());
            other->move(this->pos() + QPoint(40,40));
            other->show();
        }
        else other->destroy();
    }
    else Open();
}

void mnpave::on_actionClose_triggered()
{
    mnpave::close();
}

void mnpave::on_actionSave_triggered()
{
    Save(tFile);
}

void mnpave::on_actionSave_As_triggered()
{
    SaveAs(tFile);
}

void mnpave::on_action1_triggered()
{
    openRecent();
}

void mnpave::on_action2_triggered()
{
    openRecent();
}

void mnpave::on_action3_triggered()
{
    openRecent();
}

void mnpave::on_action4_triggered()
{
    openRecent();
}

void mnpave::on_action5_triggered()
{
    openRecent();
}

void mnpave::on_action6_triggered()
{
    openRecent();
}

void mnpave::on_actionExit_triggered()
{
    if(bmodified)
    {
        if(askSave()) qApp->exit();
    }
    else qApp->exit();
}

void mnpave::on_actionCut_triggered()
{
    ctrlkey(Qt::Key_X);
}

void mnpave::on_actionCopy_triggered()
{
    ctrlkey(Qt::Key_C);
}

void mnpave::on_actionPaste_triggered()
{
    ctrlkey(Qt::Key_V);
}

void mnpave::on_actionEnglish_triggered()
{
    *bsi = false;
    ui->actionSI->setChecked(false);
    updateTraffic();
    updateStruc();
    updateOutput();
    bmodified = true;
}

void mnpave::on_actionSI_triggered()
{
    *bsi = true;
    ui->actionEnglish->setChecked(false);
    updateTraffic();
    updateStruc();
    updateOutput();
    bmodified = true;
}

void mnpave::on_actionShow_Binder_Warnings_triggered()
{
    *bBWarn = !*bBWarn;
    ui->actionShow_Binder_Warnings->setChecked(*bBWarn);
    bmodified = true;
}

void mnpave::on_actionShow_Thickness_Warnings_triggered()
{
    *bHWarn = !*bHWarn;
    ui->actionShow_Thickness_Warnings->setChecked(*bHWarn);
    bmodified = true;
}

void mnpave::on_actionAlways_Show_Allowable_Stress_triggered()
{
    *bMohrAlways = !*bMohrAlways;
    ui->actionAlways_Show_Allowable_Stress->setChecked(*bMohrAlways);
    if(*bMohrAlways && *bMohrFail)
    {
        *bMohrFail = false;
        ui->actionShow_Allowable_Stress_if_Failed->setChecked(false);
    }
    bmodified = true;
}

void mnpave::on_actionShow_Allowable_Stress_if_Failed_triggered()
{
    *bMohrFail = !*bMohrFail;
    ui->actionShow_Allowable_Stress_if_Failed->setChecked(*bMohrFail);
    if(*bMohrFail && *bMohrAlways)
    {
        *bMohrAlways = false;
        ui->actionAlways_Show_Allowable_Stress->setChecked(false);
    }
    bmodified = true;
}

void mnpave::on_actionDesign_triggered()
{
    *bResearch = false;
    bmodified = true;
    updateMenu();
    updateView();
    repaint();
}

void mnpave::on_actionResearch_triggered()
{
    *bResearch = true;
    bmodified = true;
    updateMenu();
    updateView();
    repaint();
}

void mnpave::on_actionAbout_mnpave_triggered()
{
    AboutDlg about;
    about.setWindowTitle(tr("About %1 %2").arg(APPTITLE,PAVETXT[PAVEMENT]));
    // set proportional size but keep aspect ratio
    about.resize(QSize(ui->mptxtFrame->width()*1.6, ui->mptxtFrame->width()*1.2));
    about.exec();
}
