static void OnAirspaceListEnter(WindowControl * Sender, WndListFrame::ListInfo_t *ListInfo) { if (ItemIndex != -1) { if ((UpLimit-LowLimit>0) && (ItemIndex >= 0) // JMW fixed bug, was >0 && (ItemIndex < (UpLimit - LowLimit))) { const size_t i = (FullFlag) ? StrIndex[LowLimit + ItemIndex] : (LowLimit + ItemIndex); CAirspace *airspace = AirspaceSelectInfo[i].airspace; if (airspace) { if(airspace->Enabled()) { LKSound(TEXT("LK_BEEP0.WAV")); CAirspaceManager::Instance().AirspaceDisable(*airspace); }else{ LKSound(TEXT("LK_BEEP1.WAV")); CAirspaceManager::Instance().AirspaceEnable(*airspace); } } } } }
static void OnEnableClicked(WndButton* pWnd) { if (ItemIndex != -1) { const size_t i = (FullFlag) ? StrIndex[LowLimit + ItemIndex] : (LowLimit + ItemIndex); if ((UpLimit-LowLimit>0) && (ItemIndex >= 0) // JMW fixed bug, was >0 && (ItemIndex < (UpLimit - LowLimit))) { CAirspace *airspace = AirspaceSelectInfo[i].airspace; if (airspace) { wf->SetTimerNotify(0,NULL); LKSound(TEXT("LK_TICK.WAV")); CAirspaceManager::Instance().PopupAirspaceDetail(airspace); } } } else { if(pWnd) { WndForm * pForm = pWnd->GetParentWndForm(); if(pForm) { pForm->SetModalResult(mrCancel); } } } }
static void OnPILOTClicked(WndButton* pWnd) { RUN_MODE = RUN_PILOT; LKSound(_T("LK_SLIDE.WAV")); if(pWnd) { WndForm * pForm = pWnd->GetParentWndForm(); if(pForm) { pForm->SetModalResult(mrOK); } } }
static void OnCloseClicked(WindowControl * Sender){ (void)Sender; if (EnableSoundModes) LKSound(_T("LK_SLIDE.WAV")); switch(RUN_MODE) { case RUN_DUALPROF: RUN_MODE=RUN_WELCOME; break; } wf->SetModalResult(mrOK); }
static void OnNickelClick(WndButton* pWnd) { RUN_MODE = RUN_EXIT; RestartToNickel = true; LKSound(_T("LK_SLIDE.WAV")); if(pWnd) { WndForm * pForm = pWnd->GetParentWndForm(); if(pForm) { pForm->SetModalResult(mrOK); } } }
// // We do Sonar from draw thread, because it is reasonable to think that without a visual aid on map, // the simple sonar sound alone is an halved solution. // void MapWindow::DoSonar(void) { static unsigned long lSonarCnt = 0; if (!SonarWarning || DrawInfo.NAVWarning || !EnableSoundModes)return; CAirspace *aspfound = CAirspaceManager::Instance().GetNearestAirspaceForSideview(); if( aspfound == NULL ) { #if DEBUG_SONAR StartupStore(_T("SONAR: no aspfound, return\n")); #endif return; } CAirspace near_airspace; near_airspace = CAirspaceManager::Instance().GetAirspaceCopy(aspfound); // we dont use these at all bool bAS_Inside; int iAS_HorDistance=5000; int iAS_Bearing=0; int iAS_VertDistance=0; if ( near_airspace.GetDistanceInfo(bAS_Inside, iAS_HorDistance, iAS_Bearing, iAS_VertDistance) ) { int iSonarLevel=0; if(ISCAR||ISGAAIRCRAFT||SIMMODE||DerivedDrawInfo.FreeFlying) { AirSpaceSideViewSTRUCT tmpasp; tmpasp.psAS = &near_airspace; iSonarLevel = CalcSonarDelay( 1, &tmpasp, (int)DerivedDrawInfo.AltitudeAGL, (int)DerivedDrawInfo.NavAltitude); #if DEBUG_SONAR StartupStore(_T(".. iSonarLevel=%d\n"),iSonarLevel); #endif lSonarCnt++; if((iSonarLevel >=0) && (iSonarLevel < 10)) { if( lSonarCnt > (unsigned)sSonarLevel[iSonarLevel].iSoundDelay) { lSonarCnt = 0; // StartupStore(_T("... level=%d PLAY <%s>\n"),iSonarLevel,&sSonarLevel[iSonarLevel].szSoundFilename); LKSound((TCHAR*) &(sSonarLevel[iSonarLevel].szSoundFilename)); } } } } #if DEBUG_SONAR else StartupStore(_T("SONAR: no near_airspace, return\n")); #endif }
// warning, TODO FIX, calling AddMessage from wrong thread? CHECK BOOL NMEAParser::PDSXT(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { TCHAR mbuf[300]; if ( _tcslen(params[0]) >0) _stprintf(mbuf,_T("MESSAGE FROM <%s>: %s"), params[0], params[1]); else _stprintf(mbuf,_T("MESSAGE: %s"),params[1] ); Message::AddMessage(30000, 3, mbuf); LKSound(TEXT("LK_TONEUP.WAV")); return TRUE; }
static void OnCloseClicked(WndButton* pWnd) { LKSound(_T("LK_SLIDE.WAV")); switch (RUN_MODE) { case RUN_DUALPROF: RUN_MODE = RUN_WELCOME; break; } if(pWnd) { WndForm * pForm = pWnd->GetParentWndForm(); if(pForm) { pForm->SetModalResult(mrOK); } } }
void AlertGateOpen(int gate) { TCHAR tag[100] ={0}; if (gate == (PGNumberOfGates-1)) { // LKTOKEN _@M372_ = "LAST GATE IS OPEN" _tcsncpy(tag,gettext(TEXT("_@M372_")), array_size(tag)-1); } else { _sntprintf(tag, array_size(tag)-1, _T("%s %d of %d %s"), // LKTOKEN _@M315_ = "GATE" gettext(TEXT("_@M315_")), gate+1, PGNumberOfGates, // LKTOKEN _@M347_ = "IS OPEN" gettext(TEXT("_@M347_"))); } DoStatusMessage(tag); LKSound(_T("LK_GATEOPEN.WAV")); }
// Warn about an old locked zombie back visible void CheckBackTarget(NMEA_INFO *pGPS, int flarmslot) { if ( pGPS->FLARM_Traffic[flarmslot].Locked ) return; if ( pGPS->FLARM_Traffic[flarmslot].Status != LKT_ZOMBIE ) return; // if more than 15 minutes ago, warn pilot with full message and sound if ( (pGPS->Time - pGPS->FLARM_Traffic[flarmslot].Time_Fix) >=900) { // LKTOKEN _@M674_ = "TARGET BACK VISIBLE" DoStatusMessage(gettext(TEXT("_@M674_"))); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(_T("TARGVISIBLE.WAV")); #endif } else { // otherwise a simple sound #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_DRIP")); #endif } }
// warning, TODO FIX, calling AddMessage from wrong thread? CHECK BOOL NMEAParser::PDSXT(TCHAR *String, TCHAR **params, size_t nparams, NMEA_INFO *pGPS) { TCHAR mbuf[300]; if ( _tcslen(params[0]) >0) wsprintf(mbuf,_T("MESSAGE FROM <%s>: %s"), params[0], params[1]); else wsprintf(mbuf,_T("MESSAGE: %s"),params[1] ); Message::Lock(); // 091211 Message::AddMessage(30000, 3, mbuf); Message::Unlock(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(TEXT("LK_TONEUP.WAV")); #endif return TRUE; }
FlarmIdFile::FlarmIdFile(void) { TCHAR path[MAX_PATH]; LKSound(_T("LK_CONNECT.WAV")); TCHAR flarmIdFileName[MAX_PATH] = TEXT("\0"); #if NOSIM if (SIMMODE) return; #else #ifdef _SIM_ return; #endif #endif LocalPath(path); wsprintf(flarmIdFileName, TEXT("%s\\%s\\%s"), path, TEXT(LKD_CONF), TEXT(LKF_FLARMNET)); FILE* hFile = _wfopen(flarmIdFileName, TEXT("rt")); if (hFile == NULL) { wsprintf(flarmIdFileName, TEXT("%s\\%s\\data.fln"), path, TEXT(LKD_CONF)); hFile = _wfopen(flarmIdFileName, TEXT("rt")); if (hFile == NULL) return; } DWORD fileLength; fseek (hFile , 0 , SEEK_END); fileLength = ftell (hFile); fseek (hFile , 7 , SEEK_SET); int itemCount = 0; while( ( (signed)fileLength - ftell(hFile)) > 87) { FlarmId *flarmId = new FlarmId; GetItem(hFile, flarmId); flarmIds[flarmId->GetId()] = flarmId; itemCount++; } FlarmNetCount=itemCount; fclose(hFile); }
void AlertGateOpen(int gate) { TCHAR tag[30]; if (gate == (PGNumberOfGates-1)) { // LKTOKEN _@M372_ = "LAST GATE IS OPEN" _tcscpy(tag,gettext(TEXT("_@M372_"))); } else { _stprintf(tag,_T("%s %d of %d %s"), // LKTOKEN _@M315_ = "GATE" gettext(TEXT("_@M315_")), gate+1, PGNumberOfGates, // LKTOKEN _@M347_ = "IS OPEN" gettext(TEXT("_@M347_"))); } DoStatusMessage(tag); if (EnableSoundModes) { LKSound(_T("LK_GATEOPEN.WAV")); } }
bool DetectFreeFlying(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { static bool ffDetected=false; static int lastMaxAltitude=-1000; static double gndAltitude=0; static double vario[8]; static bool winchdetected=false; static short wlaunch=0; static int altLoss=0; static bool safeTakeoffDetected=false; static bool nowGearWarning = true; // init with true to prevent gear warning just after free flight detect static unsigned short noMessages =0; bool forcereset=LKSW_ForceFreeFlightRestart; if (DoInit[MDI_DETECTFREEFLYING]) { for (int i=0; i<8; i++) vario[i]=0; gndAltitude=0; winchdetected=false; wlaunch=0; altLoss=0; ffDetected=false; lastMaxAltitude=-1000; safeTakeoffDetected=false; nowGearWarning=true; // we are here before freeflight! noMessages=0; // after a new takeoff we can give warnings again! DoInit[MDI_DETECTFREEFLYING]=false; } // reset on ground if (Calculated->Flying == false) { Calculated->FreeFlying=false; ffDetected=false; lastMaxAltitude=-1000; // For winch launches and also for quick taekoffs do not update gndAltitude when the plane // is already moving, probably towed or winched already. Threshold is at 4m/s, = 14kmh if (Basic->Speed<=4.0) gndAltitude=Basic->Altitude; winchdetected=false; wlaunch=0; altLoss=FF_TOWING_ALTLOSS; safeTakeoffDetected=false; LKSW_ForceFreeFlightRestart=false; return false; } if (forcereset) { LKSW_ForceFreeFlightRestart=false; #if TESTBENCH StartupStore(_T("... Forced FreeFlight Restart!\n")); #endif DoStatusMessage(MsgToken(1452),NULL,false); // LKTOKEN _@M1452_ = "Free flight detected" goto confirmbacktrue; } // If we have a takeoff alarm, and it is still pending! // The AlarmTakeoffSafety is saved multiplied by 1000, so conversion between feet and meters will always be // accurate and possible with no safety concerns about loosing accuracy on this issue! if ( (AlarmTakeoffSafety>0) && !safeTakeoffDetected ) { // Only if not in SIMMODE, or in SIM but replaying a flight if ( !(SIMMODE && !ReplayLogger::IsEnabled()) ) { if ( (Basic->Altitude - gndAltitude)>=(AlarmTakeoffSafety/1000)) { LKSound(_T("LK_SAFETAKEOFF.WAV")); safeTakeoffDetected=true; } } } #ifdef GEAR_WARNING if ( (GearWarningMode>0) && ffDetected) { // Only if not in SIMMODE, or in SIM but replaying a flight // if ( !(SIMMODE && !ReplayLogger::IsEnabled()) ) { double AltitudeAGL = Calculated->AltitudeAGL; double dist = 0; if(GearWarningMode ==1){ if( ValidWayPoint(BestAlternate)) { AltitudeAGL = Basic->Altitude - WayPointList[BestAlternate].Altitude; // AGL = height above landable if( AltitudeAGL <= (GearWarningAltitude/1000)) DistanceBearing(Basic->Latitude, Basic->Longitude, WayPointList[BestAlternate].Latitude, WayPointList[BestAlternate].Longitude, &dist, NULL); }else{ dist = 9999; // set to far away if best alternate not valid } } if (( AltitudeAGL <=(GearWarningAltitude/1000)) && (noMessages < MAX_NO_GEAR_WARN)) { if(!nowGearWarning) { if(dist < 3700) // show gear warning if 2Nautical Miles close to landable { LKSound(_T("LK_GEARWARNING.WAV")); DoStatusMessage(gettext(TEXT("_@M1834_")),NULL,false); // LKTOKEN _@M1834_ "Prepare for landing !" nowGearWarning=true; noMessages++; #if TESTBENCH if(GearWarningMode ==2) StartupStore(_T("... %i. Gear warning at %im = %im [%im] AGL%s"),noMessages,(int)Basic->Altitude,(int)AltitudeAGL,(int)GearWarningAltitude/1000,NEWLINE); else StartupStore(_T("...%i. Gear warning at %im = %im [%im] over landable %s (%im)%s"),noMessages,(int)Basic->Altitude,(int)AltitudeAGL,(int)GearWarningAltitude/1000,WayPointList[BestAlternate].Name,(int)WayPointList[BestAlternate].Altitude,NEWLINE); #endif } if (noMessages==MAX_NO_GEAR_WARN) { StartupStore(_T("... GOING SILENT on too many Gear warnings. %s%s"),WhatTimeIsIt(),NEWLINE); DoStatusMessage(MsgToken(2304)); // GOING SILENT ON GEAR REPORTING noMessages++; // we go to 11, and never be back here } } } } else { if(( AltitudeAGL)> ((GearWarningAltitude/1000)+100)) // re-enable warning if higher that 100m above Gear altitude { if( nowGearWarning ) { #if TESTBENCH if(GearWarningMode ==2) StartupStore(_T("...rearmed %i. Gear warning at %im = %im AGL %s"),noMessages,(int)Basic->Altitude,(int)AltitudeAGL,NEWLINE); else StartupStore(_T("..rearmed %i. Gear warning at %im = %im over landable %s (%im)%s"),noMessages,(int)Basic->Altitude,(int)AltitudeAGL,WayPointList[BestAlternate].Name,(int)WayPointList[BestAlternate].Altitude,NEWLINE); #endif nowGearWarning = false; } } } } } #endif if (ISPARAGLIDER) { Calculated->FreeFlying=true; return true; } if (ISGAAIRCRAFT||ISCAR) { return false; } // do something special for other situations if (SIMMODE && !ReplayLogger::IsEnabled()) { Calculated->FreeFlying=true; ffDetected=true; return true; } // If flying, and start was already detected, assume valid freeflight. // Put here in the future the Engine Noise Detection for motorplanes if (ffDetected) return true; // Here we are flying, and the start of free flight must still be detected // In any case, after this time, force a start. This is to avoid that for any reason, no FF is ever detected. if ((int)Basic->Time > ( Calculated->TakeOffTime + FF_MAXTOWTIME)) { #if DEBUG_DFF DoStatusMessage(_T("DFF: TIMEOUT")); #endif goto backtrue; // unconditionally force start FF } // A loss of altitude will trigger FF lastMaxAltitude = std::max(lastMaxAltitude, (int)Basic->Altitude); if ((int)Basic->Altitude <= ( lastMaxAltitude - altLoss)) { #if DEBUG_DFF if ( (winchdetected) || ((Basic->Altitude - gndAltitude)>=400) && ((Basic->Time - Calculated->TakeOffTime) >= 150)) DoStatusMessage(_T("DFF: ALTITUDE LOSS")); #endif goto lastcheck; } #ifdef TOW_CRUISE // If circling, we assume that we're in free flight and use the // start-of-circling time and position. Turning.cpp makes sure // we aren't circling while on tow by imposing a 12 deg/sec turn // rate limit for on-tow turning. #else // If circling we assume that we are in free flight already, using the start of circling time and position. // But we must be sure that we are not circling.. while towed. A 12 deg/sec turn rate will make it quite sure. // Of course nobody can circle while winchlaunched, so in this case FF is immediately detected. #endif #ifdef TOW_CRUISE // The 12 deg/sec check is now done in Turning.cpp, so there's no // need to do it here, too. Doing it here, too, could allow the // possibility of climb mode engaging without FF detection, if the // climb rate goes above 12 deg/sec for just a split second. //if (Calculated->Circling && (winchdetected || // (fabs(Calculated->TurnRate) >= 12))) { if (Calculated->Circling) { #else if (Calculated->Circling && ( winchdetected || ( fabs(Calculated->TurnRate) >=12 ) ) ) { #endif if (UseContestEngine()) { CContestMgr::Instance().Add(new CPointGPS(static_cast<unsigned>(Calculated->ClimbStartTime), Calculated->ClimbStartLat, Calculated->ClimbStartLong, static_cast<unsigned>(Calculated->ClimbStartAlt))); } #if DEBUG_DFF DoStatusMessage(_T("DFF: THERMALLING")); #endif goto backtrue; } vario[7]=vario[6]; vario[6]=vario[5]; vario[5]=vario[4]; vario[4]=vario[3]; vario[3]=vario[2]; vario[2]=vario[1]; vario[1]=Calculated->Vario; double newavervario; double oldavervario; newavervario=(vario[1]+vario[2]+vario[3])/3; if (newavervario>=10) { wlaunch++; } else { wlaunch=0; } // After (6+2) 8 seconds of consecutive fast climbing (AFTER TAKEOFF DETECTED!), winch launch is detected if (wlaunch==6) { #if DEBUG_DFF DoStatusMessage(_T("DFF: WINCH LAUNCH")); #endif altLoss=FF_WINCHIN_ALTLOSS; winchdetected=true; } if (newavervario>0.3) return false; if (newavervario<=0) { #if DEBUG_DFF if ( (winchdetected) || ((Basic->Altitude - gndAltitude)>=400) && ((Basic->Time - Calculated->TakeOffTime) >= 150)) DoStatusMessage(_T("DFF: VARIO SINK")); #endif goto lastcheck; } oldavervario=(vario[4]+vario[5]+vario[6]+vario[7])/4; // current avervario between 0.0 and 0.3: uncertain situation, we check what we had in the previous time // Windy situations during towing may lead to false positives if delta is too low. This is the most // difficult part which could lead to false positives or negatives. if ( oldavervario >=4.5 ) { #if DEBUG_DFF StartupStore(_T("..... oldavervario=%.1f newavervario=%.1f current=%.1f\n"),oldavervario,newavervario,Calculated->Vario); if ( (winchdetected) || ((Basic->Altitude - gndAltitude)>=400) && ((Basic->Time - Calculated->TakeOffTime) >= 150)) DoStatusMessage(_T("DFF: DELTA VARIO")); #endif goto lastcheck; } // No free flight detected return false; lastcheck: // Unless under a winch launch, we shall not consider anything below 400m gain, // and before 2.5minutes have passed since takeoff // Anybody releasing tow before 3 minutes will be below 500m QFE, and won't go much around // until a thermal is found. So no problems. if (!winchdetected) { if ( (Basic->Altitude - gndAltitude)<400) return false; if ( (Basic->Time - Calculated->TakeOffTime) < 150) return false; } backtrue: // In real flight on a fly device (assuming a windowsPC is NOT a fly device) // give no messages during critical phases of flight #if ( !defined(WINDOWSPC) || WINDOWSPC==0 ) if (SIMMODE) #endif DoStatusMessage(gettext(TEXT("_@M1452_")),NULL,false); // LKTOKEN _@M1452_ = "Free flight detected" confirmbacktrue: // Always sound if (EnableSoundModes) { LKSound(_T("LK_FREEFLIGHT.WAV")); } StartupStore(_T(". Free Flight started %s%s"), WhatTimeIsIt(),NEWLINE); ffDetected=true; Calculated->FreeFlying=true; Calculated->FreeFlightStartTime=Basic->Time; Calculated->FreeFlightStartQNH=Basic->Altitude; Calculated->FreeFlightStartQFE=gndAltitude; WayPointList[RESWP_FREEFLY].Latitude=Basic->Latitude; WayPointList[RESWP_FREEFLY].Longitude=Basic->Longitude; WayPointList[RESWP_FREEFLY].Altitude=Basic->Altitude; if (WayPointList[RESWP_FREEFLY].Altitude==0) WayPointList[RESWP_FREEFLY].Altitude=0.001; WayPointList[RESWP_FREEFLY].Reachable=TRUE; WayPointList[RESWP_FREEFLY].Visible=TRUE; WayPointList[RESWP_FREEFLY].Format = LKW_VIRTUAL; TCHAR Temp[30]; Units::TimeToTextS(Temp, (int)TimeLocal((long)Calculated->FreeFlightStartTime)); LKASSERT(WayPointList[RESWP_FREEFLY].Comment!=NULL); WayPointList[RESWP_FREEFLY].Comment[99]='\0'; // for safety _stprintf(WayPointList[RESWP_FREEFLY].Comment,_T("%s: %s @%.0f%s QNH"), gettext(_T("_@M1754_")), // Free flight start Temp, ALTITUDEMODIFY*Calculated->FreeFlightStartQNH, Units::GetAltitudeName()); ResetFreeFlightStats(Calculated); return true; } // // Upon FF detection, we reset some calculations, ONLY SOME. // Most things are pertinent to flying, not to freeflying. // // Notice 1: we cannot do oldstyle reset, because it would reset also takeoff time. // For FF, we need new stuff doing new things. // Notice 2: GA and CAR mode will not ever use FF stuff // // Notice 3: since FF is not (still) affecting tasks, we shall not reset task values now // void ResetFreeFlightStats(DERIVED_INFO *Calculated) { int i; CContestMgr::Instance().Reset(Handicap); flightstats.Reset(); Calculated->timeCruising = 0; Calculated->timeCircling = 0; // Calculated->TotalHeightClimb = 0; // Calculated->CruiseStartTime = -1; // // ClimbStartTime CANNOT be reset here: it is a loop! We use themal start to detect freeflight! // We have a conflict here! // Calculated->ClimbStartTime = -1; // Calculated->AverageThermal = 0; for (i=0; i<200; i++) { Calculated->AverageClimbRate[i]= 0; Calculated->AverageClimbRateN[i]= 0; } Calculated->MaxThermalHeight = 0; for (i=0; i<NUMTHERMALBUCKETS; i++) { Calculated->ThermalProfileN[i]=0; Calculated->ThermalProfileW[i]=0; } // clear thermal sources for first time. for (i=0; i<MAX_THERMAL_SOURCES; i++) { Calculated->ThermalSources[i].LiftRate= -1.0; } // The MaxHeightGain function wait for FF in flight and will update // considering 0 as a no-altitude-set-yet . Calculated->MinAltitude = 0; Calculated->MaxAltitude = 0; Calculated->MaxHeightGain = 0; }
void MapWindow::RenderMapWindowBg(HDC hdc, const RECT rc, const POINT &Orig, const POINT &Orig_Aircraft) { HFONT hfOld; // Calculations are taking time and slow down painting of map, beware #define MULTICALC_MINROBIN 5 // minimum split #define MULTICALC_MAXROBIN 20 // max split static short multicalc_slot=0;// -1 (which becomes immediately 0) will force full loading on startup, but this is not good // because currently we are not waiting for ProgramStarted=3 // and the first scan is made while still initializing other things // TODO assign numslots with a function, based also on available CPU time short numslots=1; #if NEWSMARTZOOM static double quickdrawscale=0.0; static double delta_drawscale=1.0; #endif // If we have a BigZoom request, we serve it immediately without calculating anything // TODO: stretch the old map bitmap to the new zoom, while fastzooming if (QUICKDRAW) { goto fastzoom; } if (NumberOfWayPoints>200) { numslots=NumberOfWayPoints/400; // keep numslots optimal if (numslots<MULTICALC_MINROBIN) numslots=MULTICALC_MINROBIN; // seconds for full scan, as this is executed at 1Hz if (numslots>MULTICALC_MAXROBIN) numslots=MULTICALC_MAXROBIN; // When waypointnumber has changed, we wont be using an exceeded multicalc_slot, which would crash the sw // In this case, we shall probably continue for the first round to calculate without going from the beginning // but this is not a problem, we are round-robin all the time here. if (++multicalc_slot>numslots) multicalc_slot=1; } else { multicalc_slot=0; // forcing full scan } // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed // updating of visible landables, for example. The nearest pages do this separately, with their own sorting. // Basically we assume -like for nearest- that values will not change that much in the multicalc split time. // Target and tasks are recalculated in real time in any case. Nearest too. LKCalculateWaypointReachable(multicalc_slot, numslots); CalculateScreenPositionsAirspace(); CalculateScreenPositionsThermalSources(); CalculateScreenPositionsGroundline(); if (PGZoomTrigger) { if(!mode.Is(Mode::MODE_PANORAMA)) { mode.Special(Mode::MODE_SPECIAL_PANORAMA, true); LastZoomTrigger=GPS_INFO.Time; Message::Lock(); Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s Message::Unlock(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(TEXT("LK_TONEUP.WAV")); #endif } else { // previously called, see if time has passed if ( GPS_INFO.Time > (LastZoomTrigger + 20.0)) { // time has passed, lets go back LastZoomTrigger=0; // just for safety mode.Special(Mode::MODE_SPECIAL_PANORAMA, false); PGZoomTrigger=false; Message::Lock(); Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM Message::Unlock(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(TEXT("LK_TONEDOWN.WAV")); #endif } } } // let the calculations run, but dont draw anything but the look8000 when in MapSpaceMode != MSM_MAP if (DONTDRAWTHEMAP) { QuickRedraw: // 100318 speedup redraw DrawLook8000(hdc,rc); #ifdef CPUSTATS DrawCpuStats(hdc,rc); #endif #ifdef DRAWDEBUG DrawDebug(hdc,rc); #endif // no need to do SelectObject as at the bottom of function return; } // When no terrain is painted, set a background0 // Remember that in this case we have plenty of cpu time to spend for best result if (!EnableTerrain || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded() ) { // display border and fill background.. SelectObject(hdc, hInvBackgroundBrush[BgMapColor]); SelectObject(hdc, GetStockObject(WHITE_PEN)); Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom); // We force LK painting black values on screen depending on the background color in use // TODO make it an array once settled // blackscreen would force everything to be painted white, instead LKTextBlack=BgMapColorTextBlack[BgMapColor]; if (BgMapColor>6 ) BlackScreen=true; else BlackScreen=false; } else { LKTextBlack=false; BlackScreen=false; } fastzoom: #if NEWSMARTZOOM // Copy the old background map with no overlays if (ONSMARTZOOM) { if (quickdrawscale>0) { delta_drawscale=zoom.DrawScale() / quickdrawscale; } // StartupStore(_T("... QuickDrawScale=%.2f new zoom=%.2f delta=%.2f\n"),quickdrawscale,zoom.DrawScale(),delta_drawscale); int dx=MapRect.right-MapRect.left; int dy=MapRect.bottom-MapRect.top; // notice: zoom in is always ok.. but zoom out starting from high zoom levels will make the picture // very small and unusable. We can consider to zoom out in fast zoom normally, in such cases? // // Notice 2: the delta is not yet working correctly // if (delta_drawscale>1.0) { // zoom in StretchBlt(hdcDrawWindow, 0,0, dx,dy, hdcQuickDrawWindow, (int)((dx/2) - (dx / delta_drawscale)/2), (int)((dy/2) - (dy / delta_drawscale)/2), (int)(dx / delta_drawscale), (int)(dy / delta_drawscale), SRCCOPY); } else { // zoom out StretchBlt(hdcDrawWindow, (int)((dx/2) - (dx * delta_drawscale)/2), (int)((dy/2) - (dy * delta_drawscale)/2), (int)(dx * delta_drawscale), (int)(dy * delta_drawscale), hdcQuickDrawWindow, 0,0, dx,dy, SRCCOPY); } } #endif SelectObject(hdc, GetStockObject(BLACK_BRUSH)); SelectObject(hdc, GetStockObject(BLACK_PEN)); hfOld = (HFONT)SelectObject(hdc, MapWindowFont); // ground first... if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } #if NEWSMARTZOOM if ( OFFSMARTZOOM ) { #endif if ((EnableTerrain && (DerivedDrawInfo.TerrainValid) && RasterTerrain::isTerrainLoaded()) ) { // sunelevation is never used, it is still a todo in Terrain double sunelevation = 40.0; double sunazimuth=GetAzimuth(); LockTerrainDataGraphics(); if (DONTDRAWTHEMAP) { // 100318 UnlockTerrainDataGraphics(); SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } DrawTerrain(hdc, rc, sunazimuth, sunelevation); // LOCKED 091105 if (DONTDRAWTHEMAP) { // 100318 UnlockTerrainDataGraphics(); SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if (!QUICKDRAW) { // shaded terrain unreachable, aka glide amoeba #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) { #else if ((FinalGlideTerrain==2) && DerivedDrawInfo.TerrainValid) { #endif DrawTerrainAbove(hdc, rc); } } UnlockTerrainDataGraphics(); } #if NEWSMARTZOOM } #endif if (QUICKDRAW) { if ( !mode.AnyPan()) DrawLook8000(hdc,rc); SelectObject(hdcDrawWindow, hfOld); return; } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if (EnableTopology) { DrawTopology(hdc, rc); // LOCKED 091105 } #if 0 StartupStore(_T("... Experimental1=%.0f\n"),Experimental1); StartupStore(_T("... Experimental2=%.0f\n"),Experimental2); Experimental1=0.0; Experimental2=0.0; #endif // Topology labels are printed first, using OLD wps positions from previous run! // Reset for topology labels decluttering engine occurs also in another place here! nLabelBlocks = 0; #if TOPOFASTLABEL for (short nvi=0; nvi<SCREENVSLOTS; nvi++) nVLabelBlocks[nvi]=0; #endif if (ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) { // 100503 DrawTaskAAT(hdc, rc); } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if (OnAirSpace > 0) // Default is true, always true at startup no regsave { if ( (GetAirSpaceFillType() == asp_fill_ablend_full) || (GetAirSpaceFillType() == asp_fill_ablend_borders) ) DrawTptAirSpace(hdc, rc); else DrawAirSpace(hdc, rc); } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if(TrailActive) { // NEED REWRITING LKDrawTrail(hdc, Orig_Aircraft, rc); } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } DrawThermalEstimate(hdc, rc); if (OvertargetMode==OVT_THER) DrawThermalEstimateMultitarget(hdc, rc); // draw red cross on glide through terrain marker if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) { DrawGlideThroughTerrain(hdc, rc); } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if ((OnAirSpace > 0) && AirspaceWarningMapLabels) { DrawAirspaceLabels(hdc, rc, Orig_Aircraft); if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } } DrawWaypointsNew(hdc,rc); if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } if (ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) { // 100503 DrawTask(hdc, rc, Orig_Aircraft); } DrawTeammate(hdc, rc); if (extGPSCONNECT) { DrawBestCruiseTrack(hdc, Orig_Aircraft); DrawBearing(hdc, rc); } // draw wind vector at aircraft if (!mode.AnyPan()) { DrawWindAtAircraft2(hdc, Orig_Aircraft, rc); } else if (mode.Is(Mode::MODE_TARGET_PAN)) { DrawWindAtAircraft2(hdc, Orig, rc); } #if NEWSMARTZOOM // Save the current rendered map before painting overlays if ( OFFSMARTZOOM ) { quickdrawscale=zoom.DrawScale(); BitBlt(hdcQuickDrawWindow, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); } #endif // VisualGlide drawn BEFORE lk8000 overlays if (!mode.AnyPan() && VisualGlide > 0) { DrawGlideCircle(hdc, Orig, rc); } if (DONTDRAWTHEMAP) { // 100319 SelectObject(hdcDrawWindow, hfOld); goto QuickRedraw; } // Draw traffic and other specifix LK gauges LKDrawFLARMTraffic(hdc, rc, Orig_Aircraft); if (!mode.AnyPan()) { // REMINDER TODO let it be configurable for not circling also, as before if ((mode.Is(Mode::MODE_CIRCLING)) ) if (ThermalBar) DrawThermalBand(hdcDrawWindow, rc); // 091122 DrawLook8000(hdc,rc); } if (LKVarioBar && !mode.AnyPan()) // 091214 do not draw Vario when in Pan mode LKDrawVario(hdc,rc); // 091111 // Draw glider or paraglider if (extGPSCONNECT) { DrawAircraft(hdc, Orig_Aircraft); } if (!mode.AnyPan()) { if (TrackBar) DrawHeading(hdc, Orig, rc); } #if USETOPOMARKS // marks on top... DrawMarks(hdc, rc); #endif if (ISGAAIRCRAFT) DrawHSI(hdc,Orig,rc); #ifdef CPUSTATS DrawCpuStats(hdc,rc); #endif #ifdef DRAWDEBUG DrawDebug(hdc,rc); #endif SelectObject(hdcDrawWindow, hfOld); }
void MapWindow::LKDrawMultimap_Asp(LKSurface& Surface, const RECT& rc) { RECT rci = rc; rci.bottom -= BottomSize; #if 0 if (DoInit[MDI_MAPASP]) { DoInit[MDI_MAPASP]=false; } #endif switch(LKevent) { // // USABLE EVENTS // case LKEVENT_NEWRUN: // Upon entering a new multimap, Active is forced reset. It should not be necessary if (MapSpaceMode==MSM_VISUALGLIDE) { GetVisualGlidePoints(0); // reset upon entering! } break; case LKEVENT_TOPLEFT: IsMultimapConfigShown=true; InputEvents::setMode(_T("MMCONF")); break; case LKEVENT_TOPRIGHT: if (MapSpaceMode==MSM_MAPASP) { SonarWarning = !SonarWarning; if (SonarWarning) LKSound(TEXT("LK_TONEUP.WAV")); else LKSound(TEXT("LK_TONEDOWN.WAV")); } // ACTIVE is available only when there is a topview shown! if ( (MapSpaceMode==MSM_MAPTRK || MapSpaceMode==MSM_MAPWPT) && (Current_Multimap_TopRect.bottom>0)) { LKSound(TEXT("LK_TONEDOWN.WAV")); } break; default: // THIS SHOULD NEVER HAPPEN, but always CHECK FOR IT! break; } // // If the map is active in the proper mapspace, we shall manage here the action // if (LKevent==LKEVENT_LONGCLICK /*&& ActiveMap && (MapSpaceMode==MSM_MAPTRK || MapSpaceMode==MSM_MAPWPT)*/) { // // It would be a GOOD IDEA to keep this as a global, updated of course. // We need to know very often how is the screen splitted, and where! // It should be made global somewhere else, not here. // if ( startScreen.y < Current_Multimap_TopRect.bottom) { if( PtInRect(&rc, startScreen)) { /* * we can't show dialog from Draw thread * instead, new event is queued, dialog will be popup by main thread */ InputEvents::processGlideComputer(GCE_WAYPOINT_DETAILS_SCREEN); // LKevent=LKEVENT_NONE; } } } // // This is doing all rendering, including terrain and topology, which is not good. // #ifdef ENABLE_ALL_AS_FOR_SIDEVIEW int oldAltMode = AltitudeMode ; if (GetSideviewPage() == IM_NEAR_AS) AltitudeMode = ALLON; #endif RenderAirspace(Surface, rci); #ifdef ENABLE_ALL_AS_FOR_SIDEVIEW AltitudeMode = oldAltMode; #endif // LKevent=LKEVENT_NONE; }
// this is called only when ActiveWayPoint is 0, still waiting for start void CheckStart(NMEA_INFO *Basic, DERIVED_INFO *Calculated, int *LastStartSector) { BOOL StartCrossed= false; if (UseGates()) { #if DEBUGATE StartupStore(_T("... CheckStart Timenow=%d OpenTime=%d CloseTime=%d ActiveGate=%d\n"),LocalTime(),PGOpenTime,PGCloseTime,ActiveGate); #endif int gatetimediff=-1; if ( ActiveGate<0 ) { // init activegate: assign first valid gate, current or future ActiveGate=InitActiveGate(); if (ActiveGate<0||ActiveGate>(PGNumberOfGates-1)) { FailStore(_T("INVALID ActiveGate=%d"),ActiveGate); DoStatusMessage(_T("ERR-430 INVALID ACTIVEGATE: DISABLED")); PGNumberOfGates=0; return; } #if DEBUGATE StartupStore(_T("... CheckStart: INIT ActiveGate=%d\n"),ActiveGate); #endif } else { if (HaveGates()) { gatetimediff=GateTimeDiff(ActiveGate); #if DEBUGATE StartupStore(_T("... CheckStart: ActiveGate=%d RunningGate=%d\n"),ActiveGate,RunningGate()); StartupStore(_T("... CheckStart: gatetimediff=%d\n"),gatetimediff); #endif // a gate can be in the future , or already open! // case: first start, activegate is the first gate if (gatetimediff==0) { #if DEBUGATE StartupStore(_T("... CheckStart: ActiveGate=%d now OPEN\n"),ActiveGate); #endif AlertGateOpen(ActiveGate); // nothing else to do: the current activegate has just open } else { // check that also non-armed start is detected if (ActiveGate<(PGNumberOfGates-1)) { if (GateTimeDiff(ActiveGate+1)==0) { #if DEBUGATE StartupStore(_T("... CheckStart: ActiveGate+1=%d now OPEN\n"),ActiveGate); #endif ActiveGate++; AlertGateOpen(ActiveGate); } } } // now check for special alerts on countdown, only on current armed start if (gatetimediff==3600 && ((PGGateIntervalTime>=70)||ActiveGate==0) ) { // 850 FIRST GATE OPEN IN 1 HOUR DoStatusMessage(gettext(TEXT("_@M850_"))); if (EnableSoundModes) { LKSound(_T("LK_DINGDONG.WAV")); } } if (gatetimediff==1800 && ((PGGateIntervalTime>=45)||ActiveGate==0) ) { // 851 FIRST GATE OPEN IN 30 MINUTES DoStatusMessage(gettext(TEXT("_@M851_"))); if (EnableSoundModes) { LKSound(_T("LK_DINGDONG.WAV")); } } if (gatetimediff==600 && ((PGGateIntervalTime>=15)||ActiveGate==0) ) { // 10 minutes to go // 852 10 MINUTES TO GO DoStatusMessage(gettext(TEXT("_@M852_"))); if (EnableSoundModes) { LKSound(_T("LK_HITONE.WAV")); } } if (gatetimediff==300 && ((PGGateIntervalTime>=10)||ActiveGate==0)) { // 5 minutes to go // 853 5 MINUTES TO GO DoStatusMessage(gettext(TEXT("_@M853_"))); if (EnableSoundModes) { LKSound(_T("LK_HITONE.WAV")); } } if (gatetimediff==60) { // 1 minute to go if (EnableSoundModes) { LKSound(_T("LK_3HITONES.WAV")); } } } // HaveGates } // not init } if (ISPARAGLIDER && PGStartOut) { // start OUT and go in if (!InStartSector(Basic,Calculated,*LastStartSector, &StartCrossed)) { Calculated->IsInSector = false; if (ReadyToStart(Calculated)) { aatdistance.AddPoint(Basic->Longitude, Basic->Latitude, 0); } if (ValidStartSpeed(Basic, Calculated, StartMaxSpeedMargin)) { ReadyToAdvance(Calculated, false, true); } } else Calculated->IsInSector = true; } else { // start IN and go out, OLD CLASSIC MODE if (InStartSector(Basic,Calculated,*LastStartSector, &StartCrossed)) { // InSector check calling this function is resetting IsInSector at each run, so it was false. Calculated->IsInSector = true; if (ReadyToStart(Calculated)) { aatdistance.AddPoint(Basic->Longitude, Basic->Latitude, 0); } // ToLo: we are ready to start even when outside start rules but within margin if (ValidStartSpeed(Basic, Calculated, StartMaxSpeedMargin)) { ReadyToAdvance(Calculated, false, true); } // TODO accuracy: monitor start speed throughout time in start sector } } // end start mode if (StartCrossed && ValidGate() ) { // 100509 #if DEBUGTGATES StartupStore(_T("... CheckStart: start crossed and valid gate!\n")); #endif // ToLo: Check weather speed and height are within the rules or not (zero margin) if(!IsFinalWaypoint() && ValidStartSpeed(Basic, Calculated) && InsideStartHeight(Basic, Calculated)) { // This is set whether ready to advance or not, because it will // appear in the flight log, so if it's valid, it's valid. Calculated->ValidStart = true; if (ReadyToAdvance(Calculated, true, true)) { ActiveWayPoint=0; // enforce this since it may be 1 StartTask(Basic,Calculated, true, true); } if (Calculated->Flying) { Calculated->ValidFinish = false; } // JMW TODO accuracy: This causes Vaverage to go bonkers // if the user has already passed the start // but selects the start // Note: pilot must have armed advance // for the start to be registered // ToLo: If speed and height are outside the rules they must be within the margin... } else { if ((ActiveWayPoint<=1) && !IsFinalWaypoint() && (Calculated->ValidStart==false) && (Calculated->Flying)) { #if 0 // 101014 This is called from wrong thread, and cause bad crashes // moved to new GCE event inside InputEvents - paolo // need to detect bad starts, just to get the statistics // in case the bad start is the best available, or the user // manually started StartTask(Basic, Calculated, false, false); // Calculated->ValidStart = false; bool startTaskAnyway = false; if (ReadyToAdvance(Calculated, true, true)) { dlgStartTaskShowModal(&startTaskAnyway, Calculated->TaskStartTime, Calculated->TaskStartSpeed, Calculated->TaskStartAltitude); if (startTaskAnyway) { ActiveWayPoint=0; // enforce this since it may be 1 StartTask(Basic,Calculated, true, true); } } Calculated->ValidStart = startTaskAnyway; #else // 101014 StartTask(Basic, Calculated, false, false); if (ReadyToAdvance(Calculated, true, true)) { InputEvents::processGlideComputer(GCE_TASK_CONFIRMSTART); } #endif if (Calculated->Flying) { Calculated->ValidFinish = false; } } } } }
void Shutdown(void) { int i; // LKTOKEN _@M1219_ "Shutdown, please wait..." CreateProgressDialog(gettext(TEXT("_@M1219_"))); LKSound(_T("LK_DISCONNECT.WAV")); Poco::Thread::sleep(500); // real WAV length is 410+ms if (!GlobalRunning) { // shutdown on startup (before sim/fly or clicking on the window X) StartupStore(_T(". Quick shutdown requested before terminating startup%s"),NEWLINE); // force exit mode for the case of being in welcome screen: OnTimerNotify will catch it RUN_MODE=RUN_SHUTDOWN; CloseCalculations(); CloseGeoid(); DeInitCustomHardware(); LKRunStartEnd(false); return; } StartupStore(_T(". Entering shutdown %s%s"), WhatTimeIsIt(),NEWLINE); MapWindow::Event_Pan(0); // return from PAN restores the Task in case of Turnpoint moving #if TESTBENCH StartupLogFreeRamAndStorage(); #endif // turn off all displays GlobalRunning = false; // LKTOKEN _@M1220_ "Shutdown, saving logs..." CreateProgressDialog(gettext(TEXT("_@M1220_"))); // In case we quit while are still flying UpdateLogBook(false); // false=only log if still flying // stop logger guiStopLogger(true); // LKTOKEN _@M1221_ "Shutdown, saving profile..." CreateProgressDialog(gettext(TEXT("_@M1221_"))); extern void LKAircraftSave(const TCHAR *szFile); extern void LKPilotSave(const TCHAR *szFile); extern void LKDeviceSave(const TCHAR *szFile); LKPilotSave(defaultPilotFile); LKAircraftSave(defaultAircraftFile); LKProfileSave(defaultProfileFile); LKDeviceSave(defaultDeviceFile); #if TESTBENCH StartupStore(TEXT(". Save_Recent_WP_history%s"),NEWLINE); #endif SaveRecentList(); // Stop sound // Stop drawing // LKTOKEN _@M1219_ "Shutdown, please wait..." CreateProgressDialog(gettext(TEXT("_@M1219_"))); // 100526 this is creating problem in SIM mode when quit is called from X button, and we are in waypoint details // or probably in other menu related screens. However it cannot happen from real PNA or PDA because we don't have // that X button. MapWindow::CloseDrawingThread(); // Stop calculating too (wake up) dataTriggerEvent.set(); drawTriggerEvent.set(); // Clear data // LKTOKEN _@M1222_ "Shutdown, saving task..." CreateProgressDialog(gettext(TEXT("_@M1222_"))); #if TESTBENCH StartupStore(TEXT(".... Save default task%s"),NEWLINE); #endif SaveDefaultTask(); #if TESTBENCH StartupStore(TEXT(".... Clear task data%s"),NEWLINE); #endif LockTaskData(); Task[0].Index = -1; ActiveWayPoint = -1; AATEnabled = FALSE; CloseWayPoints(); UnlockTaskData(); // LKTOKEN _@M1219_ "Shutdown, please wait..." CreateProgressDialog(gettext(TEXT("_@M1219_"))); #if TESTBENCH StartupStore(TEXT(".... CloseTerrainTopology%s"),NEWLINE); #endif RasterTerrain::CloseTerrain(); CloseTopology(); #if USETOPOMARKS TopologyCloseMarks(); #endif CloseTerrainRenderer(); LiveTrackerShutdown(); #ifndef NO_DATARECORDER CloseFlightDataRecorder(); #endif // Stop COM devices StartupStore(TEXT(". Stop COM devices%s"),NEWLINE); devCloseAll(); CloseFLARMDetails(); ProgramStarted = psInitInProgress; // Kill windows #if TESTBENCH StartupStore(TEXT(".... Close Messages%s"),NEWLINE); #endif Message::Destroy(); #if TESTBENCH StartupStore(TEXT(".... Destroy Button Labels%s"),NEWLINE); #endif ButtonLabel::Destroy(); #if TESTBENCH StartupStore(TEXT(".... Delete Objects%s"),NEWLINE); #endif // Kill graphics objects #ifdef LXMINIMAP hBrushButtonHasFocus.Release(); #endif CAirspaceManager::Instance().CloseAirspaces(); #if TESTBENCH StartupStore(TEXT(".... Delete Critical Sections%s"),NEWLINE); #endif // Wait end of Calculation thread before deinit critical section. WaitThreadCalculation(); #if TESTBENCH StartupStore(TEXT(".... Close Progress Dialog%s"),NEWLINE); #endif CloseProgressDialog(); #if TESTBENCH StartupStore(TEXT(".... Close Calculations%s"),NEWLINE); #endif CloseCalculations(); CloseGeoid(); DeInitCustomHardware(); #if TESTBENCH StartupStore(TEXT(".... Close Windows%s"),NEWLINE); #endif #if TESTBENCH StartupLogFreeRamAndStorage(); #endif for (i=0;i<NUMDEV;i++) { if (ComPortStatus[i]!=0) { StartupStore(_T(". ComPort %d: status=%d Rx=%ld Tx=%ld ErrRx=%ld + ErrTx=%ld (==%ld)%s"), i, ComPortStatus[i], ComPortRx[i],ComPortTx[i], ComPortErrRx[i],ComPortErrTx[i],ComPortErrors[i],NEWLINE); } } StartupStore(_T(". Finished shutdown %s%s"), WhatTimeIsIt(),NEWLINE); LKRunStartEnd(false); #ifdef DEBUG TCHAR foop[80]; TASK_POINT wp; TASK_POINT *wpr = ℘ _stprintf(foop,TEXT(". Sizes %d %d %d%s"), sizeof(TASK_POINT), ((long)&wpr->AATTargetLocked)-((long)wpr), ((long)&wpr->Target)-((long)wpr), NEWLINE ); StartupStore(foop); #endif StartupStore(_T("Destroy MainWindow" NEWLINE)); MainWindow.Destroy(); }
void MapWindow::RenderMapWindowBg(LKSurface& Surface, const RECT& rc) { if ( (LKSurface::AlphaBlendSupported() && BarOpacity < 100) || mode.AnyPan() ) { RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY}; MapWindow::ChangeDrawRect(newRect); } else { RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY - BottomSize - (ScreenSizeY-MapRect.bottom)-1}; MapWindow::ChangeDrawRect(newRect); } if (QUICKDRAW) { goto _skip_calcs; } // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed // updating of visible landables, for example. The nearest pages do this separately, with their own sorting. // Basically we assume -like for nearest- that values will not change that much in the multicalc split time. // Target and tasks are recalculated in real time in any case. Nearest too. LKCalculateWaypointReachable(false); _skip_calcs: if (PGZoomTrigger) { if (!mode.Is(Mode::MODE_PANORAMA)) { mode.Special(Mode::MODE_SPECIAL_PANORAMA, true); LastZoomTrigger = DrawInfo.Time; Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s LKSound(TEXT("LK_TONEUP.WAV")); } else { // previously called, see if time has passed if (DrawInfo.Time > (LastZoomTrigger + 20.0)) { // time has passed, lets go back LastZoomTrigger = 0; // just for safety mode.Special(Mode::MODE_SPECIAL_PANORAMA, false); PGZoomTrigger = false; Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM LKSound(TEXT("LK_TONEDOWN.WAV")); } } } // // "Checkpoint Charlie" // This is were we process stuff for anything else but main map. // We let the calculations run also for MapSpace modes. // But for multimaps, we can also draw some more stuff.. // We are also sent back here from next code, when we detect that // the MapSpace mode has changed from MAP to something else while we // were rendering. // QuickRedraw: // if (DONTDRAWTHEMAP) { const bool isMultimap = IsMultiMapShared(); // DrawMapSpace can change "MapSpaceMode", get this before. DrawMapSpace(Surface, rc); // Is this a "shared map" environment? if (isMultimap) { // Shared map, of course not MSN_MAP, since dontdrawthemap was checked // if (IsMultimapOverlaysGauges()) { RenderOverlayGauges(Surface, rc); } if (IsMultimapOverlaysText()) { DrawLook8000(Surface, rc); } } else { // Not in map painting environment // ex. nearest pages, but also MAPRADAR.. } // DrawBottomBar(Surface, rc); #ifdef DRAWDEBUG DrawDebug(hdc, rc); #endif // no need to do SelectObject as at the bottom of function return; } POINT Orig, Orig_Aircraft; CalculateOrigin(rc, &Orig); const ScreenProjection _Proj = CalculateScreenPositions(Orig, rc, &Orig_Aircraft); // When no terrain is painted, set a background0 // Remember that in this case we have plenty of cpu time to spend for best result if (!IsMultimapTerrain() || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded()) { // We force LK painting black values on screen depending on the background color in use // TODO make it an array once settled // blackscreen would force everything to be painted white, instead LKTextBlack = BgMapColorTextBlack[BgMapColor]; if (BgMapColor > 6) BlackScreen = true; else BlackScreen = false; } else { LKTextBlack = false; BlackScreen = false; } // Logic of DONTDRAWTHEMAP is the following: // We are rendering the screen page here. If we are here, we passed Checkpoint Charlie. // So we were, at charlie, in MSM_MAP: preparing the main map stuff. // If we detect that MapSpace has CHANGED while we were doing our job here, // it means that the user has clicked meanwhile. He desires another page, so let's // reset our intentions and go back to beginning, or nearby.. // We have a new job to do, for another MapSpace, no more MAP. if (DONTDRAWTHEMAP) { goto QuickRedraw; } bool terrainpainted = false; if ((IsMultimapTerrain() && (DerivedDrawInfo.TerrainValid) && RasterTerrain::isTerrainLoaded()) ) { // sunelevation is never used, it is still a todo in Terrain double sunelevation = 40.0; double sunazimuth = GetAzimuth(); LockTerrainDataGraphics(); if (DONTDRAWTHEMAP) { // 100318 UnlockTerrainDataGraphics(); goto QuickRedraw; } if(DrawTerrain(Surface, DrawRect, _Proj, sunazimuth, sunelevation)) { terrainpainted = true; } if (DONTDRAWTHEMAP) { UnlockTerrainDataGraphics(); goto QuickRedraw; } if (!QUICKDRAW) { // SHADED terrain unreachable, aka glide amoeba. This is not the outlined perimeter! #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) { #else if ((FinalGlideTerrain == 2) && DerivedDrawInfo.TerrainValid) { #endif DrawTerrainAbove(Surface, DrawRect); } } UnlockTerrainDataGraphics(); } // // REMINDER: WE ARE IN MAIN MAP HERE: MSM_MAP ONLY, OR PANNING MODE! // MAPSPACEMODE CAN STILL CHANGE, DUE TO USER INPUT. BUT WE GOT HERE IN // EITHER PAN OR MSM_MAP. // if (DONTDRAWTHEMAP) { goto QuickRedraw; } if(!terrainpainted) { // fill background.. Surface.FillRect(&rc, hInvBackgroundBrush[BgMapColor]); } if (IsMultimapTopology()) { DrawTopology(Surface, DrawRect, _Proj); } else { // If no topology wanted, but terrain painted, we paint only water stuff if (terrainpainted) DrawTopology(Surface, DrawRect, _Proj, true); } #if 0 StartupStore(_T("... Experimental1=%.0f\n"), Experimental1); StartupStore(_T("... Experimental2=%.0f\n"), Experimental2); Experimental1 = 0.0; Experimental2 = 0.0; #endif // Topology labels are printed first, using OLD wps positions from previous run! // Reset for topology labels decluttering engine occurs also in another place here! ResetLabelDeclutter(); if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTaskAAT(Surface, DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (IsMultimapAirspace()) { DrawAirSpace(Surface, rc, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // In QUICKDRAW dont draw trail, thermals, glide terrain if (QUICKDRAW) { goto _skip_stuff; } DrawThermalEstimate(Surface, DrawRect, _Proj); if (OvertargetMode == OVT_THER) DrawThermalEstimateMultitarget(Surface, DrawRect, _Proj); // draw red cross on glide through terrain marker if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) { DrawGlideThroughTerrain(Surface, DrawRect, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } _skip_stuff: if (IsMultimapAirspace() && AirspaceWarningMapLabels) { DrawAirspaceLabels(Surface, DrawRect, _Proj, Orig_Aircraft); if (DONTDRAWTHEMAP) { // 100319 goto QuickRedraw; } } if (IsMultimapWaypoints()) { DrawWaypointsNew(Surface, DrawRect); } if (TrailActive) { LKDrawLongTrail(Surface, Orig_Aircraft, DrawRect); // NEED REWRITING LKDrawTrail(Surface, DrawRect, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTask(Surface, DrawRect, _Proj, Orig_Aircraft); } if (Flags_DrawFAI) { if (MapWindow::DerivedDrawInfo.Flying) { // FAI optimizer does not depend on tasks, being based on trace DrawFAIOptimizer(Surface, DrawRect, _Proj, Orig_Aircraft); } else { // not flying => show FAI sectors for the task if (ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTaskSectors(Surface, DrawRect, _Proj); } } } // In QUICKDRAW do not paint other useless stuff if (QUICKDRAW) { if (extGPSCONNECT) DrawBearing(Surface, DrawRect, _Proj); goto _skip_2; } // --------------------------------------------------- DrawTeammate(Surface, rc, _Proj); if (extGPSCONNECT) { DrawBestCruiseTrack(Surface, Orig_Aircraft); DrawBearing(Surface, DrawRect, _Proj); } // draw wind vector at aircraft if (NOTANYPAN) { DrawWindAtAircraft2(Surface, Orig_Aircraft, DrawRect); } else if (mode.Is(Mode::MODE_TARGET_PAN)) { DrawWindAtAircraft2(Surface, Orig, rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // Draw traffic and other specifix LK gauges LKDrawFLARMTraffic(Surface, DrawRect, _Proj, Orig_Aircraft); // --------------------------------------------------- _skip_2: if (NOTANYPAN) { if (IsMultimapOverlaysGauges()) { RenderOverlayGauges(Surface, rc); } if (TrackBar) { DrawHeading(Surface, Orig, DrawRect); if (ISGAAIRCRAFT) { DrawFuturePos(Surface, Orig, DrawRect); } } if (ISGAAIRCRAFT) { DrawHSIarc(Surface, Orig, DrawRect); } if (IsMultimapOverlaysText()) { DrawLook8000(Surface, rc); } DrawBottomBar(Surface, rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // Draw glider or paraglider if (extGPSCONNECT) { DrawAircraft(Surface, Orig_Aircraft); } #if USETOPOMARKS // marks on top... DrawMarks(hdc, rc); #endif if (!INPAN) { DrawMapScale(Surface, rc, zoom.BigZoom()); // unused BigZoom DrawCompass(Surface, rc, DisplayAngle); } #ifdef DRAWDEBUG DrawDebug(hdc, rc); #endif }
void MapWindow::RenderMapWindowBg(HDC hdc, const RECT rc, const POINT &Orig, const POINT &Orig_Aircraft) { // Calculations are taking time and slow down painting of map, beware #define MULTICALC_MINROBIN 5 // minimum split #define MULTICALC_MAXROBIN 20 // max split static short multicalc_slot=0;// -1 (which becomes immediately 0) will force full loading on startup, but this is not good // because currently we are not waiting for ProgramStarted=3 // and the first scan is made while still initializing other things // TODO assign numslots with a function, based also on available CPU time short numslots=1; #if NEWSMARTZOOM static double quickdrawscale=0.0; static double delta_drawscale=1.0; #endif #if 0 extern void TestChangeRect(); TestChangeRect(); #endif if ((MapWindow::AlphaBlendSupported() && BarOpacity<100) || mode.AnyPan()) { MapWindow::ChangeDrawRect(MapRect); } else { RECT newRect={0,0,ScreenSizeX,ScreenSizeY-BottomSize}; MapWindow::ChangeDrawRect(newRect); } if (QUICKDRAW) { goto _skip_calcs; } if (NumberOfWayPoints>200) { numslots=NumberOfWayPoints/400; // keep numslots optimal if (numslots<MULTICALC_MINROBIN) numslots=MULTICALC_MINROBIN; // seconds for full scan, as this is executed at 1Hz if (numslots>MULTICALC_MAXROBIN) numslots=MULTICALC_MAXROBIN; // When waypointnumber has changed, we wont be using an exceeded multicalc_slot, which would crash the sw // In this case, we shall probably continue for the first round to calculate without going from the beginning // but this is not a problem, we are round-robin all the time here. if (++multicalc_slot>numslots) multicalc_slot=1; } else { multicalc_slot=0; // forcing full scan } // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed // updating of visible landables, for example. The nearest pages do this separately, with their own sorting. // Basically we assume -like for nearest- that values will not change that much in the multicalc split time. // Target and tasks are recalculated in real time in any case. Nearest too. LKCalculateWaypointReachable(multicalc_slot, numslots); _skip_calcs: CalculateScreenPositionsAirspace(rc); CalculateScreenPositionsThermalSources(); // Make the glide amoeba out of the latlon points, converting them to screen // (This function is updated for supporting multimaps ) CalculateScreenPositionsGroundline(); if (PGZoomTrigger) { if(!mode.Is(Mode::MODE_PANORAMA)) { mode.Special(Mode::MODE_SPECIAL_PANORAMA, true); LastZoomTrigger=DrawInfo.Time; Message::Lock(); Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s Message::Unlock(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(TEXT("LK_TONEUP.WAV")); #endif } else { // previously called, see if time has passed if ( DrawInfo.Time > (LastZoomTrigger + 20.0)) { // time has passed, lets go back LastZoomTrigger=0; // just for safety mode.Special(Mode::MODE_SPECIAL_PANORAMA, false); PGZoomTrigger=false; Message::Lock(); Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM Message::Unlock(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(TEXT("LK_TONEDOWN.WAV")); #endif } } } // // "Checkpoint Charlie" // This is were we process stuff for anything else but main map. // We let the calculations run also for MapSpace modes. // But for multimaps, we can also draw some more stuff.. // We are also sent back here from next code, when we detect that // the MapSpace mode has changed from MAP to something else while we // were rendering. // QuickRedraw: // if (DONTDRAWTHEMAP) { DrawMapSpace(hdc, rc); // Is this a "shared map" environment? if (IsMultiMapShared()) { // Shared map, of course not MSN_MAP, since dontdrawthemap was checked // if (IsMultimapOverlaysText()) { DrawLook8000(hdc,rc); } if (IsMultimapOverlaysGauges()) { if (LKVarioBar) LKDrawVario(hdc,rc); if ((mode.Is(Mode::MODE_CIRCLING)) ) if (ThermalBar) DrawThermalBand(hdcDrawWindow, rc); DrawFinalGlide(hdcDrawWindow,rc); } } else { // Not in map painting environment // ex. nearest pages, but also MAPRADAR.. } // DrawBottomBar(hdc,rc); #ifdef CPUSTATS DrawCpuStats(hdc,rc); #endif #ifdef DRAWDEBUG DrawDebug(hdc,rc); #endif // no need to do SelectObject as at the bottom of function return; } // When no terrain is painted, set a background0 // Remember that in this case we have plenty of cpu time to spend for best result if (!IsMultimapTerrain() || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded() ) { // display border and fill background.. SelectObject(hdc, hInvBackgroundBrush[BgMapColor]); SelectObject(hdc, GetStockObject(WHITE_PEN)); Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom); // We force LK painting black values on screen depending on the background color in use // TODO make it an array once settled // blackscreen would force everything to be painted white, instead LKTextBlack=BgMapColorTextBlack[BgMapColor]; if (BgMapColor>6 ) BlackScreen=true; else BlackScreen=false; } else { LKTextBlack=false; BlackScreen=false; } #if NEWSMARTZOOM // Copy the old background map with no overlays if (ONSMARTZOOM) { if (quickdrawscale>0) { delta_drawscale=zoom.DrawScale() / quickdrawscale; } // StartupStore(_T("... QuickDrawScale=%.2f new zoom=%.2f delta=%.2f\n"),quickdrawscale,zoom.DrawScale(),delta_drawscale); int dx=MapRect.right-MapRect.left; int dy=MapRect.bottom-MapRect.top; // notice: zoom in is always ok.. but zoom out starting from high zoom levels will make the picture // very small and unusable. We can consider to zoom out in fast zoom normally, in such cases? // // Notice 2: the delta is not yet working correctly // if (delta_drawscale>1.0) { // zoom in StretchBlt(hdcDrawWindow, 0,0, dx,dy, hdcQuickDrawWindow, (int)((dx/2) - (dx / delta_drawscale)/2), (int)((dy/2) - (dy / delta_drawscale)/2), (int)(dx / delta_drawscale), (int)(dy / delta_drawscale), SRCCOPY); } else { // zoom out StretchBlt(hdcDrawWindow, (int)((dx/2) - (dx * delta_drawscale)/2), (int)((dy/2) - (dy * delta_drawscale)/2), (int)(dx * delta_drawscale), (int)(dy * delta_drawscale), hdcQuickDrawWindow, 0,0, dx,dy, SRCCOPY); } } #endif // Logic of DONTDRAWTHEMAP is the following: // We are rendering the screen page here. If we are here, we passed Checkpoint Charlie. // So we were, at charlie, in MSM_MAP: preparing the main map stuff. // If we detect that MapSpace has CHANGED while we were doing our job here, // it means that the user has clicked meanwhile. He desires another page, so let's // reset our intentions and go back to beginning, or nearby.. // We have a new job to do, for another MapSpace, no more MAP. if (DONTDRAWTHEMAP) { goto QuickRedraw; } #if NEWSMARTZOOM if ( OFFSMARTZOOM ) { #endif bool terrainpainted=false; if ((IsMultimapTerrain() && (DerivedDrawInfo.TerrainValid) && RasterTerrain::isTerrainLoaded()) ) { // sunelevation is never used, it is still a todo in Terrain double sunelevation = 40.0; double sunazimuth=GetAzimuth(); LockTerrainDataGraphics(); if (DONTDRAWTHEMAP) { // 100318 UnlockTerrainDataGraphics(); goto QuickRedraw; } DrawTerrain(hdc, DrawRect, sunazimuth, sunelevation); terrainpainted=true; if (DONTDRAWTHEMAP) { UnlockTerrainDataGraphics(); goto QuickRedraw; } if (!QUICKDRAW) { // SHADED terrain unreachable, aka glide amoeba. This is not the outlined perimeter! #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) { #else if ((FinalGlideTerrain==2) && DerivedDrawInfo.TerrainValid) { #endif DrawTerrainAbove(hdc, DrawRect); } } UnlockTerrainDataGraphics(); } #if NEWSMARTZOOM } #endif // // REMINDER: WE ARE IN MAIN MAP HERE: MSM_MAP ONLY, OR PANNING MODE! // MAPSPACEMODE CAN STILL CHANGE, DUE TO USER INPUT. BUT WE GOT HERE IN // EITHER PAN OR MSM_MAP. // if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (IsMultimapTopology()) { DrawTopology(hdc, DrawRect); } else { // If no topology wanted, but terrain painted, we paint only water stuff if (terrainpainted) DrawTopology(hdc, DrawRect,true); } #if 0 StartupStore(_T("... Experimental1=%.0f\n"),Experimental1); StartupStore(_T("... Experimental2=%.0f\n"),Experimental2); Experimental1=0.0; Experimental2=0.0; #endif // Topology labels are printed first, using OLD wps positions from previous run! // Reset for topology labels decluttering engine occurs also in another place here! ResetLabelDeclutter(); if (Flags_DrawTask && ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) { DrawTaskAAT(hdc, DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (IsMultimapAirspace()) { if ( (GetAirSpaceFillType() == asp_fill_ablend_full) || (GetAirSpaceFillType() == asp_fill_ablend_borders) ) DrawTptAirSpace(hdc, rc); else DrawAirSpace(hdc, rc); // full screen, to hide clipping effect on low border } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // In QUICKDRAW dont draw trail, thermals, glide terrain if (QUICKDRAW) goto _skip_stuff; if(TrailActive) { // NEED REWRITING LKDrawTrail(hdc, Orig_Aircraft, DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } DrawThermalEstimate(hdc, DrawRect); if (OvertargetMode==OVT_THER) DrawThermalEstimateMultitarget(hdc, DrawRect); // draw red cross on glide through terrain marker if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) { DrawGlideThroughTerrain(hdc, DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } _skip_stuff: if (IsMultimapAirspace() && AirspaceWarningMapLabels) { DrawAirspaceLabels(hdc, DrawRect, Orig_Aircraft); if (DONTDRAWTHEMAP) { // 100319 goto QuickRedraw; } } if (IsMultimapWaypoints()) { DrawWaypointsNew(hdc,DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (Flags_DrawTask && ValidTaskPoint(ActiveWayPoint) && ValidTaskPoint(1)) { DrawTask(hdc, DrawRect, Orig_Aircraft); } // FAI optimizer does not depend on tasks, being based on trace if (Flags_DrawFAI) DrawFAIOptimizer(hdc, DrawRect, Orig_Aircraft); // In QUICKDRAW do not paint other useless stuff if (QUICKDRAW) { if (extGPSCONNECT) DrawBearing(hdc, DrawRect); goto _skip_2; } // --------------------------------------------------- DrawTeammate(hdc, rc); if (extGPSCONNECT) { DrawBestCruiseTrack(hdc, Orig_Aircraft); DrawBearing(hdc, DrawRect); } // draw wind vector at aircraft if (NOTANYPAN) { DrawWindAtAircraft2(hdc, Orig_Aircraft, DrawRect); } else if (mode.Is(Mode::MODE_TARGET_PAN)) { DrawWindAtAircraft2(hdc, Orig, rc); } #if NEWSMARTZOOM // Save the current rendered map before painting overlays if ( OFFSMARTZOOM ) { quickdrawscale=zoom.DrawScale(); BitBlt(hdcQuickDrawWindow, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); } #endif // VisualGlide drawn BEFORE lk8000 overlays if (NOTANYPAN && (VisualGlide > 0)) { DrawGlideCircle(hdc, Orig, rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // Draw traffic and other specifix LK gauges LKDrawFLARMTraffic(hdc, DrawRect, Orig_Aircraft); // --------------------------------------------------- _skip_2: if (NOTANYPAN) { // REMINDER TODO let it be configurable for not circling also, as before if ((mode.Is(Mode::MODE_CIRCLING)) ) if (ThermalBar) DrawThermalBand(hdcDrawWindow, rc); // 091122 if (IsMultimapOverlaysText()) DrawLook8000(hdc,rc); DrawBottomBar(hdc,rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (IsMultimapOverlaysGauges() && (LKVarioBar && NOTANYPAN)) LKDrawVario(hdc,rc); // Draw glider or paraglider if (extGPSCONNECT) { DrawAircraft(hdc, Orig_Aircraft); } if (NOTANYPAN && !QUICKDRAW) { if (TrackBar) DrawHeading(hdc, Orig, DrawRect); } #if USETOPOMARKS // marks on top... DrawMarks(hdc, rc); #endif if (ISGAAIRCRAFT && IsMultimapOverlaysGauges() && NOTANYPAN) DrawHSI(hdc,Orig,DrawRect); if (!INPAN) { DrawMapScale(hdcDrawWindow,rc, zoom.BigZoom()); // unused BigZoom DrawCompass(hdcDrawWindow, rc, DisplayAngle); } if (IsMultimapOverlaysGauges() && NOTANYPAN) DrawFinalGlide(hdcDrawWindow,rc); #ifdef CPUSTATS DrawCpuStats(hdc,rc); #endif #ifdef DRAWDEBUG DrawDebug(hdc,rc); #endif }
// Thermal orbiter by Paolo Ventafridda, November 2010 void CalculateOrbiter(NMEA_INFO *Basic, DERIVED_INFO *Calculated) { static unsigned int timepassed=0; static bool alreadywarned=false; if (!Calculated->Circling || !EnableSoundModes) return; timepassed++; if (LKTH_R <1) { return; // no thermal center available } double thtime = Basic->Time - Calculated->ClimbStartTime; // we need a valid thermal center to work on. Assuming 2 minutes is enough to sample the air around. if (thtime<120) return; // after 1500ft thermal gain, autodisable if (Calculated->ThermalGain>500) return; if (Calculated->ThermalGain<50) return; // StartupStore(_T("*** Tlat=%f Tlon=%f R=%f W=%f TurnRate=%f \n"), LKTH_LAT, LKTH_LON, LKTH_R, LKTH_W, LK_TURNRATE); // StartupStore(_T("*** CalcHeading=%f Track=%f TurnRate=%f Bank=%f \n"), LK_CALCHEADING, LK_MYTRACK, LK_TURNRATE, LK_BANKING); double th_center_distance, th_center_bearing; // thermal center double orbital_bearing; // orbital tangent double orbital_brgdiff; // current difference between track and orbital_bearing double orbital_warning_angle; // warning angle difference double alpha; // alpha angle to the tangent relative to th_center_bearing double circlesense=0; // 1 for CW, -1 for CCW // these parameters should be dynamically calculated for each thermal in the future // th_angle should be correlated to IAS double th_radius; // thermal radius double th_minoverradius, th_maxoverradius; // radius+overradius is the minimal and max approach distance double th_angle; // deg/s default turning in the thermal. Pilot should turn with this // angolar speed. double reactiontime; // how many seconds pass before the pilot start turning double turningcapacitypersecond; // how many degrees can I change in my turnrate in a second? // TODO: TUNE THEM IN REAL TIME! if (ISPARAGLIDER) { th_radius=50; th_minoverradius=1; th_maxoverradius=100; th_angle=18; turningcapacitypersecond=10; reactiontime=1.0; } else { th_radius=90; th_minoverradius=5; th_maxoverradius=160; th_angle=16.5; turningcapacitypersecond=10; reactiontime=1.0; } circlesense=LK_TURNRATE>0 ? 1 : -1; //@ CCW: -1 CW: 1 if (circlesense==0 || (fabs(LK_TURNRATE)<8)) { // 8 deg/sec are 45 seconds per turn alreadywarned=false; return; } DistanceBearing(LK_MYLAT, LK_MYLON,LKTH_LAT,LKTH_LON,&th_center_distance,&th_center_bearing); if (th_center_distance< (th_radius+th_minoverradius)) { #if DEBUG_ORBITER StartupStore(_T("*** Too near: dist=%.0f < %.0f\n"), th_center_distance, th_radius+th_minoverradius); #endif return; } if (th_center_distance> (th_radius+th_maxoverradius)) { #if DEBUG_ORBITER StartupStore(_T("*** Too far: dist=%.0f > %.0f\n"), th_center_distance, th_radius+th_maxoverradius); #endif return; } // StartupStore(_T("*** distance to orbit %.0f (ratio:%0.f)\n"), // th_center_distance- th_radius , (th_center_distance - th_radius)/th_radius); alpha= atan2(th_radius, th_center_distance)*RAD_TO_DEG; orbital_bearing = th_center_bearing - (alpha*circlesense); //@ add for CCW if (orbital_bearing>359) orbital_bearing-=360; // orbital_distance = th_radius / sin(alpha); // StartupStore(_T("*** tc_dist=%f th_center_bearing=%f orbital_distance=%f orbital_bearing=%f alpha=%f mydir=%f\n"), // th_center_distance, th_center_bearing, orbital_distance, orbital_bearing, alpha, LK_CALCHEADING ); if (circlesense==1) orbital_brgdiff = orbital_bearing-LK_CALCHEADING; // CW else orbital_brgdiff = LK_CALCHEADING - orbital_bearing; // CCW if (orbital_brgdiff<0) { #if DEBUG_ORBITER StartupStore(_T("*** passed target orbit direction\n")); #endif return; } if (orbital_brgdiff>90) { #if DEBUG_ORBITER StartupStore(_T("*** wrong direction\n")); #endif return; } static int lasttimewarned=0; double actionadvancetime; // how many seconds are needed in advance, given the current turnrate? // assuming circling with the same radius of the perfect thermal: 18deg/s, 20s turn rate approx. actionadvancetime=(circlesense*(LK_TURNRATE/turningcapacitypersecond))+reactiontime; // When circling with a radius greater than the default, we have a problem. // We must correct the predicted angle threshold orbital_warning_angle=actionadvancetime*(LK_TURNRATE*LK_TURNRATE)/th_angle; #if DEBUG_ORBITER StartupStore(_T("... LK_TURNRATE=%.0f advancetime=%.2f angle=%.1f \n"), LK_TURNRATE, actionadvancetime,orbital_warning_angle); #endif if (orbital_brgdiff<orbital_warning_angle) { if (!alreadywarned && ((timepassed-lasttimewarned)>12) ) { if (th_center_distance<(th_radius+(th_maxoverradius/2))) { #if DEBUG_ORBITER StartupStore(_T("****** GO STRAIGHT NOW FOR SHORT TIME ******\n")); #endif LKSound(_T("LK_ORBITER1.WAV")); } else { #if DEBUG_ORBITER StartupStore(_T("****** GO STRAIGHT NOW FOR LONGER TIME ******\n")); #endif LKSound(_T("LK_ORBITER2.WAV")); } alreadywarned=true; lasttimewarned=timepassed; } else { #if DEBUG_ORBITER StartupStore(_T("****** GO STRAIGHT, already warned\n")); #endif } } else { alreadywarned=false; } }
// // Called by DrawThread // void MapWindow::DrawLKAlarms(HDC hDC, const RECT rc) { static unsigned short displaycounter=0; static short oldvalidalarm=-1; short validalarm=-1; // Alarms are working only with a valid GPS fix. No navigator, no alarms. if (DrawInfo.NAVWarning) return; // give priority to the lowest alarm in list if (CheckAlarms(2)) validalarm=2; if (CheckAlarms(1)) validalarm=1; if (CheckAlarms(0)) validalarm=0; // If we have a new alarm, play sound if available and enabled if (validalarm>=0) { if (EnableSoundModes) { switch (validalarm) { case 0: LKSound(_T("LK_ALARM_ALT1.WAV")); break; case 1: LKSound(_T("LK_ALARM_ALT2.WAV")); break; case 2: LKSound(_T("LK_ALARM_ALT3.WAV")); break; default: break; } } displaycounter=12; // seconds to display alarm on screen, resetting anything set previously } // Now paint message, even for passed alarms if (displaycounter) { if (--displaycounter>60) displaycounter=0; // safe check TCHAR textalarm[100]; short currentalarm=0; if (validalarm>=0) { currentalarm=validalarm; oldvalidalarm=validalarm; } else if (oldvalidalarm>=0) currentalarm=oldvalidalarm; // safety check switch(currentalarm) { case 0: case 1: case 2: wsprintf(textalarm,_T("%s %d: %s %d"), gettext(_T("_@M1650_")), currentalarm+1, gettext(_T("_@M1651_")), // ALARM ALTITUDE ((int)((double)LKalarms[currentalarm].triggervalue*ALTITUDEMODIFY))); break; default: break; } HFONT oldfont=NULL; if (ScreenLandscape) oldfont=(HFONT)SelectObject(hDC,LK8TargetFont); else oldfont=(HFONT)SelectObject(hDC,LK8MediumFont); TextInBoxMode_t TextInBoxMode = {0}; TextInBoxMode.Color = RGB_WHITE; TextInBoxMode.NoSetFont=1; TextInBoxMode.AlligneCenter = 1; TextInBoxMode.WhiteBorder = 1; TextInBoxMode.Border = 1; // same position for gps warnings: if navwarning, then no alarms. So no overlapping. TextInBox(hDC, &rc, textalarm , (rc.right-rc.left)/2, (rc.bottom-rc.top)/3, 0, &TextInBoxMode); SelectObject(hDC,oldfont); } }
bool MapWindow::Event_NearestWaypointDetails(double lon, double lat) { double Dist; unsigned int i; const double range = zoom.RealScale()*500; double dyn_range = std::max(5000.0, range*3.5); //StartupStore(_T("RANGE=%f\n"),dyn_range); LKSound(TEXT("LK_BELL.WAV")); start_search: #ifdef BUTTONS_MS LockFlightData(); DistanceBearing(lat,lon, GPS_INFO.Latitude,GPS_INFO.Longitude, &Dist, NULL); UnlockFlightData(); if(Dist < dyn_range) { #ifdef OWN_POS_MS dlgAddMultiSelectListItem(NULL,0, IM_OWN_POS, Dist); #endif #ifdef ORACLE_MS dlgAddMultiSelectListItem(NULL,0, IM_ORACLE, Dist); #endif #ifdef TEAM_CODE_MS dlgAddMultiSelectListItem(NULL,0, IM_TEAM, Dist); #endif } #endif // BUTTONS_MS for(size_t i=NUMRESWP;i<WayPointList.size();++i) { // Consider only valid markers if ((WayPointCalc[i].WpType==WPT_AIRPORT)|| (WayPointCalc[i].WpType==WPT_OUTLANDING)) { DistanceBearing(lat,lon, WayPointList[i].Latitude, WayPointList[i].Longitude, &Dist, NULL); if(Dist < dyn_range) { dlgAddMultiSelectListItem(NULL,i, IM_WAYPOINT, Dist); } } } #ifdef FLARM_MS if((MapWindow::mode.Is(MapWindow::Mode::MODE_PAN) || MapWindow::mode.Is(MapWindow::Mode::MODE_TARGET_PAN))) { LastDoTraffic=0; DoTraffic(&DrawInfo,&DerivedDrawInfo); for (unsigned i=0; i<FLARM_MAX_TRAFFIC; ++i) { if (LKTraffic[i].Status != LKT_EMPTY) { DistanceBearing(lat,lon, LKTraffic[i].Latitude, LKTraffic[i].Longitude, &Dist, NULL); if(Dist < range) { dlgAddMultiSelectListItem((long*)&LKTraffic[i],i, IM_FLARM, Dist); } } } } #endif int HorDist=0, Bearing=0, VertDist=0; CAirspaceList reslist = CAirspaceManager::Instance().GetNearAirspacesAtPoint(lon, lat, (int)(dyn_range/2)); for (CAirspaceList::const_iterator it = reslist.begin(); it != reslist.end(); ++it) { LKASSERT((*it)); (*it)->CalculateDistance(&HorDist, &Bearing, &VertDist,lon, lat); dlgAddMultiSelectListItem((long*) (*it),0, IM_AIRSPACE, HorDist); } for(i=1;i<WayPointList.size();i++) { // Consider only valid markers if ((WayPointCalc[i].WpType != WPT_AIRPORT)|| (WayPointCalc[i].WpType != WPT_OUTLANDING)) { DistanceBearing(lat,lon, WayPointList[i].Latitude, WayPointList[i].Longitude, &Dist, NULL); if(Dist < (dyn_range)) { dlgAddMultiSelectListItem(NULL,i, IM_WAYPOINT, Dist); } } } // TASK MULTISELECT int SecType= DAe; double SecRadius =0; double Bear=0; bool Angleinside = false; LockTaskData(); for(i=0; ValidTaskPoint(i); i++) { LKASSERT(Task[i].Index <=(int)WayPointList.size()); DistanceBearing(lat,lon, WayPointList[Task[i].Index].Latitude, WayPointList[Task[i].Index].Longitude, &Dist, &Bear); GetTaskSectorParameter(i, &SecType, &SecRadius); Angleinside = true; if( SecRadius < (dyn_range)) SecRadius =dyn_range; if((Dist < SecRadius) && Angleinside) { dlgAddMultiSelectListItem(NULL,i, IM_TASK_PT, Dist); } } UnlockTaskData(); #if (WINDOWSPC>0) if (EnableSoundModes) Poco::Thread::sleep(1000); // let the sound be heard in sequence #endif if(dlgGetNoElements() ==0) { if(dyn_range < 120000) { dyn_range *=2; goto start_search; } else { DoStatusMessage(gettext(TEXT("_@M2248_"))); // _@M2248_ "No Near Object found!" } } else { LKSound(TEXT("LK_GREEN.WAV")); dlgMultiSelectListShowModal(); if(ValidTaskPoint(PanTaskEdit)) { MapWindow::Event_Pan(1); } return true; } return false; }
// vkmode 0=normal 1=gesture up 2=gesture down // however we consider a down as up, and viceversa int ProcessVirtualKey(int X, int Y, long keytime, short vkmode) { #define VKTIMELONG 1500 short yup, ydown; short i, j; short numpages=0; static short s_xright=0, s_xleft=0; short shortpress_yup, shortpress_ydown; short longpress_yup, longpress_ydown; static short s_bottomY=0; #if 0 // 121123 CHECK AND REMOVE static short oldMapSpaceMode=0; #endif bool dontdrawthemap=(DONTDRAWTHEMAP); VKtime=keytime; #ifdef DEBUG_PROCVK TCHAR buf[100]; _stprintf(buf,_T("R=%d,%d,%d,%d, X=%d Y=%d kt=%ld"),0, 0, ScreenSizeX, ScreenSizeY,X,Y,keytime); DoStatusMessage(buf); #endif if (DoInit[MDI_PROCESSVIRTUALKEY]) { // calculate left and right starting from center s_xleft=(MapWindow::MapRect.right+MapWindow::MapRect.left)/2 -(MapWindow::MapRect.right-MapWindow::MapRect.left)/6; s_xright=(MapWindow::MapRect.right+MapWindow::MapRect.left)/2 + (MapWindow::MapRect.right-MapWindow::MapRect.left)/6; // same for bottom navboxes: they do not exist in infobox mode s_bottomY=MapWindow::Y_BottomBar-NIBLSCALE(2); DoInit[MDI_PROCESSVIRTUALKEY]=false; } // LK v6: check we are not out of MapRect bounds. if (X<MapWindow::MapRect.left||X>MapWindow::MapRect.right||Y<MapWindow::MapRect.top||Y>MapWindow::MapRect.bottom) return ProcessSubScreenVirtualKey(X,Y,keytime,vkmode); if (MapSpaceMode==MSM_WELCOME) { SetModeType(LKMODE_MAP, MP_MOVING); LKevent=LKEVENT_NONE; NextModeIndex(); PreviousModeIndex(); MapWindow::RefreshMap(); LKSound(_T("LK_BEEP0.WAV")); return 0; } // 120602 fix // TopSize is dynamically assigned by DrawNearest,Drawcommon, DrawXX etc. so we cannot make static yups // longpress_yup=(short)((MapWindow::Y_BottomBar-TopSize)/3.7)+TopSize; longpress_ydown=(short)(MapWindow::Y_BottomBar-(MapWindow::Y_BottomBar/3.7)); shortpress_yup=(short)((MapWindow::Y_BottomBar-TopSize)/2.7)+TopSize; shortpress_ydown=(short)(MapWindow::Y_BottomBar-(MapWindow::Y_BottomBar/2.7)); // do not consider navboxes, they are processed separately // These are coordinates for up down center VKs // yup and ydown are used normally on nearest page item selection, but also for real VK // that currently are almost unused. if (DrawBottom) { // Native LK mode: always fullscreen mode // If long click, we are processing an Enter, and we want a wider valid center area if ( keytime>=(VKSHORTCLICK*2)) { yup=longpress_yup; ydown=longpress_ydown; } else { yup=shortpress_yup; ydown=shortpress_ydown; } } else { // This could happen only in Ibox mode. We should never fall here. yup=(short)(ScreenSizeY/2.7); ydown=(short)(ScreenSizeY-(ScreenSizeY/2.7)); #if TESTBENCH StartupStore(_T("...... DrawBottom FALSE in virtual key processing!\n")); #endif } #ifdef DEBUG_PROCVK TCHAR buf[100]; #endif // Handle fullscreen 8000 mode // sound clicks require some attention here if (DrawBottom && !MapWindow::mode.AnyPan() && vkmode==LKGESTURE_NONE) { // // CLICKS on NAVBOXES, any MapSpaceMode ok // if (Y>= s_bottomY ) { // TESTFIX 090930 if ( X>s_xright ) { // standard configurable mode if (keytime >=CustomKeyTime) { // 2 is right key if (CustomKeyHandler(CKI_BOTTOMRIGHT)) return 0; } #ifdef DEBUG_PROCVK _stprintf(buf,_T("RIGHT in limit=%d"),MapWindow::Y_BottomBar-NIBLSCALE(20)); DoStatusMessage(buf); #endif BottomBarChange(true); // advance BottomSounds(); MapWindow::RefreshMap(); return 0; } if ( X<s_xleft ) { // following is ugly if (keytime >=CustomKeyTime) { // 1 is left key if (CustomKeyHandler(CKI_BOTTOMLEFT)) return 0; } #ifdef DEBUG_PROCVK _stprintf(buf,_T("LEFT in limit=%d"),MapWindow::Y_BottomBar-NIBLSCALE(20)); DoStatusMessage(buf); #endif BottomBarChange(false); // backwards BottomSounds(); MapWindow::RefreshMap(); return 0; } #ifdef DEBUG_PROCVK _stprintf(buf,_T("CENTER in limit=%d"),MapWindow::Y_BottomBar-NIBLSCALE(20)); DoStatusMessage(buf); #endif // // VIRTUAL CENTER KEY HANDLING // // long press on center navbox // Activate following choices for testing and experimenting. Always disable for real usage. #if (0) // Output NMEA to device if (keytime>1000) { PlayResource(TEXT("IDR_WAV_HIGHCLICK")); devWriteNMEAString(devA(),_T("$PGRMCE")); Message::AddMessage(1000, 3, _T("NMEA out $PGRMCE")); return 0; } #endif #if (0) // Simulate incoming NMEA string if (keytime>1000) { static TCHAR mbuf[200]; _stprintf(mbuf,_T("$VARIO,1010.18,0.0,0.00,2.34,2,000.0,000.0*51\n")); NMEAParser::ParseNMEAString(0, (TCHAR *) mbuf, &GPS_INFO); return 0; } #endif #if (0) // TESTKEY // Print a message on the screen for debugging purposes TCHAR mbuf[100]; if (keytime>1000) { // _stprintf(mbuf,_T("Cache MCA %d/%d F=%d"), Cache_Hits_MCA, Cache_Calls_MCA, Cache_False_MCA ); char *point; point=(char*)&mbuf; *point++='A'; *point++='\0'; *point++='B'; *point++='\0'; *point++=0x06; *point++=0x01; *point++='C'; *point++='\0'; *point++='\0'; *point++='\0'; //mbuf[1]=0xc4; //mbuf[1]=0x86; Message::AddMessage(20000, 3, mbuf); return 0; } #endif #if (0) if (keytime>=CustomKeyTime) { if (OvertargetMode==OVT_MAXMODE) OvertargetMode=0; else OvertargetMode++; PlayResource(TEXT("IDR_WAV_HIGHCLICK")); return 0; } #endif #if (0) if (keytime>=CustomKeyTime) { PlayResource(TEXT("IDR_WAV_HIGHCLICK")); extern bool RunSignature(void); RunSignature(); return 0; } #endif #if (0) // Long press in center screen bottom bar if (keytime>=CustomKeyTime) { PlayResource(TEXT("IDR_WAV_HIGHCLICK")); extern void ReinitScreen(void); ReinitScreen(); return 0; } #endif // REAL USAGE, ALWAYS ACTIVATE #if (1) // standard configurable mode if (keytime >=CustomKeyTime) { // 0 is center key if (CustomKeyHandler(CKI_BOTTOMCENTER)) return 0; } #endif // normally, we fall down here. // If CustomKeyHandler returned false, back as well here (nothing configured in custom). // ///// If we are clicking on center bottom bar while still in welcome page, set map before nextmode. NextModeIndex(); MapWindow::RefreshMap(); SoundModeIndex(); return 0; // End click on navboxes } else // CLICK ON SORTBOX line at the top, only with no map and only for enabled pages if ( (Y<=SortBoxY[MapSpaceMode]) && ( MapSpaceMode == MSM_LANDABLE || MapSpaceMode==MSM_AIRPORTS || MapSpaceMode==MSM_NEARTPS || MapSpaceMode==MSM_TRAFFIC || MapSpaceMode==MSM_AIRSPACES || MapSpaceMode==MSM_THERMALS || MapSpaceMode==MSM_COMMON || MapSpaceMode==MSM_RECENT) ) { // only search for 1-3, otherwise it's the fourth (fifth really) // we don't use 0 now for (i=0, j=4; i<4; i++) { // i=1 original 090925 FIX if (X <SortBoxX[MapSpaceMode][i]) { j=i; break; } } #if 0 // 121123 CHECK AND REMOVE // 120504 if we are clicking on the already selected sort button, within the same mapspacemode, // then simulate a gesture down to advance to next page, if available. if ( (MapSpaceMode==oldMapSpaceMode && SortedMode[MapSpaceMode]==j) || (MapSpaceMode==MSM_COMMON) || (MapSpaceMode==MSM_RECENT) ) { vkmode=LKGESTURE_DOWN; goto shortcut_gesture; } else { oldMapSpaceMode=MapSpaceMode; // becomes current } #else if ( (SortedMode[MapSpaceMode]==j) || (MapSpaceMode==MSM_COMMON) || (MapSpaceMode==MSM_RECENT) ) { vkmode=LKGESTURE_DOWN; goto shortcut_gesture; } #endif switch(MapSpaceMode) { case MSM_LANDABLE: case MSM_AIRPORTS: case MSM_NEARTPS: SortedMode[MapSpaceMode]=j; LKForceDoNearest=true; PlayResource(TEXT("IDR_WAV_CLICK")); break; case MSM_TRAFFIC: SortedMode[MapSpaceMode]=j; // force immediate resorting LastDoTraffic=0; PlayResource(TEXT("IDR_WAV_CLICK")); break; case MSM_AIRSPACES: SortedMode[MapSpaceMode]=j; PlayResource(TEXT("IDR_WAV_CLICK")); break; case MSM_THERMALS: SortedMode[MapSpaceMode]=j; // force immediate resorting LastDoThermalH=0; PlayResource(TEXT("IDR_WAV_CLICK")); break; default: DoStatusMessage(_T("ERR-022 UNKNOWN MSM in VK")); break; } SelectedPage[MapSpaceMode]=0; SelectedRaw[MapSpaceMode]=0; MapWindow::RefreshMap(); return 0; // end sortbox } // end newmap with no gestures } // REAL virtual keys // Emulate real keypresses with wParam shortcut_gesture: // UP gesture if (vkmode>LKGESTURE_NONE) { // WE MANAGE GESTURES IN ALL MAPSPACES switch(MapSpaceMode) { case MSM_LANDABLE: case MSM_AIRPORTS: case MSM_NEARTPS: LKForceDoNearest=true; numpages=Numpages; break; case MSM_COMMON: LKForceDoCommon=true; numpages=Numpages; break; case MSM_RECENT: LKForceDoRecent=true; numpages=Numpages; break; case MSM_AIRSPACES: numpages=Numpages; break; case MSM_TRAFFIC: numpages=Numpages; break; case MSM_THERMALS: numpages=Numpages; break; default: break; } SelectedRaw[MapSpaceMode]=0; switch(vkmode) { // SCROLL DOWN case LKGESTURE_DOWN: // no pagedown for main map.. where do you want to go?? if (NOTANYPAN && IsMultiMapNoMain()) { LKevent=LKEVENT_PAGEDOWN; MapWindow::RefreshMap(); return 0; } // careful, selectedpage starts from 0 if (++SelectedPage[MapSpaceMode] >=numpages) { PlayResource(TEXT("IDR_WAV_HIGHCLICK")); SelectedPage[MapSpaceMode]=0; } else { PlayResource(TEXT("IDR_WAV_CLICK")); } LKevent=LKEVENT_NEWPAGE; MapWindow::RefreshMap(); return 0; // SCROLL UP case LKGESTURE_UP: // no pagedown for main map.. where do you want to go?? if (NOTANYPAN && IsMultiMapNoMain()) { LKevent=LKEVENT_PAGEUP; MapWindow::RefreshMap(); return 0; } if (--SelectedPage[MapSpaceMode] <0) { PlayResource(TEXT("IDR_WAV_CLICK")); SelectedPage[MapSpaceMode]=(numpages-1); } else { if (SelectedPage[MapSpaceMode]==0) { PlayResource(TEXT("IDR_WAV_HIGHCLICK")); } else { PlayResource(TEXT("IDR_WAV_CLICK")); } } LKevent=LKEVENT_NEWPAGE; MapWindow::RefreshMap(); return 0; case LKGESTURE_RIGHT: gesture_right: NextModeType(); MapWindow::RefreshMap(); // Notice: MultiMap has its own sounds. We come here when switching pages, but with // an exception: from moving map we generate currently a direct NextModeType from // MapWndProc, and thus we dont get ProcessVirtualKeys for that single case. // We should not be playing a CLICK sound while we are playing the MM tone, or // it wont come up ! if (ModeIndex!=LKMODE_MAP) { if (CURTYPE == 0) PlayResource(TEXT("IDR_WAV_HIGHCLICK")); else PlayResource(TEXT("IDR_WAV_CLICK")); } return 0; break; case LKGESTURE_LEFT: gesture_left: PreviousModeType(); MapWindow::RefreshMap(); if (ModeIndex!=LKMODE_MAP) { if (CURTYPE == 0) PlayResource(TEXT("IDR_WAV_HIGHCLICK")); else PlayResource(TEXT("IDR_WAV_CLICK")); } return 0; break; default: return 0; } return 0; } if (!MapWindow::mode.AnyPan() && (IsMultiMap()||MapSpaceMode==MSM_MAPTRK)) { if (keytime>=(VKSHORTCLICK*4)) { LKevent=LKEVENT_LONGCLICK; MapWindow::RefreshMap(); return 0; } } // UNGESTURES: // No need to use gestures if clicking on right or left center border screen // This will dramatically speed up the user interface in turbulence if (dontdrawthemap) { if (Y>longpress_yup && Y<longpress_ydown) { if (UseUngestures || !ISPARAGLIDER) { if (X<=MapWindow::X_Left) goto gesture_left; if (X>=MapWindow::X_Right) goto gesture_right; } } } /// /// REMOVE. ActiveMap always false /// ///if (!MapWindow::mode.AnyPan() && IsMultiMapNoMain() && ActiveMap) { /// LKevent=LKEVENT_SHORTCLICK; /// MapWindow::RefreshMap(); /// return 0; ///} if (Y<yup) { // we are processing up/down in mapspacemode i.e. browsing waypoints on the page if (dontdrawthemap) { if (MapSpaceMode<=MSM_MAP) { // DoStatusMessage(_T("DBG-032-A event up not used here")); return 0; } PlayResource(TEXT("IDR_WAV_CLICK")); LKevent=LKEVENT_UP; MapWindow::RefreshMap(); // DoStatusMessage(_T("DBG-032-B event up used here")); return 0; } PlayResource(TEXT("IDR_WAV_CLICK")); if (keytime>=VKTIMELONG) return 0xc1; else return 38; } if (Y>ydown) { if (dontdrawthemap) { if (MapSpaceMode<=MSM_MAP) return 0; PlayResource(TEXT("IDR_WAV_CLICK")); LKevent=LKEVENT_DOWN; MapWindow::RefreshMap(); return 0; } PlayResource(TEXT("IDR_WAV_CLICK")); if (keytime>=VKTIMELONG) return 0xc2; else return 40; } // This will not be detected in case of UP and DOWN was detected, of course. // We must handle this separately, before checking for UP DOWN, above. if (!MapWindow::mode.AnyPan() && IsMultiMap()) { LKevent=LKEVENT_SHORTCLICK; MapWindow::RefreshMap(); return 0; } // no click for already clicked events // If in mapspacemode process ENTER if ( (keytime>=(VKSHORTCLICK*2)) && dontdrawthemap && !IsMultiMap()) { LKSound(_T("LK_BEEP1.WAV")); LKevent=LKEVENT_ENTER; MapWindow::RefreshMap(); return 0; } /* // do not process enter in panmode, unused if ( !MapWindow::mode.AnyPan() ) { DoStatusMessage(_T("Virtual ENTER")); return 13; } */ // // Here we are when short clicking in the center area, not an up and not a down.. a center. // We do nothing. // if (SIMMODE) { if ( MapWindow::mode.AnyPan() && ISPARAGLIDER) return 99; // 091221 return impossible value else return 0; } else { return 0; } DoStatusMessage(_T("VirtualKey Error")); return 0; }
void MapWindow::LKDrawMultimap_Asp(HDC hdc, const RECT rc) { RECT rci = rc; rci.bottom -= BottomSize; #if 0 if (DoInit[MDI_MAPASP]) { DoInit[MDI_MAPASP]=false; } #endif switch(LKevent) { // // USABLE EVENTS // case LKEVENT_NEWRUN: // Upon entering a new multimap, Active is forced reset. It should not be necessary ActiveMap=false; if (MapSpaceMode==MSM_VISUALGLIDE) { GetVisualGlidePoints(0); // reset upon entering! } break; case LKEVENT_TOPLEFT: IsMultimapConfigShown=true; InputEvents::setMode(_T("MMCONF")); break; case LKEVENT_TOPRIGHT: if (MapSpaceMode==MSM_MAPASP) { Sonar_IsEnabled = !Sonar_IsEnabled; if (EnableSoundModes) { if (Sonar_IsEnabled) LKSound(TEXT("LK_TONEUP.WAV")); else LKSound(TEXT("LK_TONEDOWN.WAV")); } } // ACTIVE is available only when there is a topview shown! if ( (MapSpaceMode==MSM_MAPTRK || MapSpaceMode==MSM_MAPWPT) && (Current_Multimap_TopRect.bottom>0)) { ActiveMap = !ActiveMap; if (EnableSoundModes) { if (ActiveMap) LKSound(TEXT("LK_TONEUP.WAV")); else LKSound(TEXT("LK_TONEDOWN.WAV")); } } break; default: // THIS SHOULD NEVER HAPPEN, but always CHECK FOR IT! break; } // // If the map is active in the proper mapspace, we shall manage here the action // if (LKevent==LKEVENT_SHORTCLICK && ActiveMap && (MapSpaceMode==MSM_MAPTRK || MapSpaceMode==MSM_MAPWPT)) { // // It would be a GOOD IDEA to keep this as a global, updated of course. // We need to know very often how is the screen splitted, and where! // It should be made global somewhere else, not here. // if ( YstartScreen < Current_Multimap_TopRect.bottom) { double Xstart, Ystart; SideviewScreen2LatLon(XstartScreen, YstartScreen, Xstart, Ystart); MapWindow::Event_NearestWaypointDetails(Xstart, Ystart, 1.0e5, false); LKevent=LKEVENT_NONE; ActiveMap=false; return; } } // // This is doing all rendering, including terrain and topology, which is not good. // #ifdef ENABLE_ALL_AS_FOR_SIDEVIEW int oldAltMode = AltitudeMode ; if (GetSideviewPage() == IM_NEAR_AS) AltitudeMode = ALLON; #endif RenderAirspace(hdc, rci); #ifdef ENABLE_ALL_AS_FOR_SIDEVIEW AltitudeMode = oldAltMode; #endif LKevent=LKEVENT_NONE; }
// // Called by LKDrawLook8000, this is what happens when we change mapspace mode, advancing through types. // We paint infopages, nearest, tri, etc.etc. // Normally there is plenty of cpu available because the map is not even calculated. // This is why we bring to the Draw thread, in the nearest pages case, also calculations. // void MapWindow::DrawMapSpace(HDC hdc, RECT rc ) { HFONT oldfont; HBRUSH hB; TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE*2]; #ifdef DRAWLKSTATUS bool dodrawlkstatus=false; #endif static POINT p[10]; if (MapSpaceMode==MSM_WELCOME) { if (INVERTCOLORS) hB=LKBrush_Petrol; else hB=LKBrush_Mlight; } else { if (INVERTCOLORS) hB=LKBrush_Mdark; else hB=LKBrush_Mlight; } oldfont = (HFONT)SelectObject(hdc, LKINFOFONT); // save font if (MapSpaceMode!=MSM_WELCOME) FillRect(hdc,&rc, hB); if (DoInit[MDI_DRAWMAPSPACE]) { p[0].x=0; p[0].y=rc.bottom-BottomSize-NIBLSCALE(2); p[1].x=rc.right-1; p[1].y=p[0].y; p[2].x=0; p[2].y=0; p[3].x=rc.right-1; p[3].y=0; // 091230 right-1 p[4].x=0; p[4].y=0; p[5].x=0; p[5].y=rc.bottom-BottomSize-NIBLSCALE(2); p[6].x=rc.right-1; p[6].y=0; p[7].x=rc.right-1; p[7].y=rc.bottom-BottomSize-NIBLSCALE(2); // 091230 right-1 // p[8].x=0; p[8].y=rc.bottom-BottomSize-NIBLSCALE(2); p[9].x=rc.right; p[9].y=p[8].y; /* StartupStore(_T("DOINIT DRAWMAPSPACE 21=%d=%d 22=%d=%d 23=%d=%d 24=%d=%d 31=%d=%d 32=%d=%d\n"), ConfIP[LKMODE_WP][0],ConfIP21, ConfIP[LKMODE_WP][1],ConfIP22, ConfIP[LKMODE_WP][2],ConfIP23, ConfIP[LKMODE_WP][3],ConfIP24, ConfIP[LKMODE_NAV][0],ConfIP31, ConfIP[LKMODE_NAV][1],ConfIP32); */ if (MapSpaceMode==MSM_WELCOME) LoadSplash(hdc,_T("LKPROFILE")); DoInit[MDI_DRAWMAPSPACE]=false; } // Paint borders in green, but only in nearest pages and welcome if (MapSpaceMode==MSM_WELCOME || (!IsMultiMap() && MapSpaceMode!=MSM_MAP) ) { if (INVERTCOLORS) { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_GREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_GREEN, rc); } else { _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[2], p[3], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[4], p[5], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[6], p[7], RGB_DARKGREEN, rc); _DrawLine(hdc, PS_SOLID, NIBLSCALE(1), p[0], p[1], RGB_DARKGREEN, rc); } } #ifdef DRAWLKSTATUS if (LKevent==LKEVENT_NEWRUN) dodrawlkstatus=true; #endif // We are entering mapspacemodes with no initial check on configured subpages. // Thus we need to ensure that the page is really available, or find the first valid. // However, this will prevent direct customkey access to pages! // Instead, we do it when we call next page from InfoPageChange // if (!ConfIP[ModeIndex][CURTYPE]) NextModeType(); switch (MapSpaceMode) { case MSM_WELCOME: #if (1) if (!DrawInfo.NAVWarning) { static double firsttime=DrawInfo.Time; // delayed automatic exit from welcome mode if ( DrawInfo.Time > (firsttime+1.0) ) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; if (EnableSoundModes) LKSound(_T("LK_BEEP1.WAV")); RefreshMap(); break; } } #endif if(GlobalModelType==MODELTYPE_PNA_MINIMAP) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } DrawWelcome8000(hdc, rc); break; case MSM_MAPTRK: SetSideviewPage(IM_HEADING); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPWPT: #if 0 // If there is no destination, force jump to the map if (GetOvertargetIndex()<0) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } #endif SetSideviewPage(IM_NEXT_WP); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPASP: SetSideviewPage(IM_NEAR_AS); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPRADAR: LKDrawMultimap_Radar(hdc,rc); break; case MSM_VISUALGLIDE: SetSideviewPage(IM_VISUALGLIDE); LKDrawMultimap_Asp(hdc,rc); break; case MSM_MAPTEST: LKDrawMultimap_Test(hdc,rc); break; case MSM_LANDABLE: case MSM_NEARTPS: case MSM_AIRPORTS: DrawNearest(hdc, rc); break; case MSM_AIRSPACES: DrawAspNearest(hdc, rc); break; case MSM_COMMON: case MSM_RECENT: DrawCommon(hdc, rc); break; case MSM_MAP: break; case MSM_INFO_THERMAL: case MSM_INFO_CRUISE: case MSM_INFO_TASK: case MSM_INFO_AUX: case MSM_INFO_TRI: case MSM_INFO_HSI: case MSM_INFO_TRF: case MSM_INFO_TARGET: case MSM_INFO_CONTEST: DrawInfoPage(hdc,rc, false); break; case MSM_TRAFFIC: DrawTraffic(hdc,rc); break; case MSM_THERMALS: DrawThermalHistory(hdc,rc); break; default: memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.NoSetFont = 1; TextDisplayMode.AlligneCenter = 1; SelectObject(hdc, LK8TargetFont); _stprintf(Buffer,TEXT("MapSpaceMode=%d"),MapSpaceMode); TextInBox(hdc, &rc, Buffer, (rc.right-rc.left)/2, NIBLSCALE(50) , 0, &TextDisplayMode, false); break; } #ifdef DRAWLKSTATUS // no need to clear dodrawlkstatus, it is already reset at each run if (dodrawlkstatus) DrawLKStatus(hdc, rc); #endif SelectObject(hdc, oldfont); }
// Called periodically to show new airspace warning messages to user // return 1 only for requesting run analysis // This is called by WINMAIN thread, every second (1hz) short ShowAirspaceWarningsToUser() { if (msg.originator != NULL) return 0; // Dialog already open bool there_is_message = CAirspaceManager::Instance().PopWarningMessage(&msg); if (!there_is_message) return 0; // no message to display airspace_copy = CAirspaceManager::Instance().GetAirspaceCopy(msg.originator); bool ackdialog_required = false; TCHAR msgbuf[128]; // which message we need to show? switch (msg.event) { default: // normally not show DoStatusMessage(TEXT("Unknown airspace warning message")); break; //Unknown msg type case aweNone: case aweMovingInsideFly: // normal, no msg, normally this msg type shouldn't get here case awePredictedEnteringFly: // normal, no msg, normally this msg type shouldn't get here case aweMovingOutsideNonfly: // normal, no msg, normally this msg type shouldn't get here break; case awePredictedLeavingFly: case aweNearOutsideFly: case aweLeavingFly: case awePredictedEnteringNonfly: case aweNearInsideNonfly: case aweEnteringNonfly: case aweMovingInsideNonfly: // repeated messages case aweMovingOutsideFly: // repeated messages ackdialog_required = true; break; case aweEnteringFly: // LKTOKEN _@M1240_ "Entering" if( _tcsnicmp( airspace_copy.Name(), airspace_copy.TypeName() ,_tcslen(airspace_copy.TypeName())) == 0) _stprintf(msgbuf,TEXT("%s %s"),gettext(TEXT("_@M1240_")),airspace_copy.Name()); else _stprintf(msgbuf,TEXT("%s %s %s"),gettext(TEXT("_@M1240_")),airspace_copy.TypeName(),airspace_copy.Name()); // wsprintf(msgbuf, TEXT("%s %s %s "), gettext(TEXT("_@M1240_")),airspace_copy.TypeName(), airspace_copy.Name()); DoStatusMessage(msgbuf); break; case aweLeavingNonFly: // LKTOKEN _@M1241_ "Leaving" if( _tcsnicmp( airspace_copy.Name(), airspace_copy.TypeName() ,_tcslen(airspace_copy.TypeName())) == 0) _stprintf(msgbuf,TEXT("%s %s"),gettext(TEXT("_@M1241_")),airspace_copy.Name()); else _stprintf(msgbuf,TEXT("%s %s %s"),gettext(TEXT("_@M1241_")),airspace_copy.TypeName(),airspace_copy.Name()); // wsprintf(msgbuf, TEXT("%s %s %s"), gettext(TEXT("_@M1241_")),airspace_copy.TypeName(), airspace_copy.Name()); DoStatusMessage(msgbuf); break; } // show dialog to user if needed if (ackdialog_required && (airspace_copy.WarningLevel() == msg.warnlevel)) { if (!ScreenLandscape) dlg = dlgLoadFromXML(CallBackTable, NULL, hWndMainWindow, TEXT("IDR_XML_LKAIRSPACEWARNING_L")); else dlg = dlgLoadFromXML(CallBackTable, NULL, hWndMainWindow, TEXT("IDR_XML_LKAIRSPACEWARNING")); if (dlg==NULL) { StartupStore(_T("------ LKAirspaceWarning setup FAILED!%s"),NEWLINE); //@ 101027 return 0; } dlg->SetKeyDownNotify(OnKeyDown); dlg->SetTimerNotify(OnTimer); timer_counter = AirspaceWarningDlgTimeout; // Auto closing dialog in x secs WndButton *wb = (WndButton*)dlg->FindByName(TEXT("cmdAckForTime")); if (wb) { TCHAR stmp2[40]; wsprintf(stmp2,TEXT("%s (%dmin)"), gettext(TEXT("_@M46_")), AcknowledgementTime/60); wb->SetCaption(stmp2); } dlgLKAirspaceFill(); #ifndef DISABLEAUDIO if (EnableSoundModes) LKSound(_T("LK_AIRSPACE.WAV")); // 100819 #endif if( _tcsnicmp( airspace_copy.Name(), airspace_copy.TypeName() ,_tcslen(airspace_copy.TypeName())) == 0) _stprintf(msgbuf,TEXT("%s"),airspace_copy.Name()); else _stprintf(msgbuf,TEXT("%s %s"),airspace_copy.TypeName(),airspace_copy.Name()); // _stprintf(msgbuf,_T("%s: %s %s"),gettext(_T("_@M68_")),airspace_copy.TypeName(),airspace_copy.Name()); dlg->SetCaption(msgbuf); dlg->ShowModal(); delete dlg; dlg = NULL; } msg.originator = NULL; // If we clicked on Analysis button, we shall return 1 and the calling function will // detect and take care of it. // 120128 unused, we call directly eventSetup return 1; }
// Remember that this function is called at 2hz static int OnTimerNotify(WindowControl *Sender) { static short rezoom=0; static short limiter=0; // safe limiter #define ORCREZOOM 2 // We wait for some time before forcing nearest search, because we need to be sure // that the visibility scan is updated if (--WaitToCallForce>0) { if (WaitToCallForce==1) { #ifdef DEBUG_ORTIMER StartupStore(_T("..... Force Calculation\n")); #endif MapWindow::RefreshMap(); // trigger rescan or we shall wait for 2 seconds more! LKSW_ForceNearestTopologyCalculation=true; // set wait times for zoom effective in the background and return rezoom=ORCREZOOM; limiter=0; } #ifdef DEBUG_ORTIMER else { StartupStore(_T("..... WaitToCallForce\n")); } #endif return 0; } // If the Nearest topology calculation is still running we wait if (LKSW_ForceNearestTopologyCalculation) { if (++limiter > 20) { // Something is wrong, lets get out of here because there is no exit button! StartupStore(_T("...... Oracle ForceNearestTopo limit exceeded, aborting search%s"),NEWLINE); LKSW_ForceNearestTopologyCalculation=false; // time exceeded, reset forced limiter=0; rezoom=0; goto _end; } #ifdef DEBUG_ORTIMER StartupStore(_T("..... Wait for ForceNearest done\n")); #endif return 0; } limiter=0; // probably useless // Ok the ForceNearestTopo was cleared by Terrain search, so we have the nearesttopo items ready. // Do we need still to rezoom for letting whereami search for nearest waypoints in a visibility // screen range? if (rezoom>0) { // Extend a wide search of farvisible items // We do it now that nearestTopology has been calculated, // because WhereAmI will issue some Nearest search on waypoints // and we need to include airports a bit more far away if (rezoom==ORCREZOOM) { #ifdef DEBUG_ORTIMER StartupStore(_T("..... REZOOM\n")); #endif MapWindow::zoom.EventSetZoom(6); MapWindow::ForceVisibilityScan=true; MapWindow::RefreshMap(); } #ifdef DEBUG_ORTIMER else StartupStore(_T("..... WAIT AFTER REZOOM\n")); #endif // rezoom once, then wait rezoom--; return 0; } _end: #ifdef DEBUG_ORTIMER StartupStore(_T("..... LETS GO\n")); #endif // Dont come back here anymore! wf->SetTimerNotify(NULL); // Bell, and print results if (EnableSoundModes) LKSound(TEXT("LK_GREEN.WAV")); WhereAmI(); // Remember to force exit from showmodal, because there is no Close button wf->SetModalResult(mrOK); return 0; }
// handle custom keys. Input: key pressed (center, left etc.) // Returns true if handled successfully, false if not // // Passthrough mode for keys>=1000 (custom menu keys) // bool CustomKeyHandler(const int key) { int ckeymode; static bool doinit=true; static int oldModeIndex; if (doinit) { oldModeIndex=LKMODE_INFOMODE;; doinit=false; } if (key>=1000) { ckeymode=key-1000; LKASSERT((ckeymode>=0 && ckeymode<ckTOP)); goto passthrough; } switch(key) { case CKI_BOTTOMCENTER: ckeymode=CustomKeyModeCenter; break; case CKI_BOTTOMLEFT: ckeymode=CustomKeyModeLeft; break; case CKI_BOTTOMRIGHT: ckeymode=CustomKeyModeRight; break; case CKI_BOTTOMICON: ckeymode=CustomKeyModeAircraftIcon; break; case CKI_TOPLEFT: ckeymode=CustomKeyModeLeftUpCorner; break; case CKI_TOPRIGHT: ckeymode=CustomKeyModeRightUpCorner; break; case CKI_CENTERSCREEN: ckeymode=CustomKeyModeCenterScreen; break; default: DoStatusMessage(_T("ERR-725 UNKNOWN CUSTOMKEY")); return false; break; } passthrough: switch(ckeymode) { case ckDisabled: break; case ckZoomIn: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif MapWindow::zoom.EventScaleZoom(1); return true; break; case ckZoomInMore: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif MapWindow::zoom.EventScaleZoom(2); return true; break; case ckZoomOut: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif MapWindow::zoom.EventScaleZoom(-1); return true; break; case ckZoomOutMore: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif MapWindow::zoom.EventScaleZoom(-2); return true; break; case ckMenu: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif ShowMenu(); return true; case ckBackMode: PreviousModeIndex(); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckToggleMap: //TODO if (ModeIndex==LKMODE_MAP) SetModeIndex(oldModeIndex); else { oldModeIndex=ModeIndex; SetModeIndex(LKMODE_MAP); } MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckTrueWind: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::setMode(_T("TrueWind")); return true; case ckTeamCode: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventSetup(_T("Teamcode")); return true; case ckToggleOverlays: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif ToggleMultimapOverlays(); return true; case ckToggleMapLandable: if (ModeIndex==LKMODE_MAP) SetModeIndex(LKMODE_WP); else SetModeIndex(LKMODE_MAP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckLandables: SetModeIndex(LKMODE_WP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckToggleMapCommons: if (ModeIndex==LKMODE_MAP) SetModeIndex(LKMODE_NAV); else SetModeIndex(LKMODE_MAP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckCommons: SetModeIndex(LKMODE_NAV); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckToggleMapTraffic: if (ModeIndex==LKMODE_MAP) SetModeIndex(LKMODE_TRF); else SetModeIndex(LKMODE_MAP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckTraffic: SetModeIndex(LKMODE_TRF); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckInvertColors: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventInvertColor(NULL); return true; case ckTimeGates: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventTimeGates(NULL); return true; case ckMarkLocation: InputEvents::eventMarkLocation(_T("")); return true; case ckAutoZoom: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventZoom(_T("auto toggle")); InputEvents::eventZoom(_T("auto show")); return true; case ckActiveMap: // NO MORE USED BUT KEPT FOR OPTIMIZING COMPILER return true; case ckBooster: DoStatusMessage(_T("FEEL THE THERMAL")); if (EnableSoundModes) LKSound(_T("LK_BOOSTER.WAV")); return true; case ckGoHome: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif if (ValidWayPoint(HomeWaypoint)) { if ( (ValidTaskPoint(ActiveWayPoint)) && (Task[ActiveWayPoint].Index == HomeWaypoint )) { // LKTOKEN _@M82_ = "Already going home" DoStatusMessage(gettext(TEXT("_@M82_"))); } else { GotoWaypoint(HomeWaypoint); } } else // LKTOKEN _@M465_ = "No Home to go!" DoStatusMessage(gettext(TEXT("_@M465_"))); return true; case ckPanorama: if (PGZoomTrigger==false) PGZoomTrigger=true; else LastZoomTrigger=0; #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif return true; case ckMultitargetRotate: RotateOvertarget(); return true; case ckMultitargetMenu: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::setMode(_T("MTarget")); return true; case ckBaroToggle: ToggleBaroAltitude(); return true; case ckBasicSetup: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventSetup(_T("Basic")); return true; case ckSimMenu: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::setMode(_T("SIMMENU")); return true; case ckToggleMapAirspace: if (ModeIndex==LKMODE_MAP) SetModeType(LKMODE_WP,WP_AIRSPACES); else SetModeIndex(LKMODE_MAP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckAirspaceAnalysis: SetModeType(LKMODE_MAP,MP_MAPASP); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckOptimizeRoute: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif PGOptimizeRoute=!PGOptimizeRoute; if (ISPARAGLIDER && PGOptimizeRoute) { AATEnabled = true; ClearOptimizedTargetPos(); } return true; case ckLockScreen: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventService(_T("LOCKMODE")); return true; case ckWhereAmI: // no sound here, chime is played by service event InputEvents::eventService(_T("ORACLE")); return true; case ckUseTotalEnergy: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventService(_T("TOTALEN")); return true; case ckNotepad: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventChecklist(_T("")); return true; case ckTerrainColors: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventService(_T("TERRCOL")); return true; case ckNearestAirspace: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventNearestAirspaceDetails(NULL); return true; case ckOlcAnalysis: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventSetup(_T("OlcAnalysis")); return true; case ckTerrainColorsBack: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventService(_T("TERRCOLBACK")); return true; case ckForceFreeFlightRestart: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif if (!CALCULATED_INFO.Flying) { DoStatusMessage(MsgToken(922)); // NOT FLYING } else { if (MessageBoxX(hWndMapWindow, MsgToken(1754), _T(""), MB_YESNO|MB_ICONQUESTION) == IDYES) { LKSW_ForceFreeFlightRestart=true; } } return true; case ckCustomMenu1: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif extern void dlgCustomMenuShowModal(void); InputEvents::eventMode(_T("MYMODE")); return true; case ckTaskCalc: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventCalculator(NULL); return true; case ckTaskTarget: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventSetup(_T("Target")); return true; case ckArmAdvance: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventArmAdvance(_T("toggle")); InputEvents::eventArmAdvance(_T("show")); return true; case ckMessageRepeat: InputEvents::eventRepeatStatusMessage(NULL); return true; case ckWaypointLookup: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventWaypointDetails(_T("select")); return true; case ckPan: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventPan(_T("toggle")); return true; case ckWindRose: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif UseWindRose=!UseWindRose; return true; case ckFlarmRadar: SetModeType(LKMODE_MAP,MP_RADAR); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckDeviceA: if(devA() && devA()->Config) { devA()->Config(devA()); } return true; case ckDeviceB: if(devB() && devB()->Config) { devB()->Config(devB()); } return true; case ckResetOdometer: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif if (MessageBoxX(hWndMapWindow, MsgToken(2229), _T(""), MB_YESNO|MB_ICONQUESTION) == IDYES) { LKSW_ResetOdometer=true; } return true; case ckForceLanding: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif if ( !CALCULATED_INFO.Flying ) { DoStatusMessage(MsgToken(922)); // NOT FLYING } else { if ( (GPS_INFO.Speed > TakeOffSpeedThreshold) && (!GPS_INFO.NAVWarning) ) { DoStatusMessage(MsgToken(1799)); // STOP MOVING! } else { if (MessageBoxX(hWndMapWindow, MsgToken(2230), _T(""), MB_YESNO|MB_ICONQUESTION) == IDYES) { LKSW_ForceLanding=true; } } } return true; case ckResetTripComputer: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif if (MessageBoxX(hWndMapWindow, MsgToken(2236), _T(""), MB_YESNO|MB_ICONQUESTION) == IDYES) { LKSW_ResetTripComputer=true; } return true; case ckSonarToggle: SonarWarning = !SonarWarning; TCHAR sonarmsg[60]; _stprintf(sonarmsg,_T("%s "),MsgToken(1293)); // SONAR if (SonarWarning) _tcscat(sonarmsg,MsgToken(1643)); // ENABLED else _tcscat(sonarmsg,MsgToken(1600)); // DISABLED DoStatusMessage(sonarmsg,NULL,false); if (EnableSoundModes) { if (SonarWarning) LKSound(TEXT("LK_TONEUP.WAV")); else LKSound(TEXT("LK_TONEDOWN.WAV")); } return true; case ckResetView: ModeType[LKMODE_MAP] = MP_MOVING; ModeType[LKMODE_INFOMODE]= IM_CRUISE; ModeType[LKMODE_WP] = WP_AIRPORTS; ModeType[LKMODE_NAV] = NV_COMMONS; ModeType[LKMODE_TRF] = TF_LIST; SetModeType(LKMODE_MAP,MP_MOVING); MapWindow::RefreshMap(); SoundModeIndex(); return true; case ckMapOrient: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif TCHAR MapOrientMsg[60]; if (MapSpaceMode==MSM_MAP) { DisplayOrientation++; if(DisplayOrientation > NORTHSMART) DisplayOrientation = 0; MapWindow::SetAutoOrientation(true); // 101008 reset it switch(DisplayOrientation) { case TRACKUP : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M737_"))) ; break; // _@M737_ "Track up" case NORTHUP : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M483_"))) ; break; // _@M483_ "North up" case NORTHCIRCLE : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M482_"))) ; break; // _@M482_ "North circling" case TRACKCIRCLE : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M682_"))) ; break; // _@M682_ "Target circling" _@M485_ "NorthUp above " case NORTHTRACK : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M484_"))) ; break; // _@M484_ "North/track" case NORTHSMART : _stprintf(MapOrientMsg,_T("%s"),gettext(TEXT("_@M481_"))) ; break; // _@M481_ "North Smart" } DoStatusMessage(MapOrientMsg,NULL,false); } else { SetMMNorthUp(GetSideviewPage(), (GetMMNorthUp(GetSideviewPage())+1)%2); } return true; case ckResetComm: #ifndef DISABLEAUDIO if (EnableSoundModes) PlayResource(TEXT("IDR_WAV_CLICK")); #endif InputEvents::eventRestartCommPorts(NULL); return true; default: DoStatusMessage(_T("ERR-726 INVALID CUSTOMKEY")); StartupStore(_T("... ERR-726 INVALID CUSTOMKEY=%d\n"),ckeymode); break; } return false; }
void LKBatteryManager() { static bool invalid=false, recharging=false; static bool warn33=true, warn50=true, warn100=true; static double last_time=0, init_time=0; static int last_percent=0, last_status=0; if (invalid) return; if (DoInit[MDI_BATTERYMANAGER]) { invalid=false, recharging=false; warn33=true, warn50=true, warn100=true; last_time=0, init_time=0; last_percent=0, last_status=0; numwarn=0; if (PDABatteryPercent<1 || PDABatteryPercent>100) { StartupStore(_T("... LK BatteryManager V1: internal battery information not available, function disabled%s"), NEWLINE); invalid=true; DoInit[MDI_BATTERYMANAGER]=false; // just to be sure return; } StartupStore(_T(". LK Battery Manager V1 started, current charge=%d%%%s"),PDABatteryPercent,NEWLINE); init_time=GPS_INFO.Time; DoInit[MDI_BATTERYMANAGER]=false; } // if first run, and not passed 30 seconds, do nothing if (last_percent==0 && (GPS_INFO.Time<(init_time+30))) { // StartupStore(_T("... first run, waiting for 30s\n")); return; } TCHAR mbuf[100]; // first run after 30 seconds: give a message if (last_percent==0) { // StartupStore(_T("... first run, last percent=0\n")); if (PDABatteryPercent <=50) { last_time=GPS_INFO.Time; // LKTOKEN _@M1352_ "BATTERY LEVEL" _stprintf(mbuf,_T("%s %d%%"), gettext(TEXT("_@M1352_")), PDABatteryPercent); DoStatusMessage(mbuf); warn50=false; } // special case, pdabattery is 0... if (PDABatteryPercent <1) { StartupStore(_T("... LK Battery Manager disabled, low battery %s"),NEWLINE); // LKTOKEN _@M1353_ "BATTERY MANAGER DISABLED" DoStatusMessage(gettext(TEXT("_@M1353_"))); invalid=true; return; } else last_percent=PDABatteryPercent; if (PDABatteryStatus!=AC_LINE_UNKNOWN) { last_status=PDABatteryStatus; } // StartupStore(_T("... last_percent first assigned=%d\n"),last_percent); return; } if (PDABatteryStatus!=AC_LINE_UNKNOWN) { if (last_status != PDABatteryStatus) { if (PDABatteryStatus==AC_LINE_OFFLINE) { if (GiveBatteryWarnings()) // LKTOKEN _@M514_ = "POWER SUPPLY OFF" DoStatusMessage(gettext(TEXT("_@M514_"))); } else { if (PDABatteryStatus==AC_LINE_ONLINE) { if (GiveBatteryWarnings()) // LKTOKEN _@M515_ = "POWER SUPPLY ON" DoStatusMessage(gettext(TEXT("_@M515_"))); } else { if (PDABatteryStatus==AC_LINE_BACKUP_POWER) { if (GiveBatteryWarnings()) // LKTOKEN _@M119_ = "BACKUP POWER SUPPLY ON" DoStatusMessage(gettext(TEXT("_@M119_"))); } } } } last_status=PDABatteryStatus; } // Only check every 5 minutes normally if (GPS_INFO.Time<(last_time+(60*5))) return; // if battery is recharging, reset warnings and do nothing if (last_percent<PDABatteryPercent) { warn33=true; warn50=true; warn100=true; last_percent=PDABatteryPercent; if (!recharging) { recharging=true; if (PDABatteryFlag==BATTERY_FLAG_CHARGING || PDABatteryStatus==AC_LINE_ONLINE) { if (GiveBatteryWarnings()) // LKTOKEN _@M124_ = "BATTERY IS RECHARGING" DoStatusMessage(gettext(TEXT("_@M124_"))); last_time=GPS_INFO.Time; } } return; } // if battery is same level, do nothing except when 100% during recharge if (last_percent == PDABatteryPercent) { if (recharging && (PDABatteryPercent==100) && warn100) { if (GiveBatteryWarnings()) // LKTOKEN _@M123_ = "BATTERY 100% CHARGED" DoStatusMessage(gettext(TEXT("_@M123_"))); warn100=false; last_time=GPS_INFO.Time; } return; } // else battery is discharging recharging=false; // Time to give a message to the user, if necessary if (PDABatteryPercent <=5) { // LKTOKEN _@M1354_ "BATTERY LEVEL CRITIC!" _stprintf(mbuf,_T("%d%% %s"), PDABatteryPercent, gettext(TEXT("_@M1354_"))); DoStatusMessage(mbuf); #ifndef DISABLEAUDIO LKSound(TEXT("LK_RED.WAV")); #endif // repeat after 1 minute, forced last_time=GPS_INFO.Time-(60*4); last_percent=PDABatteryPercent; return; } if (PDABatteryPercent <=10) { // LKTOKEN _@M1355_ "BATTERY LEVEL VERY LOW!" _stprintf(mbuf,_T("%d%% %s"), PDABatteryPercent, gettext(TEXT("_@M1355_"))); DoStatusMessage(mbuf); // repeat after 2 minutes, forced last_time=GPS_INFO.Time-(60*3); last_percent=PDABatteryPercent; return; } if (PDABatteryPercent <=20) { // LKTOKEN _@M1356_ "BATTERY LEVEL LOW!" _stprintf(mbuf,_T("%d%% %s"), PDABatteryPercent, gettext(TEXT("_@M1356_"))); DoStatusMessage(mbuf); last_time=GPS_INFO.Time; last_percent=PDABatteryPercent; return; } if (PDABatteryPercent <=30) { if (warn33) { // LKTOKEN _@M1352_ "BATTERY LEVEL" _stprintf(mbuf, _T("%s %d%%"), gettext(TEXT("_@M1352_")), PDABatteryPercent); DoStatusMessage(mbuf); warn33=false; } last_time=GPS_INFO.Time; last_percent=PDABatteryPercent; return; } // DISABLED if (PDABatteryPercent <=50) { if (warn50) { // LKTOKEN _@M1352_ "BATTERY LEVEL" // _stprintf(mbuf, _T("%s %d%%"), gettext(TEXT("_@M1352_")), PDABatteryPercent); // DoStatusMessage(mbuf); warn50=false; } last_time=GPS_INFO.Time; last_percent=PDABatteryPercent; return; } }