// Loads a new task from scratch. // This is called on startup by the even manager because in DEFAULT MENU we have a GCE event // configured to load Default.tsk for STARTUP_SIMULATOR and STARTUP_REAL. // Until we change this, which would be a good thing because these configuration are unnecessary , // we must use the FullResetAsked trick. void LoadNewTask(LPCTSTR szFileName) { TASK_POINT Temp; START_POINT STemp; int i; bool TaskInvalid = false; bool WaypointInvalid = false; bool TaskLoaded = false; char taskinfo[LKPREAMBOLSIZE+1]; // 100207 bool oldversion=false; // 100207 TCHAR taskFileName[MAX_PATH]; LockTaskData(); ClearTask(); if (FullResetAsked) { #if TESTBENCH StartupStore(_T("... LoadNewTask detected FullResetAsked, attempt to load DEMO.TSK\n")); #endif // Clear the flag, forever. FullResetAsked=false; _tcscpy(taskFileName,_T("%LOCAL_PATH%\\\\_Tasks\\DEMO.TSK")); ExpandLocalPath(taskFileName); } else { _tcscpy(taskFileName,szFileName); } StartupStore(_T(". LoadNewTask <%s>%s"),taskFileName,NEWLINE); FILE* stream = _tfopen(taskFileName, _T("rb")); if(stream) { // Defaults int old_StartLine = StartLine; int old_SectorType = SectorType; DWORD old_SectorRadius = SectorRadius; DWORD old_StartRadius = StartRadius; int old_AutoAdvance = AutoAdvance; double old_AATTaskLength = AATTaskLength; BOOL old_AATEnabled = AATEnabled; DWORD old_FinishRadius = FinishRadius; int old_FinishLine = FinishLine; bool old_EnableMultipleStartPoints = EnableMultipleStartPoints; TaskLoaded = true; if(fread(taskinfo, sizeof(char), LKPREAMBOLSIZE, stream) != LKPREAMBOLSIZE) { TaskInvalid = true; goto goEnd; } // task version check if ( (taskinfo[0]!= 'L') || (taskinfo[1]!= 'K') || (taskinfo[2]!=LKTASKVERSION) ) { TaskInvalid = true; oldversion = true; goto goEnd; } for(i=0;i<OLD_MAXTASKPOINTS;i++) { if(fread(&Temp, 1, sizeof(OLD_TASK_POINT), stream) != sizeof(OLD_TASK_POINT)) { TaskInvalid = true; break; } if(i < MAXTASKPOINTS) { memcpy(&Task[i],&Temp, sizeof(OLD_TASK_POINT)); if( !ValidNotResWayPoint(Temp.Index) && (Temp.Index != -1) ) { // 091213 // Task is only invalid here if the index is out of range // of the waypoints and not equal to -1. // (Because -1 indicates a null task item) WaypointInvalid = true; } } } if (!TaskInvalid) { TaskInvalid = fread(&AATEnabled, 1, sizeof(BOOL), stream) != sizeof(BOOL); } if (!TaskInvalid) { TaskInvalid = fread(&AATTaskLength, 1, sizeof(double), stream) != sizeof(double); } // ToDo review by JW // 20060521:sgi added additional task parameters if (!TaskInvalid) { TaskInvalid = fread(&FinishRadius, 1, sizeof(FinishRadius), stream) != sizeof(FinishRadius); } if (!TaskInvalid) { TaskInvalid = fread(&FinishLine, 1, sizeof(FinishLine), stream) != sizeof(FinishLine); } if (!TaskInvalid) { TaskInvalid = fread(&StartRadius, 1, sizeof(StartRadius), stream) != sizeof(StartRadius); } if (!TaskInvalid) { TaskInvalid = fread(&StartLine, 1, sizeof(StartLine), stream) != sizeof(StartLine); } if (!TaskInvalid) { TaskInvalid = fread(&SectorType, 1, sizeof(SectorType), stream) != sizeof(SectorType); } if (!TaskInvalid) { TaskInvalid = fread(&SectorRadius, 1, sizeof(SectorRadius), stream) != sizeof(SectorRadius); } if (!TaskInvalid) { TaskInvalid = fread(&AutoAdvance, 1, sizeof(AutoAdvance), stream) != sizeof(AutoAdvance); } if (!TaskInvalid) { TaskInvalid = fread(&EnableMultipleStartPoints, 1, sizeof(EnableMultipleStartPoints), stream) != sizeof(EnableMultipleStartPoints); } for(i=0;i<MAXSTARTPOINTS;i++) { if(fread(&STemp, 1, sizeof(START_POINT), stream) != sizeof(START_POINT)) { TaskInvalid = true; break; } if( ValidNotResWayPoint(STemp.Index) || (STemp.Index==-1) ) { // 091213 memcpy(&StartPoints[i],&STemp, sizeof(START_POINT)); } else { WaypointInvalid = true; StartupStore(_T("--- LoadNewTask: invalid waypoint=%d found%s"),STemp.Index,NEWLINE); // 091213 } } // search for waypoints... if (!TaskInvalid) { if (!LoadTaskWaypoints(stream) && WaypointInvalid) { // couldn't lookup the waypoints in the file and we know there are invalid waypoints TaskInvalid = true; StartupStore(_T(". LoadTaskNew: cant locate waypoint in file, and invalid wp in task file%s"),NEWLINE); } } // TimeGate config if (!TaskInvalid) { TaskInvalid = fread(&PGOpenTimeH, 1, sizeof(PGOpenTimeH), stream) != sizeof(PGOpenTimeH); } if (!TaskInvalid) { TaskInvalid = fread(&PGOpenTimeM, 1, sizeof(PGOpenTimeM), stream) != sizeof(PGOpenTimeM); } if (!TaskInvalid) { InitActiveGate(); // PGOpenTime is Calculated ! int tmp; TaskInvalid = fread(&tmp, 1, sizeof(tmp), stream) != sizeof(tmp); } if (!TaskInvalid) { PGCloseTime=86399; // PGCloseTime is Calculated ! int tmp; TaskInvalid = fread(&tmp, 1, sizeof(tmp), stream) != sizeof(tmp); } if (!TaskInvalid) { TaskInvalid = fread(&PGGateIntervalTime, 1, sizeof(PGGateIntervalTime), stream) != sizeof(PGGateIntervalTime); } if (!TaskInvalid) { TaskInvalid = fread(&PGNumberOfGates, 1, sizeof(PGNumberOfGates), stream) != sizeof(PGNumberOfGates); } if (!TaskInvalid) { TaskInvalid = fread(&PGStartOut, 1, sizeof(PGStartOut), stream) != sizeof(PGStartOut); } goEnd: fclose(stream); if (TaskInvalid) { if (oldversion) StartupStore(_T("------ Task is invalid: old task format%s"),NEWLINE); else StartupStore(_T("------ Task is invalid%s"),NEWLINE); StartLine = old_StartLine; SectorType = old_SectorType; SectorRadius = old_SectorRadius; StartRadius = old_StartRadius; AutoAdvance = old_AutoAdvance; AATTaskLength = old_AATTaskLength; AATEnabled = old_AATEnabled; FinishRadius = old_FinishRadius; FinishLine = old_FinishLine; EnableMultipleStartPoints = old_EnableMultipleStartPoints; } } else { StartupStore(_T("... LoadNewTask: file <%s> not found%s"),taskFileName,NEWLINE); // 091213 TaskInvalid = true; } if (TaskInvalid) { ClearTask(); } RefreshTask(); if (!ValidTaskPoint(0)) { ActiveTaskPoint = 0; } UnlockTaskData(); if (TaskInvalid && TaskLoaded) { if (oldversion) { // LKTOKEN _@M360_ = "Invalid old task format!" MessageBoxX(MsgToken(360), // LKTOKEN _@M396_ = "Load task" MsgToken(396), mbOk); } else { // LKTOKEN _@M264_ = "Error in task file!" MessageBoxX(MsgToken(264), // LKTOKEN _@M396_ = "Load task" MsgToken(396), mbOk); } } else { #if TESTBENCH StartupStore(_T("------ Task is Loaded%s"),NEWLINE); #endif TaskModified = false; TargetModified = false; _tcscpy(LastTaskFileName, taskFileName); } }
// 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; } }
// Conversion between submenus and global mapspace modes // Basic initialization of global variables and parameters. // void InitModeTable() { short i,j; #if TESTBENCH StartupStore(_T(". Init ModeTable for LK8000: ")); #endif for (i=0; i<=LKMODE_TOP; i++) for (j=0; j<=MSM_TOP; j++) ModeTable[i][j]=INVALID_VALUE; // this table is for submenus, order is not important ModeTable[LKMODE_MAP][MP_WELCOME] = MSM_WELCOME; ModeTable[LKMODE_MAP][MP_MOVING] = MSM_MAP; ModeTable[LKMODE_MAP][MP_MAPTRK] = MSM_MAPTRK; ModeTable[LKMODE_MAP][MP_MAPWPT] = MSM_MAPWPT; ModeTable[LKMODE_MAP][MP_MAPASP] = MSM_MAPASP; ModeTable[LKMODE_MAP][MP_RADAR] = MSM_MAPRADAR; ModeTable[LKMODE_MAP][MP_TEST] = MSM_MAPTEST; ModeTable[LKMODE_WP][WP_AIRPORTS] = MSM_AIRPORTS; ModeTable[LKMODE_WP][WP_LANDABLE] = MSM_LANDABLE; ModeTable[LKMODE_WP][WP_NEARTPS] = MSM_NEARTPS; ModeTable[LKMODE_WP][WP_AIRSPACES] = MSM_AIRSPACES; ModeTable[LKMODE_INFOMODE][IM_CRUISE] = MSM_INFO_CRUISE; ModeTable[LKMODE_INFOMODE][IM_THERMAL] = MSM_INFO_THERMAL; ModeTable[LKMODE_INFOMODE][IM_TASK] = MSM_INFO_TASK; ModeTable[LKMODE_INFOMODE][IM_AUX] = MSM_INFO_AUX; ModeTable[LKMODE_INFOMODE][IM_CONTEST] = MSM_INFO_CONTEST; ModeTable[LKMODE_INFOMODE][IM_TRI] = MSM_INFO_TRI; ModeTable[LKMODE_NAV][NV_COMMONS] = MSM_COMMON; ModeTable[LKMODE_NAV][NV_HISTORY] = MSM_RECENT; ModeTable[LKMODE_NAV][NV_THERMALS] = MSM_THERMALS; ModeTable[LKMODE_TRF][TF_LIST] = MSM_TRAFFIC; ModeTable[LKMODE_TRF][IM_TRF] = MSM_INFO_TRF; ModeTable[LKMODE_TRF][IM_TARGET] = MSM_INFO_TARGET; // startup mode ModeIndex=LKMODE_MAP; // startup values for each mode. we shall update these defaults using current profile settings // for ConfIP real values. #if TESTBENCH ModeType[LKMODE_MAP] = MP_MOVING; #else ModeType[LKMODE_MAP] = MP_WELCOME; #endif ModeType[LKMODE_INFOMODE]= IM_CRUISE; ModeType[LKMODE_WP] = WP_AIRPORTS; ModeType[LKMODE_NAV] = NV_COMMONS; ModeType[LKMODE_TRF] = TF_LIST; ModeTableTop[LKMODE_MAP]=MP_TOP; ModeTableTop[LKMODE_WP]=WP_TOP; ModeTableTop[LKMODE_INFOMODE]=IM_TOP; ModeTableTop[LKMODE_NAV]=NV_TOP; ModeTableTop[LKMODE_TRF]=TF_TOP; // set all sorting type to distance (default) even for unconventional modes just to be sure for (i=0; i<=MSM_TOP; i++) SortedMode[i]=1; SortedMode[MSM_AIRSPACES]=2; // Airspaces have a different layout for (i=0; i<MAXNEAREST;i++) { SortedTurnpointIndex[i]=-1; SortedLandableIndex[i]=-1; SortedAirportIndex[i]=-1; } for (i=0; i<MAXCOMMON; i++) CommonIndex[i]= -1; for (i=0; i<=MSM_TOP; i++) { SortBoxY[i]=0; for (j=0; j<=MAXSORTBOXES; j++) SortBoxX[i][j]=0; } SetInitialModeTypes(); #if TESTBENCH StartupStore(_T("Ok%s"),NEWLINE); #endif }
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)}; 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()) { // fill background.. Surface.FillRect(&rc, hInvBackgroundBrush[BgMapColor]); // 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; } 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 (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 OnSend(WndButton* pWnd) { if(ItemIndex < FileList.size()) { StartHourglassCursor(); //Start Bluetooth if needed... #ifdef UNDER_CE CObexPush Obex; if(Obex.Startup()) { StartupStore(_T("Startup OK \n")); size_t nDevice = Obex.LookupDevice(); StartupStore(_T("LookupDevice OK \n")); if(nDevice == 0) { StopHourglassCursor(); MessageBoxX(_T("No Device"), _T("Error"), mbOk); StartHourglassCursor(); } else { WndProperty* wp = (WndProperty*)wfDlg->FindByName(TEXT("prpDeviceList")); DataFieldEnum* dfe = NULL; if (wp) { dfe = (DataFieldEnum*)wp->GetDataField(); } if(dfe) { dfe->Clear(); dfe->addEnumText(_T("none")); } for(size_t i = 0; i < nDevice; ++i) { TCHAR szDeviceName[100] = {0}; if(!Obex.GetDeviceName(i, szDeviceName, array_size(szDeviceName))) { _stprintf(szDeviceName, _T("Unknown device <%d>"), i); } StartupStore(_T("GetDeviceName <%d><%s> \n"), i, szDeviceName); if(dfe) { dfe->addEnumText(szDeviceName); } } if(wp) { if(dfe) { dfe->SetAsInteger(0); } wp->SetReadOnly(false); wp->RefreshDisplay(); } StopHourglassCursor(); size_t DeviceIndex = 0; if(dfe && wp) { dlgComboPicker(wp); DeviceIndex = dfe->GetAsInteger(); } StartHourglassCursor(); if(DeviceIndex != 0) { DeviceIndex--; TCHAR szFileFullPath[MAX_PATH] = _T("\0"); LocalPath(szFileFullPath, _T(LKD_LOGS)); size_t nLen = _tcslen(szFileFullPath); if (szFileFullPath[nLen - 1] != _T('\\')) { _tcscat(szFileFullPath, _T("\\")); } FileList_t::const_iterator ItFileName = FileList.begin(); std::advance(ItFileName, ItemIndex); _tcscat(szFileFullPath, ItFileName->c_str()); if(!Obex.SendFile(DeviceIndex, szFileFullPath)) { StopHourglassCursor(); MessageBoxX(_T("Send Failed"), _T("Error"), mbOk); StartHourglassCursor(); } else { StopHourglassCursor(); MessageBoxX(_T("File sent!"), _T("Success"), mbOk); StartHourglassCursor(); } } } Obex.Shutdown(); } else { MessageBoxX(_T("Unsupported on this device"), _T("Error"), mbOk); } #else MessageBoxX(_T("Unsupported on this device"), _T("Error"), mbOk); #endif StopHourglassCursor(); } }
// // Default globals are NOT necessarily default settings. // We had to give them an initialization, but real init // is done through ResetProfile. These are the values used // BEFORE a profile is loaded at startup, FYI. // There are globals that are not configurable of course, // and thus are not part of a profile. // // Please LOAD NEW GLOBALS always at the bottom of the file // to keep trace of new items. // void Globals_Init(void) { #if TESTBENCH StartupStore(_T(". Globals_Init\n")); #endif int i; // _tcscpy(LK8000_Version,_T("")); // No, this is initialised by lk8000 on startup as the first thing _tcscpy(strAssetNumber,_T(LOGGER_ASSET_ID)); ProgramStarted = psInitInProgress; RangeLandableNumber=0; RangeAirportNumber=0; RangeTurnpointNumber=0; SortedNumber=0; CommonNumber=0; RecentNumber=0; BgMapColor=0; BgMapColor_Config=0; BgMapColorTextBlack[0] = false; BgMapColorTextBlack[1] = false; BgMapColorTextBlack[2] = false; BgMapColorTextBlack[3] = false; BgMapColorTextBlack[4] = true; BgMapColorTextBlack[5] = true; BgMapColorTextBlack[6] = true; BgMapColorTextBlack[7] = true; BgMapColorTextBlack[8] = true; BgMapColorTextBlack[9] = true; // // Default infobox groups configuration // Real defaults set by ResetDefaults // for (i=0; i<MAXINFOWINDOWS; i++) InfoType[i]=0; InfoType[0] = 1008146198; InfoType[1] = 1311715074; InfoType[2] = 923929365; InfoType[3] = 975776319; InfoType[4] = 956959267; InfoType[5] = 1178420506; InfoType[6] = 1410419993; InfoType[7] = 1396384771; InfoType[8] = 387389207; StatusMessageData_Size = 0; // // Configuration with default values for new profile // MenuTimeout_Config = MENUTIMEOUTMAX; // Config MenuTimeOut=0; // Runtime // TODO check!! DisplayOrientation = TRACKUP; DisplayOrientation_Config = TRACKUP; AutoOrientScale = 10; DisplayTextType = DISPLAYNONE; AltitudeMode_Config = ALLON; AltitudeMode = AltitudeMode_Config; ClipAltitude = 10000; // m * 10 AltWarningMargin = 1000; // m *10 AutoAdvance = 1; AutoAdvance_Config = 1; AdvanceArmed = false; SafetyAltitudeMode = 0; GlobalRunning = false; GlobalModelType=MODELTYPE_PNA_PNA; SPEEDMODIFY = TOKNOTS; LIFTMODIFY = TOKNOTS; DISTANCEMODIFY = TONAUTICALMILES; ALTITUDEMODIFY = TOFEET; TASKSPEEDMODIFY = TOKPH; MACCREADY = 0; // in m/s QNH = (double)1013.25; BUGS = 1; // This is the runtime Efficiency that can be changed by basic settings 1=100% 0.5=50% BALLAST = 0; AutoMacCready_Config = true; TerrainRamp_Config = 0; NettoSpeed = 1000; GPSCONNECT = FALSE; time_in_flight=0; time_on_ground=0; TakeOffSpeedThreshold=0.0; RUN_MODE=RUN_WELCOME; EnableFLARMMap = 0; // Final Glide Data SAFETYALTITUDEARRIVAL = 3000; SAFETYALTITUDETERRAIN = 500; SAFTEYSPEED = 50.0; // Total Energy usage, config and runtime separated UseTotalEnergy=false; UseTotalEnergy_Config=false; POLAR[0] = 0; POLAR[1] = 0; POLAR[2] = 0; WEIGHTS[0] = 250; WEIGHTS[1] = 70; WEIGHTS[2] = 100; POLARV[0] = 21; POLARV[1] = 27; POLARV[2] = 40; POLARLD[0] = 33; POLARLD[1] = 30; POLARLD[2] = 20; Handicap = 85; // KA6CR // Team code info TeamCodeRefWaypoint = -1; TeamFlarmTracking = false; TeammateCodeValid = false; WayPointList = NULL; WayPointCalc = NULL; NumberOfWayPoints = 0; SectorType = 1; // FAI sector SectorRadius = 3000; StartLine = TRUE; StartRadius = 3000; HomeWaypoint = -1; TakeOffWayPoint=false; AirfieldsHomeWaypoint = -1; // Alternates Alternate1 = -1; Alternate2 = -1; BestAlternate = -1; ActiveAlternate = -1; GPSAltitudeOffset = 0; UseGeoidSeparation=false; PressureHg=false; CustomKeyTime=700; CustomKeyModeCenter=(CustomKeyMode_t)ckDisabled; CustomKeyModeLeft=(CustomKeyMode_t)ckDisabled; CustomKeyModeRight=(CustomKeyMode_t)ckDisabled; CustomKeyModeAircraftIcon=(CustomKeyMode_t)ckDisabled; CustomKeyModeLeftUpCorner=(CustomKeyMode_t)ckDisabled; CustomKeyModeRightUpCorner=(CustomKeyMode_t)ckDisabled; CustomKeyModeCenterScreen=(CustomKeyMode_t)ckDisabled; QFEAltitudeOffset = 0; WasFlying = false; LastDoRangeWaypointListTime=0; DeviceNeedClipping=false; // forcing extensive clipping ForcedClipping=false; // force clipping around EnableAutoBacklight=true; EnableAutoSoundVolume=true; AircraftCategory=0; ExtendedVisualGlide=false; Look8000=lxcAdvanced; HideUnits=false; CheckSum=true; OutlinedTp_Config=0; OutlinedTp=OutlinedTp_Config; OverColor=0; TpFilter=0; MapBox=0; ActiveMap=false; GlideBarMode=0; OverlaySize=0; BarOpacity=255; FontRenderer=0; LockModeStatus=false; ArrivalValue=0; NewMapDeclutter=0; Shading=1; Shading_Config=1; for (i=0; i<10; i++) ConfMP[i]=1; ConfBB0=0, ConfBB1=1, ConfBB2=1, ConfBB3=1, ConfBB4=1, ConfBB5=1, ConfBB6=1, ConfBB7=1, ConfBB8=1, ConfBB9=1, ConfBB0Auto=1; ConfIP11=1, ConfIP12=1, ConfIP13=1, ConfIP14=1, ConfIP15=1, ConfIP16=1, ConfIP21=1, ConfIP22=1; ConfIP23=1, ConfIP24=1, ConfIP31=1, ConfIP32=1, ConfIP33=1; AverEffTime=0; DrawBottom=false; BottomMode=BM_CRU; BottomSize=1; // Init by MapWindow3 TopSize=0; BottomGeom=0; // default initialization for gestures. InitLK8000 will fine tune it. GestureSize=60; // xml dlgconfiguration value replacing 246 which became 278 LKwdlgConfig=0; IphoneGestures=false; PGClimbZoom=1; PGCruiseZoom=1; PGAutoZoomThreshold = 5000; // This is the gauge bar on the left for variometer LKVarioBar=0; // This is the value to be used for painting the bar LKVarioVal=0; // moving map is all black and need white painting - not much used 091109 BlackScreen=false; // if true, LK specific text on map is painted black, otherwise white LKTextBlack=false;; LKVarioSize=2; // init by InitLK8000 // activated by Utils2 in virtual keys, used inside RenderMapWindowBg PGZoomTrigger=false; BestWarning=false; ThermalBar=0; McOverlay=true; TrackBar=false; PGOptimizeRoute=true; WindCalcSpeed=0; WindCalcTime=WCALC_TIMEBACK; RepeatWindCalc=false; // FLARM Traffic is real if <=1min, Shadow if <= etc. If >Zombie it is removed LKTime_Real=15, LKTime_Ghost=60, LKTime_Zombie=180; // Number of IDs (items) of existing traffic updated from DoTraffic LKNumTraffic=0; // 100404 index inside FLARM_Traffic of our target, and its type as defined in Utils2 LKTargetIndex=-1; LKTargetType=LKT_TYPE_NONE; // Number of asps (items) of existing airspaces updated from DoAirspaces LKNumAirspaces=0; WpHome_Lat=0; WpHome_Lon=0; // Name of nearest wp to takeoff and landings _tcscpy(TAKEOFFWP_Name,_T("")); _tcscpy(LANDINGWP_Name,_T("")); // Number of Thermals updated from DoThermalHistory LKNumThermals=0; // LK8000 Hearth beats at 2Hz LKHearthBeats=0; // number of reporting messages from Portmonitor. PortMonitorMessages=0; PollingMode=false; GlideBarOffset=0; EngineeringMenu=false; // never saved to registry splitter=1; NumDataOptions = 0; #if (WINDOWSPC>0) SCREENWIDTH=800; SCREENHEIGHT=400; #endif debounceTimeout=200; WarningHomeDir=false; ScreenSize=0; ScreenSizeX=0; ScreenSizeY=0; ScreenLandscape=false; ScreenDScale=1; ScreenScale=1; ScreenIntScale=false; // Default arrival mode calculation type // 091016 currently not changed anymore AltArrivMode=ALTA_MC; // zoomout trigger time handled by MapWindow LastZoomTrigger=0; // traffic DoTraffic interval, also reset during key up and down to prevent wrong selections LastDoTraffic=0; LastDoNearest=0; LastDoAirspaces=0; LastDoCommon=0; LastDoThermalH=0; // Paraglider's time gates PGOpenTimeH=0; PGOpenTimeM=0; PGOpenTime=0; PGCloseTime=0; // Interval, in minutes PGGateIntervalTime=0; // How many gates, 1-x PGNumberOfGates=0; // Start out or start in? PGStartOut=false; // Current assigned gate ActiveGate=-1; // LKMAPS flag for topology: >0 means ON, and indicating how many topo files are loaded LKTopo=0; // This threshold used in Terrain.cpp to distinguish water altitude LKWaterThreshold=0; LKTopoZoomCat05=0; LKTopoZoomCat10=0; LKTopoZoomCat20=0; LKTopoZoomCat30=0; LKTopoZoomCat40=0; LKTopoZoomCat50=0; LKTopoZoomCat60=0; LKTopoZoomCat70=0; LKTopoZoomCat80=0; LKTopoZoomCat90=0; LKTopoZoomCat100=0; LKTopoZoomCat110=0; // max number of topo and wp labels painted on map, defined by default in Utils LKMaxLabels=0; // current mode of overtarget 0=task 1=alt1, 2=alt2, 3=best alt OvertargetMode=0; // Simulator has one thermal at a time with these values SimTurn=0; ThLatitude=1; ThLongitude=1; ThermalRadius=0; SinkRadius=0; // LK8000 sync flags NearestDataReady=false; CommonDataReady=false; RecentDataReady=false; LKForceDoNearest=false; LKForceDoCommon=false; LKForceDoRecent=false; LKevent=LKEVENT_NONE; LKForceComPortReset=false; LKDoNotResetComms=false; Cpu_Draw=0; Cpu_Calc=0; Cpu_Instrument=0; Cpu_PortA=0; Cpu_PortB=0; Cpu_Aver=0; Experimental1=0, Experimental2=0; NearestAirspaceHDist=-1; NearestAirspaceVDist=0; _tcscpy(NearestAirspaceName,_T("")); _tcscpy(NearestAirspaceVName,_T("")); // FlarmNetCount=0; BUG 120606 this cannot be done here, it is already done by class init! //Airspace Warnings AIRSPACEWARNINGS = TRUE; WarningTime = 60; AcknowledgementTime = 900; // keep ack level for this time, [secs] AirspaceWarningRepeatTime = 300; // warning repeat time if not acknowledged after 5 minutes AirspaceWarningVerticalMargin = 1000; // vertical distance used to calculate too close condition , in m*10 AirspaceWarningDlgTimeout = 30; // airspace warning dialog auto closing in x secs AirspaceWarningMapLabels = 1; // airspace warning map labels showed SnailNext = 0; // OLC COOKED VALUES //CContestMgr::CResult OlcResults[CContestMgr::TYPE_NUM]; // user interface settings FinalGlideTerrain = 1; EnableSoundModes = true; OverlayClock = false; LKLanguageReady = false; //IGC Logger LoggerActive = false; // Others COMPORTCHANGED = FALSE; MAPFILECHANGED = FALSE; AIRSPACEFILECHANGED = FALSE; AIRFIELDFILECHANGED = FALSE; WAYPOINTFILECHANGED = FALSE; TERRAINFILECHANGED = FALSE; TOPOLOGYFILECHANGED = FALSE; POLARFILECHANGED = FALSE; LANGUAGEFILECHANGED = FALSE; INPUTFILECHANGED = FALSE; ActiveWayPoint = -1; // Assigned Area Task AATTaskLength = 120; AATEnabled = FALSE; FinishMinHeight = 0; StartMaxHeight = 0; StartMaxSpeed = 0; StartMaxHeightMargin = 0; StartMaxSpeedMargin = 0; AlarmMaxAltitude1=0; AlarmMaxAltitude2=0; AlarmMaxAltitude3=0; AlarmTakeoffSafety=0; WaypointsOutOfRange = 1; // include by default UTCOffset = 0; EnableThermalLocator = 1; EnableMultipleStartPoints = false; StartHeightRef = 0; // MSL #if (!defined(WINDOWSPC) || (WINDOWSPC==0)) SetSystemTimeFromGPS = true; #else SetSystemTimeFromGPS = false; #endif SelectedWaypoint = -1; TrailActive = TRUE; TrailActive_Config = TRUE; VisualGlide = 0; DisableAutoLogger = false; LiveTrackerInterval = 0; IGCWriteLock=false; // workaround, but not a real solution LoggerTimeStepCruise=2; // 111221 using 2 seconds LoggerTimeStepCircling=1; AutoWindMode_Config= D_AUTOWIND_CIRCLING; AutoWindMode= AutoWindMode_Config; EnableTrailDrift_Config = false; MapWindow::EnableTrailDrift=EnableTrailDrift_Config; AutoZoom_Config = false; MapWindow::zoom.AutoZoom(AutoZoom_Config); EnableNavBaroAltitude=false; EnableNavBaroAltitude_Config=false; Orbiter=1; Orbiter_Config=1; // EnableExternalTriggerCruise=false; REMOVE ExternalTriggerCruise= false; ExternalTriggerCircling= false; EnableExternalTriggerCruise = false; ForceFinalGlide= false; AutoForceFinalGlide= false; AutoMcMode_Config = amcEquivalent; // this is the config saved value AutoMcMode = amcEquivalent; // this is temporary runtime EnableFAIFinishHeight = false; BallastTimerActive = false; FinishLine=1; FinishRadius=3000; BallastSecsToEmpty = 120; // TODO: cancel Appearance struct and reorganize Appearance.DefaultMapWidth=206; // Only used in MapWindow2, can be de-configured Appearance.BestCruiseTrack=ctBestCruiseTrackAltA; // Landables style Appearance.IndLandable=wpLandableDefault; // Black/White inversion Appearance.InverseInfoBox=false; InverseInfoBox_Config=false; Appearance.InfoBoxModel=apImPnaGeneric; TerrainContrast = 140; TerrainBrightness = 115; TerrainRamp = 0; extGPSCONNECT = FALSE; DialogActive=false; PDABatteryPercent = 100; PDABatteryTemperature = 0; PDABatteryStatus=0; PDABatteryFlag=0; szPolarFile[0] = TEXT('\0'); szAirspaceFile[0] = TEXT('\0'); szAdditionalAirspaceFile[0] = TEXT('\0'); szWaypointFile[0] = TEXT('\0'); szAdditionalWaypointFile[0] = TEXT('\0'); szTerrainFile[0] = TEXT('\0'); szAirfieldFile[0] = TEXT('\0'); szLanguageFile[0] = TEXT('\0'); szInputFile[0] = TEXT('\0'); szMapFile[0] = TEXT('\0'); // Ports and device settings dwDeviceName1[0]=_T('\0'); dwPortIndex1 = 0; dwSpeedIndex1 = 2; dwBit1Index = (BitIndex_t)bit8N1; dwDeviceName2[0]=_T('\0'); dwPortIndex2 = 0; dwSpeedIndex2 = 2; dwBit2Index = (BitIndex_t)bit8N1; // Units SpeedUnit_Config = 2; // default is kmh TaskSpeedUnit_Config = 2; // default is kph DistanceUnit_Config = 2; // default is km LiftUnit_Config = 1; // default m/s AltitudeUnit_Config = 1; // default m // Editable fonts FontDesc_MapWindow[0]=_T('\0'); FontDesc_MapLabel [0]=_T('\0'); // Logger PilotName_Config[0]=_T('\0'); LiveTrackersrv_Config[0]=_T('\0'); LiveTrackerusr_Config[0]=_T('\0'); LiveTrackerpwd_Config[0]=_T('\0'); AircraftType_Config[0]=_T('\0'); AircraftRego_Config[0]=_T('\0'); CompetitionClass_Config[0]=_T('\0'); CompetitionID_Config[0]=_T('\0'); LockSettingsInFlight = false; LoggerShortName = false; /* * These tables are initialized by InitSineTable later than Globals here COSTABLE[4096]; SINETABLE[4096]; INVCOSINETABLE[4096]; ISINETABLE[4096]; ICOSTABLE[4096]; */ TouchContext=0; BUGS_Config = 1; // equivalent saved in system config and set by default on startup // Load and use higher resolution bitmaps UseHiresBitmap=false; // Coordinate Y of bottombar area valid for click BottomBarY=0; // Set by InitLKScreen, used in Draw parts AircraftMenuSize=0; CompassMenuSize=0; // Configuration variable for Ungestures UseUngestures=true; // on by default // This is a runtime only variable, by default disabled. Must be enabled by customkey UseWindRose=false; // use wind rose (ex: NNE) for wind direction, instead of degrees extern void Reset_CustomMenu(void); Reset_CustomMenu(); Reset_Multimap_Flags(); extern void Reset_Multimap_Mode(void); Reset_Multimap_Mode(); Trip_Moving_Time=0; Trip_Steady_Time=0; Rotary_Speed=0; Rotary_Distance=0; // These are not saved to profile Flags_DrawTask=true; Flags_DrawFAI=true; // ^ ADD NEW GLOBALS up here ^ // --------------------------- }
// 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: PlayResource(TEXT("IDR_WAV_CLICK")); MapWindow::zoom.EventScaleZoom(1); return true; break; case ckZoomInMore: PlayResource(TEXT("IDR_WAV_CLICK")); MapWindow::zoom.EventScaleZoom(2); return true; break; case ckZoomOut: PlayResource(TEXT("IDR_WAV_CLICK")); MapWindow::zoom.EventScaleZoom(-1); return true; break; case ckZoomOutMore: PlayResource(TEXT("IDR_WAV_CLICK")); MapWindow::zoom.EventScaleZoom(-2); return true; break; case ckMenu: 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: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::setMode(_T("TrueWind")); return true; case ckTeamCode: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventSetup(_T("Teamcode")); return true; case ckToggleOverlays: PlayResource(TEXT("IDR_WAV_CLICK")); 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: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventInvertColor(NULL); return true; case ckTimeGates: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventTimeGates(NULL); return true; case ckMarkLocation: InputEvents::eventMarkLocation(_T("")); return true; case ckAutoZoom: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventZoom(_T("auto toggle")); InputEvents::eventZoom(_T("auto show")); return true; case ckActiveMap: // NO MORE USED (reserved) return true; case ckBooster: DoStatusMessage(_T("FEEL THE THERMAL")); LKSound(_T("LK_BOOSTER.WAV")); return true; case ckGoHome: PlayResource(TEXT("IDR_WAV_CLICK")); if (ValidWayPoint(HomeWaypoint)) { if ( (ValidTaskPoint(ActiveTaskPoint)) && (Task[ActiveTaskPoint].Index == HomeWaypoint )) { // LKTOKEN _@M82_ = "Already going home" DoStatusMessage(MsgToken(82)); } else { GotoWaypoint(HomeWaypoint); } } else // LKTOKEN _@M465_ = "No Home to go!" DoStatusMessage(MsgToken(465)); return true; case ckPanorama: if (PGZoomTrigger==false) PGZoomTrigger=true; else LastZoomTrigger=0; PlayResource(TEXT("IDR_WAV_CLICK")); return true; case ckMultitargetRotate: RotateOvertarget(); return true; case ckMultitargetMenu: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::setMode(_T("MTarget")); return true; case ckBaroToggle: ToggleBaroAltitude(); return true; case ckBasicSetup: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventSetup(_T("Basic")); return true; case ckSimMenu: PlayResource(TEXT("IDR_WAV_CLICK")); 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: PlayResource(TEXT("IDR_WAV_CLICK")); PGOptimizeRoute=!PGOptimizeRoute; if (ISPARAGLIDER && PGOptimizeRoute) { AATEnabled = true; ClearOptimizedTargetPos(); } return true; case ckLockScreen: PlayResource(TEXT("IDR_WAV_CLICK")); 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: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventService(_T("TOTALEN")); return true; case ckNotepad: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventChecklist(_T("")); return true; case ckTerrainColors: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventService(_T("TERRCOL")); return true; case ckNearestAirspace: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventNearestAirspaceDetails(NULL); return true; case ckOlcAnalysis: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventSetup(_T("OlcAnalysis")); return true; case ckTerrainColorsBack: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventService(_T("TERRCOLBACK")); return true; case ckForceFreeFlightRestart: PlayResource(TEXT("IDR_WAV_CLICK")); if (!CALCULATED_INFO.Flying) { DoStatusMessage(MsgToken(922)); // NOT FLYING } else { if (MessageBoxX(MsgToken(1754), _T(""), mbYesNo) == IdYes) { LKSW_ForceFreeFlightRestart=true; } } return true; case ckCustomMenu1: PlayResource(TEXT("IDR_WAV_CLICK")); extern void dlgCustomMenuShowModal(void); InputEvents::eventMode(_T("MYMODE")); return true; case ckTaskCalc: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventCalculator(NULL); return true; case ckTaskTarget: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventSetup(_T("Target")); return true; case ckArmAdvance: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventArmAdvance(_T("toggle")); InputEvents::eventArmAdvance(_T("show")); return true; case ckMessageRepeat: InputEvents::eventRepeatStatusMessage(NULL); return true; case ckWaypointLookup: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventWaypointDetails(_T("select")); return true; case ckPan: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventPan(_T("toggle")); return true; case ckWindRose: PlayResource(TEXT("IDR_WAV_CLICK")); 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 ckDeviceC: if(devC() && devC()->Config) { devC()->Config(devC()); } return true; case ckDeviceD: if(devD() && devD()->Config) { devD()->Config(devD()); } return true; case ckDeviceE: if(devE() && devE()->Config) { devE()->Config(devE()); } return true; case ckDeviceF: if(devF() && devF()->Config) { devF()->Config(devF()); } return true; case ckResetOdometer: PlayResource(TEXT("IDR_WAV_CLICK")); if (MessageBoxX(MsgToken(2229), _T(""), mbYesNo) == IdYes) { LKSW_ResetOdometer=true; } return true; case ckForceLanding: PlayResource(TEXT("IDR_WAV_CLICK")); 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(MsgToken(2230), _T(""), mbYesNo) == IdYes) { LKSW_ForceLanding=true; } } } return true; case ckResetTripComputer: PlayResource(TEXT("IDR_WAV_CLICK")); if (MessageBoxX(MsgToken(2236), _T(""), mbYesNo) == 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 (SonarWarning) LKSound(TEXT("LK_TONEUP.WAV")); else LKSound(TEXT("LK_TONEDOWN.WAV")); return true; case ckDrawXCToggle: Flags_DrawXC = !Flags_DrawXC; if (EnableSoundModes) { if (!Flags_DrawXC) 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: PlayResource(TEXT("IDR_WAV_CLICK")); TCHAR MapOrientMsg[60]; if (MapSpaceMode==MSM_MAP) { DisplayOrientation++; if(DisplayOrientation > TARGETUP) DisplayOrientation = 0; MapWindow::SetAutoOrientation(); // 101008 reset it switch(DisplayOrientation) { case TRACKUP : _stprintf(MapOrientMsg,_T("%s"),MsgToken(737)) ; break; // _@M737_ "Track up" case NORTHUP : _stprintf(MapOrientMsg,_T("%s"),MsgToken(483)) ; break; // _@M483_ "North up" case NORTHCIRCLE : _stprintf(MapOrientMsg,_T("%s"),MsgToken(482)) ; break; // _@M482_ "North circling" case TARGETCIRCLE: _stprintf(MapOrientMsg,_T("%s"),MsgToken(682)) ; break; // _@M682_ "Target circling" _@M485_ "NorthUp above " case NORTHTRACK : _stprintf(MapOrientMsg,_T("%s"),MsgToken(484)) ; break; // _@M484_ "North/track" case NORTHSMART : _stprintf(MapOrientMsg,_T("%s"),MsgToken(481)) ; break; // _@M481_ "North Smart" case TARGETUP : _stprintf(MapOrientMsg,_T("%s"),MsgToken(2349)); break; // _@M2349_"Target up" } DoStatusMessage(MapOrientMsg,NULL,false); } else { SetMMNorthUp(GetSideviewPage(), (GetMMNorthUp(GetSideviewPage())+1)%2); } return true; case ckResetComm: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::eventRestartCommPorts(NULL); return true; case ckDspMode: PlayResource(TEXT("IDR_WAV_CLICK")); InputEvents::setMode(_T("Display3")); return true; case ckAirspaceLookup: PlayResource(TEXT("IDR_WAV_CLICK")); dlgAirspaceSelect(); return true; default: DoStatusMessage(_T("ERR-726 INVALID CUSTOMKEY")); StartupStore(_T("... ERR-726 INVALID CUSTOMKEY=%d\n"),ckeymode); break; } 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::LKDrawVario(LKSurface& Surface, const RECT& rc) { static PixelRect vrc, mrc, hrc, htrc, hbrc; static BrushReference greenBrush, darkyellowBrush, orangeBrush, redBrush; static BrushReference lakeBrush, blueBrush, indigoBrush; static PenReference borderPen; // Pen for border of vario bar and vario bricks ( white or black) static BrushReference forgroundBrush; // Brush used for draw middle thick or monochrome brick ( same color of borderPen ) /* * this array define vario Value for each brick, ( positive value ) * Number of brick for positive value is defined by this array size. */ static const double positive_vario_step[] = {0.05, 0.25, 0.50, 0.75, 1.00, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00, 3.50, 4.50, 5.00, 6.00, 7.00}; static const unsigned positive_brick_count = array_size(positive_vario_step); static BrushReference positiveBrush[positive_brick_count]; static PixelRect positiveBricks[positive_brick_count]; /* * this array define vario Value for each brick, ( negative value ) * Number of brick for negative value is defined by this array size. */ static const double negative_vario_step[] = {-0.05, -0.25, -0.50, -0.75, -1.00, -1.25, -1.50, -1.75, -2.00, -2.50, -3.00, -3.50, -4.50, -5.00, -6.00, -7.00}; static const unsigned negative_brick_count = array_size(negative_vario_step); static BrushReference negativeBrush[negative_brick_count]; static PixelRect negativeBricks[negative_brick_count]; static short startInitCounter = 0; static bool dogaugeinit = true; static double max_positiveGload; static double max_negativeGload; if (DoInit[MDI_DRAWVARIO]) { const int boxthick = IBLSCALE(BOXTHICK); const int hpixelseparate = (LKVarioBar > vBarVarioGR) ? 0 : IBLSCALE(PIXELSEPARATE); const int vpixelseparate = IBLSCALE(PIXELSEPARATE); const int variowidth = LKVarioSize; startInitCounter = 0; dogaugeinit = true; // initial fullscale G loads for 2D driving. // These values are then rescaled (only increased) automatically. max_positiveGload = 0.1; max_negativeGload = -0.1; borderPen = (BgMapColor > POSCOLOR) ? LKPen_White_N0 : LKPen_Black_N0; forgroundBrush = (BgMapColor > POSCOLOR) ? LKBrush_White : LKBrush_Black; greenBrush = LKBrush_Green; darkyellowBrush = LKBrush_DarkYellow2; orangeBrush = LKBrush_Orange; redBrush = LKBrush_Red; lakeBrush = LKBrush_Lake; blueBrush = LKBrush_Blue; indigoBrush = LKBrush_Indigo; const short lkvariobar = (LKVarioBar > vBarVarioGR) ? LKVarioBar - vBarVarioGR : LKVarioBar; switch (lkvariobar) { default: LKASSERT(false); // wrong config value or disabled, in any case, it's BUG // no break; for avoid to have unitialized Brush array. case vBarVarioColor: // set default background in case of missing values std::fill(std::begin(positiveBrush), std::end(positiveBrush), forgroundBrush); std::fill(std::begin(negativeBrush), std::end(negativeBrush), forgroundBrush); static_assert(array_size(positiveBrush)> 15, "\"positiveBrush\" size must be greater than 15, check \"positive_vario_step\" size"); positiveBrush[15] = redBrush; positiveBrush[14] = redBrush; positiveBrush[13] = redBrush; positiveBrush[12] = redBrush; positiveBrush[11] = orangeBrush; positiveBrush[10] = orangeBrush; positiveBrush[9] = orangeBrush; positiveBrush[8] = orangeBrush; positiveBrush[7] = darkyellowBrush; positiveBrush[6] = darkyellowBrush; positiveBrush[5] = darkyellowBrush; positiveBrush[4] = darkyellowBrush; positiveBrush[3] = greenBrush; positiveBrush[2] = greenBrush; positiveBrush[1] = greenBrush; positiveBrush[0] = greenBrush; negativeBrush[0] = lakeBrush; negativeBrush[1] = lakeBrush; negativeBrush[2] = lakeBrush; negativeBrush[3] = lakeBrush; negativeBrush[4] = blueBrush; negativeBrush[5] = blueBrush; negativeBrush[6] = blueBrush; negativeBrush[7] = blueBrush; negativeBrush[8] = indigoBrush; negativeBrush[9] = indigoBrush; negativeBrush[10] = indigoBrush; negativeBrush[11] = indigoBrush; negativeBrush[12] = forgroundBrush; negativeBrush[13] = forgroundBrush; negativeBrush[14] = forgroundBrush; negativeBrush[15] = forgroundBrush; static_assert(array_size(negativeBrush)> 15, "\"negativeBrush\" size must be greater than 15, check \"negative_vario_step\" size"); break; case vBarVarioMono: std::fill(std::begin(positiveBrush), std::end(positiveBrush), forgroundBrush); std::fill(std::begin(negativeBrush), std::end(negativeBrush), forgroundBrush); break; case vBarVarioRB: std::fill(std::begin(positiveBrush), std::end(positiveBrush), redBrush); std::fill(std::begin(negativeBrush), std::end(negativeBrush), blueBrush); break; case vBarVarioGR: std::fill(std::begin(positiveBrush), std::end(positiveBrush), greenBrush); std::fill(std::begin(negativeBrush), std::end(negativeBrush), redBrush); break; } // vario paint area vrc.left = rc.left; vrc.top = rc.top; vrc.right = vrc.left + variowidth; vrc.bottom = rc.bottom - BottomSize; // meter area mrc.left = vrc.left + hpixelseparate; mrc.top = vrc.top + vpixelseparate; mrc.right = vrc.right - hpixelseparate; mrc.bottom = vrc.bottom - vpixelseparate; // half vario separator for positive and negative values const double vmiddle_height = NIBLSCALE(2) - ((mrc.bottom - mrc.top) % 2); const double vmiddle = ((mrc.bottom - mrc.top) / 2.0) + mrc.top; hrc.top = vrc.top + vmiddle - (vmiddle_height / 2); hrc.bottom = vrc.top + vmiddle + (vmiddle_height / 2); hrc.left = vrc.left; hrc.right = vrc.right; // half top meter area htrc.left = mrc.left; htrc.right = mrc.right; htrc.bottom = hrc.top - vpixelseparate; htrc.top = mrc.top + vpixelseparate; // half bottom meter area hbrc.left = mrc.left; hbrc.right = mrc.right; hbrc.top = hrc.bottom + vpixelseparate; hbrc.bottom = mrc.bottom - vpixelseparate; // pixel height of each positive brick const int positive_brick_size = (htrc.bottom - htrc.top - (boxthick * (positive_brick_count - 1))) / positive_brick_count; const int positive_brick_advance = positive_brick_size + boxthick; // Pre-calculate brick positions for half top for (unsigned i = 0; i < positive_brick_count; ++i) { RECT& brc = positiveBricks[i]; brc.left = htrc.left; brc.right = htrc.right - NIBLSCALE(4); brc.bottom = htrc.bottom - (i * positive_brick_advance); brc.top = brc.bottom - positive_brick_size; } // update last box for hide rounding artefact positiveBricks[positive_brick_count - 1].top = htrc.top; // pixel height of each negative brick const int negative_brick_size = (hbrc.bottom - hbrc.top - (boxthick * (negative_brick_count - 1))) / negative_brick_count; const int negative_brick_advance = negative_brick_size + boxthick; // Pre-calculate brick positions for half bottom for (unsigned i = 0; i < negative_brick_count; ++i) { RECT& brc = negativeBricks[i]; brc.left = hbrc.left; brc.right = hbrc.right - NIBLSCALE(4); brc.top = hbrc.top + (i * negative_brick_advance); brc.bottom = brc.top + negative_brick_size; } // update last box for hide rounding artefact negativeBricks[negative_brick_count - 1].bottom = hbrc.bottom; DoInit[MDI_DRAWVARIO] = false; } // END of INIT double vario_value = 0; // can be vario, vario netto or STF offset, depending of config and map mode double mc_value = 0; // current MacCready value, used only for Vario or VarioNetto. if (ISCAR && DrawInfo.Speed > 0) { // Heading is setting Gload, but Heading is not calculated while steady! // For this case, we force vario_value to 0. // // Since we use currently a scale 0-6 for vario, we can use 0-2 for cars. // This accounts for an acceleration topscale of 0-100kmh in 13.9 seconds. // Not a big acceleration, but very good for normal car usage. // We make this concept dynamical, and different for positive and negative accelerations. // Because negative accelerations are much higher, on a car. Of course! // if (DerivedDrawInfo.Gload > 0) { if (DerivedDrawInfo.Gload > max_positiveGload) { max_positiveGload = DerivedDrawInfo.Gload; StartupStore(_T("..... NEW MAXPOSITIVE G=%f\n"), max_positiveGload); } LKASSERT(max_positiveGload > 0); vario_value = (DerivedDrawInfo.Gload / max_positiveGload)*6; //StartupStore(_T("Speed=%f G=%f max=%f val=%f\n"),DrawInfo.Speed, DerivedDrawInfo.Gload, max_positiveGload,vario_value); } if (DerivedDrawInfo.Gload < 0) { if (DerivedDrawInfo.Gload < max_negativeGload) { max_negativeGload = DerivedDrawInfo.Gload; StartupStore(_T("..... NEW MAXNEGATIVE G=%f\n"), max_negativeGload); } LKASSERT(max_negativeGload < 0); vario_value = (DerivedDrawInfo.Gload / max_negativeGload)*-6; //StartupStore(_T("Speed=%f G=%f max=%f val=%f\n"),DrawInfo.Speed, DerivedDrawInfo.Gload, max_negativeGload,vario_value); } } else if (MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING) || LKVarioVal == vValVarioVario) { if (DrawInfo.VarioAvailable) { // UHM. I think we are not painting values correctly for knots &c. //vario_value = LIFTMODIFY*DrawInfo.Vario; vario_value = DrawInfo.Vario; } else { vario_value = DerivedDrawInfo.Vario; } mc_value = MACCREADY; } else { switch (LKVarioVal) { default: case vValVarioNetto: vario_value = DerivedDrawInfo.NettoVario; // simple hack for avoid to used polar curve : glider_sink_rate = Vario - NettoVario; mc_value = MACCREADY + (DerivedDrawInfo.Vario - DerivedDrawInfo.NettoVario); break; case vValVarioSoll: double ias; if (DrawInfo.AirspeedAvailable && DrawInfo.VarioAvailable) ias = DrawInfo.IndicatedAirspeed; else ias = DerivedDrawInfo.IndicatedAirspeedEstimated; // m/s 0-nnn autolimit to 20m/s full scale (72kmh diff) vario_value = clamp(DerivedDrawInfo.VOpt - ias, -20., 20.); vario_value /= 3.3333; // 0-20 -> 0-6 vario_value *= -1; // if up, push down break; } } // Backup selected Brush & Pen LKSurface::OldPen oldPen = Surface.SelectObject(LK_NULL_PEN); LKSurface::OldBrush oldBrush = Surface.SelectObject(LKBrush_Hollow); // draw Vario box ( only if not transparent ) if (LKVarioBar <= vBarVarioGR) { Surface.SelectObject(borderPen); Surface.SelectObject(hInvBackgroundBrush[BgMapColor]); Surface.Rectangle(vrc.left, vrc.top, vrc.right, vrc.bottom); } // draw middle separator for 0 scale indicator Surface.FillRect(&hrc, forgroundBrush); Surface.SelectObject(borderPen); if (dogaugeinit) { // this is causing problems on emulators and condor and most of the times when the gps has no valid date // so we don't use seconds, but loop counter if (startInitCounter++ > 2) { dogaugeinit = false; } // Demo show all bricks for (unsigned i = 0; i < positive_brick_count; ++i) { const RECT& brc = positiveBricks[i]; Surface.SelectObject(positiveBrush[i]); Surface.Rectangle(brc.left, brc.top, brc.right, brc.bottom); } for (unsigned i = 0; i < negative_brick_count; ++i) { const RECT& brc = negativeBricks[i]; Surface.SelectObject(negativeBrush[i]); Surface.Rectangle(brc.left, brc.top, brc.right, brc.bottom); } } else { // Draw Real Vario Data // Draw Positive Brick for (unsigned i = 0; i < positive_brick_count && vario_value >= positive_vario_step[i]; ++i) { const RECT& brc = positiveBricks[i]; Surface.SelectObject(positiveBrush[i]); Surface.Rectangle(brc.left, brc.top, brc.right, brc.bottom); } // Draw Negative Brick for (unsigned i = 0; i < negative_brick_count && vario_value <= negative_vario_step[i]; ++i) { const RECT& brc = negativeBricks[i]; Surface.SelectObject(negativeBrush[i]); Surface.Rectangle(brc.left, brc.top, brc.right, brc.bottom); } // Draw MacCready Indicator const auto step_iterator = std::upper_bound(std::begin(positive_vario_step), std::end(positive_vario_step), mc_value); size_t mc_brick_idx = std::distance(std::begin(positive_vario_step), step_iterator); if (mc_brick_idx > 1) { const PixelRect& brc_next = positiveBricks[mc_brick_idx]; const PixelRect& brc_Prev = positiveBricks[mc_brick_idx-1]; const PixelSize IconSize = hMcVario.GetSize(); const PixelSize DrawSize = { vrc.GetSize().cx, IconSize.cy * vrc.GetSize().cx / IconSize.cx }; const RasterPoint DrawPos = { vrc.left, brc_Prev.top + ((brc_next.bottom - brc_Prev.top) / 2) + (IconSize.cy / 2) }; hMcVario.Draw(Surface, DrawPos.x, DrawPos.y, DrawSize.cx, DrawSize.cy); } } // cleanup Surface.SelectObject(oldPen); Surface.SelectObject(oldBrush); }
void UpdateTask() { if (mA1 == 180.0) { if (mIdx == 0) { StartLine = 0; StartRadius = mR1; } else if (mIdx == (size_t) getFinalWaypoint()) { FinishLine = 0; FinishRadius = mR1; } else { Task[mIdx].AATType = CIRCLE; Task[mIdx].AATCircleRadius = mR1; } } else { switch (mType) { case 0: // - Fixed value, if (mLine) { StartupStore(_T("..Cup Task : \"Fixed\" LINE Turnpoint is not supported%s"), NEWLINE); UpdateFixedLine(); } else { UpdateFixedSector(); } break; case 1: // - Symmetrical, if (mLine) { StartupStore(_T("..Cup Task : \"Symmetrical\" LINE Turnpoint is not supported%s"), NEWLINE); UpdateSymLine(); } else { UpdateSymSector(); } break; case 2: // - To next point, if (mLine) { if (mIdx > 0) { StartupStore(_T("..Cup Task : \"To next point\" LINE Turnpoint is not supported%s"), NEWLINE); } UpdateToNextLine(); } else { UpdateToNextSector(); } break; case 3: // - To previous point, if (mLine) { if (mIdx < (size_t) getFinalWaypoint()) { StartupStore(_T("..Cup Task : \"To previous point\" LINE Turnpoint is not supported%s"), NEWLINE); } UpdateToPrevLine(); } else { UpdateToPrevSector(); } break; case 4: // - To start point if (mLine) { StartupStore(_T("..Cup Task : \"To start point\" LINE Turnpoint is not supported%s"), NEWLINE); UpdateToStartLine(); } else { UpdateToStartSector(); } break; } } }
/* 1 Next waypoint 0 Show waypoint details -1 Previous waypoint 2 Next waypoint with wrap around -2 Previous waypoint with wrap around */ void NextUpDown(int UpDown) { if (!ValidTaskPoint(ActiveWayPoint)) { // BUGFIX 091116 StartupStore(_T(". DBG-801 activewaypoint%s"),NEWLINE); return; } LockTaskData(); if(UpDown>0) { // this was a bug. checking if AWP was < 0 assuming AWP if inactive was -1; actually it can also be 0, a bug is around if(ActiveWayPoint < MAXTASKPOINTS) { // Increment Waypoint if(Task[ActiveWayPoint+1].Index >= 0) { if(ActiveWayPoint == 0) { // manual start // TODO bug: allow restart // TODO bug: make this work only for manual if (CALCULATED_INFO.TaskStartTime==0) { CALCULATED_INFO.TaskStartTime = GPS_INFO.Time; } } ActiveWayPoint ++; AdvanceArmed = false; CALCULATED_INFO.LegStartTime = GPS_INFO.Time ; } // No more, try first else if((UpDown == 2) && (Task[0].Index >= 0)) { /* ****DISABLED**** if(ActiveWayPoint == 0) { // TODO bug: allow restart // TODO bug: make this work only for manual // TODO bug: This should trigger reset of flight stats, but // should ask first... if (CALCULATED_INFO.TaskStartTime==0) { CALCULATED_INFO.TaskStartTime = GPS_INFO.Time ; } } */ AdvanceArmed = false; ActiveWayPoint = 0; CALCULATED_INFO.LegStartTime = GPS_INFO.Time ; } } } else if (UpDown<0){ if(ActiveWayPoint >0) { ActiveWayPoint --; /* XXX How do we know what the last one is? } else if (UpDown == -2) { ActiveWayPoint = MAXTASKPOINTS; */ } else { if (ActiveWayPoint==0) { RotateStartPoints(); // restarted task.. // TODO bug: not required? CALCULATED_INFO.TaskStartTime = 0; } } aatdistance.ResetEnterTrigger(ActiveWayPoint); } else if (UpDown==0) { SelectedWaypoint = Task[ActiveWayPoint].Index; PopupWaypointDetails(); } if (ActiveWayPoint>=0) { SelectedWaypoint = Task[ActiveWayPoint].Index; } UnlockTaskData(); }
bool LoadCupTask(LPCTSTR szFileName) { LockTaskData(); mapCode2Waypoint_t mapWaypoint; ClearTask(); size_t idxTP = 0; bool bTakeOff = true; bool bLoadComplet = true; bool bLastInvalid=true; TCHAR szString[READLINE_LENGTH + 1]; TCHAR TpCode[NAME_SIZE + 1]; szString[READLINE_LENGTH] = _T('\0'); TpCode[NAME_SIZE] = _T('\0'); memset(szString, 0, sizeof (szString)); // clear Temp Buffer WAYPOINT newPoint = {0}; WAYPOINT* WPtoAdd=NULL; enum { none, Waypoint, TaskTp, Option } FileSection = none; FILE * stream = _tfopen(szFileName, _T("rt")); if (stream) { charset cs = charset::unknown; while (ReadStringX(stream, READLINE_LENGTH, szString, cs)) { if ((FileSection == none) && ((_tcsncmp(_T("name,code,country"), szString, 17) == 0) || (_tcsncmp(_T("Title,Code,Country"), szString, 18) == 0))) { FileSection = Waypoint; continue; } else if ((FileSection == Waypoint) && (_tcscmp(szString, _T("-----Related Tasks-----")) == 0)) { FileSection = TaskTp; continue; } TCHAR *pToken = NULL; TCHAR *pWClast = NULL; switch (FileSection) { case Waypoint: memset(&newPoint, 0, sizeof(newPoint)); if (ParseCUPWayPointString(szString, &newPoint)) { mapWaypoint[newPoint.Name] = newPoint; } break; case TaskTp: // 1. Description // First column is the description of the task. If filled it should be double quoted. // If left empty, then SeeYou will determine the task type on runtime. if ((pToken = strsep_r(szString, TEXT(","), &pWClast)) == NULL) { UnlockTaskData(); return false; } // 2. and all successive columns, separated by commas // Each column represents one waypoint name double quoted. The waypoint name must be exactly the // same as the Long name of a waypoint listed above the Related tasks. WPtoAdd=NULL; while (bLoadComplet && (pToken = strsep_r(NULL, TEXT(","), &pWClast)) != NULL) { if (idxTP < MAXTASKPOINTS) { _tcsncpy(TpCode, pToken, NAME_SIZE); CleanCupCode(TpCode); mapCode2Waypoint_t::iterator It = mapWaypoint.find(TpCode); if(!ISGAAIRCRAFT) { if (It != mapWaypoint.end()) { if (bTakeOff) { // skip TakeOff Set At Home Waypoint int ix = FindOrAddWaypoint(&(It->second),false); if (ix>=0) { #if 0 // REMOVE // We must not change HomeWaypoint without user knowing! // The takeoff and homewaypoint are independent from task. // In addition, this is a bug because on next run the index is invalid // and we have no more HowWaypoint! HomeWaypoint = ix; #endif bTakeOff = false; } #if BUGSTOP else LKASSERT(0); // .. else is unmanaged, TODO #endif } else { int ix = FindOrAddWaypoint(&(It->second),false); if (ix>=0) Task[idxTP++].Index = ix; #if BUGSTOP else LKASSERT(0); // .. else is unmanaged, TODO #endif } bLastInvalid=false; } else { // An invalid takeoff, probably a "???" , which we ignore #if TESTBENCH if (bTakeOff) StartupStore(_T("....... CUP Takeoff not found: <%s>\n"),TpCode); #endif // in any case bTakeOff now is false bTakeOff=false; bLastInvalid=true; } } else { //ISGAIRRCRAFT if(It != mapWaypoint.end()) { if(WPtoAdd!=NULL) { //add what we found in previous cycle: it was not the last one int ix = FindOrAddWaypoint(WPtoAdd,false); if (ix>=0) Task[idxTP++].Index = ix; #if BUGSTOP else LKASSERT(0); // .. else is unmanaged, TODO #endif } if (bTakeOff) { //it's the first: may be we have a corresponding airfield //look for departure airfield and add it int ix = FindOrAddWaypoint(&(It->second),true); if (ix>=0) { Task[idxTP++].Index = ix; bTakeOff = false; } #if BUGSTOP else LKASSERT(0); // .. else is unmanaged, TODO #endif } else WPtoAdd=&(It->second); //store it for next cycle (may be it is the last one) } } } else { bLoadComplet = false; } } if(ISGAAIRCRAFT) { //For GA: check if we have an airport corresponding to the last WP if(WPtoAdd!=NULL) { //if we have the last one (probably an airfield) still to add... if(idxTP<MAXTASKPOINTS) { int ix=FindOrAddWaypoint(WPtoAdd,true); //look for arrival airport and add it if (ix>=0) { Task[idxTP++].Index= ix; } #if BUGSTOP else LKASSERT(0); // .. else is unmanaged, TODO #endif } else bLoadComplet=false; } } FileSection = Option; break; case Option: if ((pToken = strsep_r(szString, TEXT(","), &pWClast)) != NULL) { if (_tcscmp(pToken, _T("Options")) == 0) { while ((pToken = strsep_r(NULL, TEXT(","), &pWClast)) != NULL) { if (_tcsstr(pToken, _T("NoStart=")) == pToken) { // Opening of start line PGNumberOfGates = 1; StrToTime(pToken + 8, &PGOpenTimeH, &PGOpenTimeM); } else if (_tcsstr(pToken, _T("TaskTime=")) == pToken) { // Designated Time for the task // TODO : } else if (_tcsstr(pToken, _T("WpDis=")) == pToken) { // Task distance calculation. False = use fixes, True = use waypoints // TODO : } else if (_tcsstr(pToken, _T("NearDis=")) == pToken) { // Distance tolerance // TODO : } else if (_tcsstr(pToken, _T("NearAlt=")) == pToken) { // Altitude tolerance // TODO : } else if (_tcsstr(pToken, _T("MinDis=")) == pToken) { // Uncompleted leg. // False = calculate maximum distance from last observation zone. // TODO : } else if (_tcsstr(pToken, _T("RandomOrder=")) == pToken) { // if true, then Random order of waypoints is checked // TODO : } else if (_tcsstr(pToken, _T("MaxPts=")) == pToken) { // Maximum number of points // TODO : } else if (_tcsstr(pToken, _T("BeforePts=")) == pToken) { // Number of mandatory waypoints at the beginning. 1 means start line only, two means // start line plus first point in task sequence (Task line). // TODO : } else if (_tcsstr(pToken, _T("AfterPts=")) == pToken) { // Number of mandatory waypoints at the end. 1 means finish line only, two means finish line // and one point before finish in task sequence (Task line). // TODO : } else if (_tcsstr(pToken, _T("Bonus=")) == pToken) { // Bonus for crossing the finish line // TODO : } } } else if (_tcsstr(pToken, _T("ObsZone=")) == pToken) { TCHAR *sz = NULL; CupObsZoneUpdater TmpZone; TmpZone.mIdx = _tcstol(pToken + 8, &sz, 10); if (TmpZone.mIdx < MAXSTARTPOINTS) { while ((pToken = strsep_r(NULL, TEXT(","), &pWClast)) != NULL) { if (_tcsstr(pToken, _T("Style=")) == pToken) { // Direction. 0 - Fixed value, 1 - Symmetrical, 2 - To next point, 3 - To previous point, 4 - To start point TmpZone.mType = _tcstol(pToken + 6, &sz, 10); } else if (_tcsstr(pToken, _T("R1=")) == pToken) { // Radius 1 TmpZone.mR1 = ReadLength(pToken + 3); } else if (_tcsstr(pToken, _T("A1=")) == pToken) { // Angle 1 in degrees TmpZone.mA1 = _tcstod(pToken + 3, &sz); } else if (_tcsstr(pToken, _T("R2=")) == pToken) { // Radius 2 TmpZone.mR2 = ReadLength(pToken + 3); } else if (_tcsstr(pToken, _T("A2=")) == pToken) { // Angle 2 in degrees TmpZone.mA2 = _tcstod(pToken + 3, &sz); } else if (_tcsstr(pToken, _T("A12=")) == pToken) { // Angle 12 TmpZone.mA12 = _tcstod(pToken + 4, &sz); } else if (_tcsstr(pToken, _T("Line=")) == pToken) { // true For Line Turmpoint type // Exist only for start an Goalin LK TmpZone.mLine = (_tcstol(pToken + 5, &sz, 10) == 1); } } TmpZone.UpdateTask(); } } } break; case none: default: break; } memset(szString, 0, sizeof (szString)); // clear Temp Buffer } fclose(stream); } if(!ISGAAIRCRAFT) { // Landing don't exist in LK Task Systems, so Remove It; if ( bLoadComplet && !bLastInvalid ) { RemoveTaskPoint(getFinalWaypoint()); } } UnlockTaskData(); for (mapCode2Waypoint_t::iterator It = mapWaypoint.begin(); It != mapWaypoint.end(); ++It) { if (It->second.Comment) { free(It->second.Comment); } if (It->second.Details) { free(It->second.Details); } } mapWaypoint.clear(); return ValidTaskPoint(0); }
// Leonardo Live Tracker (www.livetrack24.com) data exchange thread static DWORD WINAPI LiveTrackerThread (LPVOID lpvoid) { int tracker_fsm = 0; livetracker_point_t sendpoint = {0}; bool sendpoint_valid = false; bool sendpoint_processed = false; bool sendpoint_processed_old = false; // Session variables unsigned int packet_id = 0; unsigned int session_id = 0; int userid = -1; _t_end = false; _t_run = true; srand(GetTickCount()); do { if (WaitForSingleObject(_hNewDataEvent, 5000) == WAIT_OBJECT_0) ResetEvent(_hNewDataEvent); if (!_t_run) break; do { if (1) { sendpoint_valid = false; CCriticalSection::CGuard guard(_t_mutex); if (!_t_points.empty()) { sendpoint = _t_points.front(); sendpoint_valid = true; } } //mutex if (sendpoint_valid) { sendpoint_processed = false; do { switch (tracker_fsm) { default: case 0: // Wait for flying if (!sendpoint.flying) { sendpoint_processed = true; break; } tracker_fsm++; break; case 1: // Get User ID userid = GetUserIDFromServer(); sendpoint_processed = false; if (userid>=0) tracker_fsm++; break; case 2: //Start of track packet sendpoint_processed = SendStartOfTrackPacket(&packet_id, &session_id, userid); if (sendpoint_processed) { StartupStore(TEXT(". Livetracker new track started.%s"),NEWLINE); sendpoint_processed_old = true; tracker_fsm++; } break; case 3: //Gps point packet sendpoint_processed = SendGPSPointPacket(&packet_id, &session_id, &sendpoint); //Connection lost to server if (sendpoint_processed_old && !sendpoint_processed) { StartupStore(TEXT(". Livetracker connection to server lost.%s"), NEWLINE); } //Connection established to server if (!sendpoint_processed_old && sendpoint_processed) { CCriticalSection::CGuard guard(_t_mutex); int queue_size = _t_points.size(); StartupStore(TEXT(". Livetracker connection to server established, start sending %d queued packets.%s"), queue_size, NEWLINE); } sendpoint_processed_old = sendpoint_processed; if (!sendpoint.flying) { tracker_fsm++; } break; case 4: //End of track packet sendpoint_processed = SendEndOfTrackPacket(&packet_id, &session_id); if (sendpoint_processed) { StartupStore(TEXT(". Livetracker track finished, sent %d points.%s"), packet_id, NEWLINE); tracker_fsm=0; } break; }// sw if (sendpoint_processed) { CCriticalSection::CGuard guard(_t_mutex); _t_points.pop_front(); } else InterruptibleSleep(2500); sendpoint_processed_old = sendpoint_processed; } while (!sendpoint_processed && _t_run); } } while (sendpoint_valid && _t_run); } while (_t_run); _t_end = true; return 0; }
// Do a transaction with server // returns received bytes, -1 if transaction failed static int DoTransactionToServer(char *txbuf, unsigned int txbuflen, char *rxbuf, unsigned int maxrxbuflen) { SOCKET s = INVALID_SOCKET; unsigned int sent = 0; int tmpres; int rxfsm = 0; unsigned int rxlen = 0; char recvbuf[BUFSIZ]; unsigned char cdata; #ifdef LT_DEBUG TCHAR utxbuf[500]; ascii2unicode(txbuf,utxbuf,400); StartupStore(TEXT("Livetracker send: %s%s"), utxbuf, NEWLINE); #endif s = EstablishConnection(_server_name); if ( s==INVALID_SOCKET ) return -1; //Send the query to the server while(sent < txbuflen) { tmpres = send(s, txbuf+sent, txbuflen-sent, 0); if( tmpres == -1 ) return -1; sent += tmpres; } //Receive the page while( (tmpres = recv(s, recvbuf, BUFSIZ, 0)) > 0) { for (int i=0; i<tmpres; i++) { cdata = recvbuf[i]; switch (rxfsm) { default: case 0: if (cdata=='\r') rxfsm++; break; case 1: if (cdata=='\n') { rxfsm++; break; } rxfsm=0; break; case 2: if (cdata=='\r') { rxfsm++; break; } rxfsm=0; break; case 3: if (cdata=='\n') { rxfsm++; rxlen=0; break; } rxfsm=0; break; case 4: //Content chr rxbuf[rxlen] = cdata; if (rxlen<maxrxbuflen) rxlen++; break; }//sw } //for } //wh closesocket(s); rxbuf[rxlen]=0; #ifdef LT_DEBUG TCHAR urxbuf[500]; ascii2unicode(rxbuf,urxbuf,400); StartupStore(TEXT("Livetracker recv len=%d: %s%s"), rxlen, urxbuf, NEWLINE); #endif return rxlen; }
void Shutdown(void) { int i; LKSound(_T("LK_DISCONNECT.WAV")); 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; } // LKTOKEN _@M1219_ "Shutdown, please wait..." CreateProgressDialog(gettext(TEXT("_@M1219_"))); 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_"))); StartupStore(TEXT(". CloseDrawingThread%s"),NEWLINE); // 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) SetEvent(dataTriggerEvent); SetEvent(drawTriggerEvent); // 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(); extern void CloseFlightDataRecorder(void); CloseFlightDataRecorder(); // 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 DeleteObject(hBrushSelected); DeleteObject(hBrushUnselected); DeleteObject(hBrushButton); #ifdef LXMINIMAP DeleteObject(hBrushButtonHasFocus); #endif extern void DeInitialiseFonts(void); DeInitialiseFonts(); CAirspaceManager::Instance().CloseAirspaces(); #if TESTBENCH StartupStore(TEXT(".... Delete Critical Sections%s"),NEWLINE); #endif // Wait end of Calculation thread before deinit critical section. WaitForSingleObject(hCalculationThread, INFINITE); CloseHandle(hCalculationThread); #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 DestroyWindow(hWndMapWindow); DestroyWindow(hWndMainWindow); #if TESTBENCH StartupStore(TEXT(".... Close Event Handles%s"),NEWLINE); #endif CloseHandle(drawTriggerEvent); CloseHandle(dataTriggerEvent); #if TESTBENCH StartupLogFreeRamAndStorage(); #endif for (i=0;i<NUMDEV;i++) { if (ComPortStatus[i]!=0) { StartupStore(_T(". ComPort %d: status=%d Rx=%d Tx=%d ErrRx=%d + ErrTx=%d (==%d)%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 }
// 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" wsprintf(msgbuf, TEXT("%s %s"), gettext(TEXT("_@M1240_")), airspace_copy.Name()); DoStatusMessage(msgbuf); break; case aweLeavingNonFly: // LKTOKEN _@M1241_ "Leaving" wsprintf(msgbuf, TEXT("%s %s"), gettext(TEXT("_@M1241_")), 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 _stprintf(msgbuf,_T("%s: %s"),gettext(_T("_@M68_")),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; }
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { long wdata; switch (message) { case WM_ERASEBKGND: return TRUE; // JMW trying to reduce screen flicker break; case WM_COMMAND: return MainMenu(hWnd, message, wParam, lParam); break; case WM_CTLCOLORSTATIC: wdata = GetWindowLong((HWND)lParam, GWL_USERDATA); switch(wdata) { case 0: SetBkColor((HDC)wParam, ColorUnselected); SetTextColor((HDC)wParam, RGB(0x00,0x00,0x00)); return (LRESULT)hBrushUnselected; case 1: SetBkColor((HDC)wParam, ColorSelected); SetTextColor((HDC)wParam, RGB(0x00,0x00,0x00)); return (LRESULT)hBrushSelected; case 2: SetBkColor((HDC)wParam, ColorUnselected); SetTextColor((HDC)wParam, ColorWarning); return (LRESULT)hBrushUnselected; case 3: SetBkColor((HDC)wParam, ColorUnselected); SetTextColor((HDC)wParam, ColorOK); return (LRESULT)hBrushUnselected; case 4: // black on light green SetTextColor((HDC)wParam, RGB_BLACK); SetBkColor((HDC)wParam, ColorButton); return (LRESULT)hBrushButton; case 5: // grey on light green SetBkColor((HDC)wParam, ColorButton); SetTextColor((HDC)wParam, RGB(0x80,0x80,0x80)); return (LRESULT)hBrushButton; #ifdef LXMINIMAP case 6: // black on dark yellow SetTextColor((HDC)wParam, RGB_BLACK); SetBkColor((HDC)wParam, ColorButtonHasFocus); return (LRESULT)hBrushButtonHasFocus; case 7: // grey on dark yellow SetTextColor((HDC)wParam, RGB(0x80,0x80,0x80)); SetBkColor((HDC)wParam, ColorButtonHasFocus); return (LRESULT)hBrushButtonHasFocus; #endif } break; case WM_CREATE: #ifdef HAVE_ACTIVATE_INFO memset (&s_sai, 0, sizeof (s_sai)); s_sai.cbSize = sizeof (s_sai); #endif if (iTimerID == 0) { iTimerID = SetTimer(hWnd,1000,500,NULL); // 500ms 2 times per second } break; case WM_ACTIVATE: if(LOWORD(wParam) != WA_INACTIVE) { SetWindowPos(hWndMainWindow,HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE); #ifdef HAVE_ACTIVATE_INFO SHFullScreen(hWndMainWindow,SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON|SHFS_HIDESTARTICON); #endif } #ifdef HAVE_ACTIVATE_INFO if (api_has_SHHandleWMActivate) { SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE); } else { #ifdef TESTBENCH StartupStore(TEXT("... SHHandleWMActivate not available%s"),NEWLINE); #endif return DefWindowProc(hWnd, message, wParam, lParam); } #endif break; case WM_SETTINGCHANGE: #ifdef HAVE_ACTIVATE_INFO if (api_has_SHHandleWMSettingChange) { SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai); } else { #ifdef TESTBENCH StartupStore(TEXT("... SHHandleWMSettingChange not available%s"),NEWLINE); #endif return DefWindowProc(hWnd, message, wParam, lParam); } #endif break; #if DEBUG_FOCUS case WM_KILLFOCUS: // This is happening when focus is given to another window, either internally inside LK // or externally, for example to explorer.. // SO: if we select MapWindow, we get here a KILLFOCUS from it. // When we select another process/program, or click on the desktop, the old window having focus is // receiving KILLFOCUS. So in case MapWindow was working, the signal will be sent over there, not here. // StartupStore(_T("............ WNDPROC LOST FOCUS (KILLFOCUS)\n")); break; #endif case WM_SETFOCUS: // When explorer/desktop is giving focus to LK, this is where we get the signal. // But we must return focus to previous windows otherwise keys will not be working. // Mouse is another story, because mouse click is pertinent to a screen area which is mapped. // A mouse click will be sent to the window in the background, whose handler will receive the event. // // Each event handler receiving focus has to save it in hWndWithFocus, in LK. // Each event handler must thus handle SETFOCUS! // #if DEBUG_FOCUS StartupStore(_T("............ WNDPROC HAS FOCUS (SETFOCUS)\n")); if (hWndWithFocus==NULL) StartupStore(_T(".....(no Wnd to give focus to)\n")); else StartupStore(_T(".....(passing focus to other window)\n")); #endif if (hWndWithFocus!=NULL) SetFocus(hWndWithFocus); break; case WM_KEYUP: break; case WM_TIMER: // WM_TIMER is run at about 2hz. LKHearthBeats++; // 100213 // ASSERT(hWnd==hWndMainWindow); if (ProgramStarted > psInitInProgress) { if (SIMMODE) SIMProcessTimer(); else ProcessTimer(); if (ProgramStarted==psFirstDrawDone) { AfterStartup(); ProgramStarted = psNormalOp; StartupStore(_T(". ProgramStarted=NormalOp %s%s"), WhatTimeIsIt(),NEWLINE); StartupLogFreeRamAndStorage(); } } break; case WM_INITMENUPOPUP: if (ProgramStarted > psInitInProgress) { CheckMenuItem((HMENU) wParam,IDM_FILE_LOCK,MF_CHECKED|MF_BYCOMMAND); if(LoggerActive) CheckMenuItem((HMENU) wParam,IDM_FILE_LOGGER,MF_CHECKED|MF_BYCOMMAND); else CheckMenuItem((HMENU) wParam,IDM_FILE_LOGGER,MF_UNCHECKED|MF_BYCOMMAND); } break; case WM_CLOSE: LKASSERT(hWnd==hWndMainWindow); if((hWnd==hWndMainWindow) && (MessageBoxX(hWndMainWindow, // LKTOKEN _@M198_ = "Confirm Exit?" gettext(TEXT("_@M198_")), TEXT("LK8000"), MB_YESNO|MB_ICONQUESTION) == IDYES)) { if(iTimerID) { KillTimer(hWnd,iTimerID); iTimerID = 0; } Shutdown(); } break; case WM_DESTROY: if (hWnd==hWndMainWindow) { PostQuitMessage(0); } break; #if TESTBENCH case WM_DEVICECHANGE: TCHAR serr[50]; static WPARAM oldwparam=0; StartupStore(_T("DEVICE CHANGE DETECTED, CODE=0x%x%s"),wParam,NEWLINE); if (wParam!=oldwparam) { oldwparam=wParam; wsprintf(serr,_T("DEVICE CHANGE DETECTED\nCODE=0x%x"),wParam); MessageBoxX(hWndMainWindow, serr, TEXT("LK8000"), MB_OK|MB_ICONQUESTION, true); oldwparam=0; } return TRUE; // acknowledge break; #endif default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
static void SetValues(int indexid) { WndProperty* wp; TCHAR buffer[80]; if (indexid<0 || indexid>MAXTHISTORY) { // TODO check StartupStore(_T("... LK thermal setvalues invalid indexid=%d%s"),indexid,NEWLINE); DoStatusMessage(_T("ERR-216 INVALID THERMAL INDEXID")); return; } if ( !ThermalHistory[indexid].Valid ) { DoStatusMessage(_T("ERR-217 INVALID THERMAL INDEXID")); return; } wp = (WndProperty*)wf->FindByName(TEXT("prpName")); if (wp) { _tcscpy(buffer,ThermalHistory[indexid].Name); ConvToUpper(buffer); wp->SetText(buffer); wp->RefreshDisplay(); } wp = (WndProperty*)wf->FindByName(TEXT("prpHTop")); if (wp) { _stprintf(buffer,_T("%.0f %s"),ThermalHistory[indexid].HTop*ALTITUDEMODIFY, Units::GetAltitudeName()); wp->SetText(buffer); wp->RefreshDisplay(); } wp = (WndProperty*)wf->FindByName(TEXT("prpHBase")); if (wp) { _stprintf(buffer,_T("%.0f %s"),ThermalHistory[indexid].HBase*ALTITUDEMODIFY, Units::GetAltitudeName()); wp->SetText(buffer); wp->RefreshDisplay(); } wp = (WndProperty*)wf->FindByName(TEXT("prpLift")); if (wp) { _stprintf(buffer,_T("%+.1f %s"),ThermalHistory[indexid].Lift*LIFTMODIFY, Units::GetVerticalSpeedName()); wp->SetText(buffer); wp->RefreshDisplay(); } wp = (WndProperty*)wf->FindByName(TEXT("prpTeamCode")); if (wp) { // Taken from CalculateTeamBear.. if (!WayPointList) return; if (TeamCodeRefWaypoint < 0) return; double distance=0, bearing=0; LL_to_BearRange( WayPointList[TeamCodeRefWaypoint].Latitude, WayPointList[TeamCodeRefWaypoint].Longitude, ThermalHistory[indexid].Latitude, ThermalHistory[indexid].Longitude, &bearing, &distance); GetTeamCode(buffer, bearing, distance); buffer[5]='\0'; wp->SetText(buffer); wp->RefreshDisplay(); } }
// // Set all default values for configuration. // We need to set runtime variables later, that make use of // configuration values. One setting for configuration, and the // runtime equivalent of the same setting, for the case when it // is possible to change such runtime value with a button. // // ALL configurable parameters MUST be listed here. Add new items at the bottom! // // Let's keep this list alpha sorted like in LKPROFILES.h and load/save functions // // AFTER this function is called: // * values must be normalized with ProfileAdjustVariables() // * Runtime values must be initialised with InitRuntime() // void LKProfileResetDefault(void) { int i; #if TESTBENCH StartupStore(TEXT("... ProfileResetDefault%s"),NEWLINE); #endif AcknowledgementTime = 1800; // keep ack level for this time, [secs] Units::CoordinateFormat = (CoordinateFormats_t)cfDDMMSS; // Units SpeedUnit_Config = 2; // default is kmh TaskSpeedUnit_Config = 2; // default is kph DistanceUnit_Config = 2; // default is km LiftUnit_Config = 1; // default m/s AltitudeUnit_Config = 1; // default m // // Default infobox groups configuration // Should be different for each aircraft category // InfoType[0] = 1326913302; InfoType[1] = 1915694850; InfoType[2] = 403835669; InfoType[3] = 740895295; InfoType[4] = 1460275747; InfoType[5] = 725435674; InfoType[6] = 168906009; InfoType[7] = 387389207; InfoType[8] = 387389207; // totally unused! DisplayOrientation_Config=NORTHCIRCLE; DisplayTextType=0; AltitudeMode_Config = ALLON; ClipAltitude = 10000; // * 10 AltWarningMargin = 1000; // * 10 AIRSPACEWARNINGS = TRUE; WarningTime = 60; AirspaceWarningRepeatTime = 300; // warning repeat time if not acknowledged after 5 minutes AirspaceWarningVerticalMargin = 1000; // vertical distance used to calculate too close condition *10 AirspaceWarningDlgTimeout = 30; // airspace warning dialog auto closing in x secs AirspaceWarningMapLabels = 1; // airspace warning map labels showed AirspaceAckAllSame = 0; SafetyAltitudeMode = 0; SAFETYALTITUDEARRIVAL = 3000; // * 10 SAFETYALTITUDETERRAIN = 500; // *10 SAFTEYSPEED = 55.556; WindCalcTime=WCALC_TIMEBACK; WindCalcSpeed=27.778; SectorType = 1; SectorRadius = 3000; for(i=0;i<AIRSPACECLASSCOUNT;i++) { MapWindow::iAirspaceMode[i] = 3; // Display + Warning } MapWindow::SetAirSpaceFillType(MapWindow::asp_fill_patterns_full); MapWindow::SetAirSpaceOpacity(30); TrailActive_Config = TRUE; EnableTrailDrift_Config = false; EnableThermalLocator = 1; FinalGlideTerrain = 1; AutoWindMode_Config = D_AUTOWIND_CIRCLING; MapWindow::zoom.CircleZoom(1); HomeWaypoint = -1; Alternate1 = -1; Alternate2 = -1; MapWindow::SnailWidthScale = 16; TeamCodeRefWaypoint = -1; StartLine = 1; StartRadius = 3000; FinishLine = 1; FinishRadius = 3000; EnableAutoBacklight = 1; EnableAutoSoundVolume = 0; AircraftCategory = 0; AATEnabled=FALSE; if (ScreenLandscape) Look8000 = (Look8000_t)lxcAdvanced; else Look8000 = (Look8000_t)lxcStandard; CheckSum = 1; PGCruiseZoom=4; PGAutoZoomThreshold = 5000; PGClimbZoom=1; AutoOrientScale=100; PGOpenTimeH=12; PGOpenTimeM=0; PGCloseTimeH=23; PGCloseTimeM=59; PGNumberOfGates=0; PGGateIntervalTime=30; PGStartOut=0; // These values are used on startup, but on reset change also OpenCloseTopology LKTopoZoomCat05=DEFAULT_WATER_LABELS_THRESHOLD; // coast area share the same label management of cat10 LKTopoZoomCat10=DEFAULT_WATER_LABELS_THRESHOLD; // water labels threshold, over this realscale, no water labels are printed) LKTopoZoomCat20=9999; // water lines LKTopoZoomCat30=25; // Big Roads LKTopoZoomCat40=6; // Medium road LKTopoZoomCat50=3; // Small road LKTopoZoomCat60=8; // Railroad LKTopoZoomCat70=15; // Big cities LKTopoZoomCat80=9999; // Med city LKTopoZoomCat90=9999; // Small city LKTopoZoomCat100=3; // Very small cities LKTopoZoomCat110=9999; // city polyline area LKMaxLabels=70; IphoneGestures = (IphoneGestures_t)iphDisabled; PollingMode = (PollingMode_t)pollmodeDisabled; LKVarioBar = (LKVarioBar_t)vBarDisabled; LKVarioVal = (LKVarioVal_t)vValVarioVario; OutlinedTp_Config = (OutlinedTp_t)otLandable; TpFilter = (TpFilter_t)TfNoLandables; OverColor = (OverColor_t)OcBlack; DeclutterMode = (DeclutterMode_t)dmHigh; // full size overlay by default OverlaySize = 0; BarOpacity = 65; #ifdef PPC2002 FontRenderer = 1; // AntiAliasing #else FontRenderer = 0; // ClearType Compatible #endif GPSAltitudeOffset = 0; UseGeoidSeparation = 1; PressureHg = 0; CustomKeyTime = 700; CustomKeyModeCenter = (CustomKeyMode_t)ckToggleMap; CustomKeyModeLeft = (CustomKeyMode_t)ckDisabled; CustomKeyModeRight = (CustomKeyMode_t)ckDisabled; CustomKeyModeAircraftIcon = (CustomKeyMode_t)ckDisabled; CustomKeyModeLeftUpCorner = (CustomKeyMode_t)ckMultitargetRotate; CustomKeyModeRightUpCorner = (CustomKeyMode_t)ckToggleOverlays; CustomKeyModeCenterScreen = (CustomKeyMode_t)ckWhereAmI; MapBox = (MapBox_t)mbBoxed; // Units labels printout if ((ScreenSize == (ScreenSize_t)ss240x320) || (ScreenSize == (ScreenSize_t)ss272x480) || (ScreenSize == (ScreenSize_t)ss320x240) ) HideUnits = 1; else HideUnits = 0; BestWarning=1; ThermalBar=0; McOverlay=1; TrackBar=1; PGOptimizeRoute=true; PGOptimizeRoute_Config = true; GlideBarMode = (GlideBarMode_t)gbDisabled; ArrivalValue = (ArrivalValue_t)avAltitude; // 1 is showing all airports and declutter only unneeded outlandings NewMapDeclutter = 1; AverEffTime = (AverEffTime_t)ae30seconds; BgMapColor_Config = 2; debounceTimeout = 250; DeviceNeedClipping=false; Appearance.DefaultMapWidth=206; // Landables style Appearance.IndLandable=wpLandableDefault; // White/Black inversion InverseInfoBox_Config=true; // black Appearance.InfoBoxModel=apImPnaGeneric; AutoAdvance_Config = 1; AutoMcMode_Config = amcEquivalent; AutoMacCready_Config = true; UseTotalEnergy_Config= false; WaypointsOutOfRange = 1; // include also wps out of terrain EnableFAIFinishHeight = false; Handicap = 100; // Std Cirrus UTCOffset = 0; AutoZoom_Config=false; MenuTimeout_Config = MENUTIMEOUTMAX; LockSettingsInFlight = 0; LoggerShortName = 0; EnableFLARMMap = 0; TerrainContrast = 128; TerrainBrightness = 128; TerrainRamp_Config = 0; MapWindow::GliderScreenPosition = 40; BallastSecsToEmpty = 120; #if ((WINDOWSPC==0)) SetSystemTimeFromGPS = true; #else SetSystemTimeFromGPS = false; #endif AutoForceFinalGlide = false; UseCustomFonts = 0; AlarmMaxAltitude1 = 0; AlarmMaxAltitude2 = 0; AlarmMaxAltitude3 = 0; AlarmTakeoffSafety = 0; GearWarningMode=0; GearWarningAltitude=200; FinishMinHeight = 0; StartHeightRef = 0; StartMaxHeight = 0; StartMaxHeightMargin = 0; StartMaxSpeed = 0; StartMaxSpeedMargin = 0; EnableNavBaroAltitude_Config = 1; Orbiter_Config = 1; Shading_Config = 1; OverlayClock = 0; SonarWarning_Config = 1; // sonar enabled by default on reset // default BB and IP is all ON ConfBB0 = 0; // TRM is off by default on v4 ConfBB1 = 1; ConfBB2 = 1; ConfBB3 = 1; ConfBB4 = 1; ConfBB5 = 1; ConfBB6 = 1; ConfBB7 = 1; ConfBB8 = 1; ConfBB9 = 1; ConfBB0Auto = 1; ConfIP11 = 1; ConfIP12 = 1; ConfIP13 = 1; ConfIP14 = 1; ConfIP15 = 1; ConfIP16 = 1; ConfIP17 = 1; ConfIP21 = 1; ConfIP22 = 1; ConfIP23 = 1; ConfIP24 = 1; ConfIP31 = 1; ConfIP32 = 1; ConfIP33 = 1; LoggerTimeStepCruise = 1; LoggerTimeStepCircling = 1; GlidePolar::SafetyMacCready = 0.5; // This is saved *10 and loaded /10 in Adjust! DisableAutoLogger = false; LiveTrackerInterval = 0; // empty or demo versions //szAirspaceFile[0] = TEXT('\0'); //szWaypointFile[0] = TEXT('\0'); //szTerrainFile[0] = TEXT('\0'); //szAirfieldFile[0] = TEXT('\0'); //szMapFile[0] = TEXT('\0'); //szPolarFile[0] = TEXT('\0'); _tcscpy(szPolarFile,_T("%LOCAL_PATH%\\\\_Polars\\Std Cirrus.plr")); _tcscpy(szAirspaceFile,_T("%LOCAL_PATH%\\\\_Airspaces\\DEMO.txt")); szAdditionalAirspaceFile[0] = TEXT('\0'); _tcscpy(szWaypointFile,_T("%LOCAL_PATH%\\\\_Waypoints\\DEMO.cup")); szAdditionalWaypointFile[0] = TEXT('\0'); _tcscpy(szTerrainFile,_T("%LOCAL_PATH%\\\\_Maps\\DEMO.DEM")); _tcscpy(szAirfieldFile,_T("%LOCAL_PATH%\\\\_Waypoints\\WAYNOTES.txt")); _tcscpy(szLanguageFile,_T("%LOCAL_PATH%\\\\_Language\\ENGLISH.LNG")); szInputFile[0] = TEXT('\0'); _tcscpy(szMapFile,_T("%LOCAL_PATH%\\\\_Maps\\DEMO.LKM")); // Ports and device settings dwDeviceName1[0]=_T('\0'); szPort1[0] = _T('\0'); dwSpeedIndex1 = 2; dwBit1Index = (BitIndex_t)bit8N1; dwDeviceName2[0]=_T('\0'); szPort2[0] = _T('\0'); dwSpeedIndex2 = 2; dwBit2Index = (BitIndex_t)bit8N1; FontDesc_MapWindow[0]=_T('\0'); FontDesc_MapLabel [0]=_T('\0'); _tcscpy(PilotName_Config,_T("WOLF.HIRTH")); _tcscpy(LiveTrackersrv_Config,_T("www.livetrack24.com")); LiveTrackerport_Config = 80; _tcscpy(LiveTrackerusr_Config,_T("LK8000")); _tcscpy(LiveTrackerpwd_Config,_T("")); _tcscpy(AircraftType_Config,_T("CIRRUS-STD")); _tcscpy(AircraftRego_Config,_T("D-1900")); _tcscpy(CompetitionClass_Config,_T("CLUB")); _tcscpy(CompetitionID_Config,_T("WH")); LockSettingsInFlight = false; LoggerShortName = false; BUGS_Config=1; // 1=100%, 0.5 = 50% .. FLOATS! UseUngestures=true; // This is also reset by global init, but never mind. Done twice. extern void Reset_CustomMenu(void); Reset_CustomMenu(); extern void Reset_Multimap_Flags(void); Reset_Multimap_Flags(); extern void Reset_Multimap_Mode(void); Reset_Multimap_Mode(); UseWindRose=false; // use wind rose (ex: NNE) for wind direction, instead of degrees // only Changed by custom Key // ######### ADD NEW ITEMS ABOVE THIS LINE ######### }
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; } }
void MapWindow::DrawThread () { while ((!ProgramStarted) || (!Initialised)) { Poco::Thread::sleep(50); } #if TRACETHREAD StartupStore(_T("############## DRAW threadid=%d\n"),GetCurrentThreadId()); #endif #if TESTBENCH StartupStore(_T("... DrawThread START%s"),NEWLINE); #endif // THREADRUNNING = FALSE; THREADEXIT = FALSE; bool lastdrawwasbitblitted=false; // // Big LOOP // while (!CLOSETHREAD) { if(drawTriggerEvent.tryWait(5000)) if (CLOSETHREAD) break; // drop out without drawing if ((!THREADRUNNING) || (!GlobalRunning)) { Poco::Thread::sleep(50); continue; } drawTriggerEvent.reset(); #ifdef HAVE_CPU_FREQUENCY const ScopeLockCPU cpu; #endif ScopeLock Lock(Surface_Mutex); // Until MapDirty is set true again, we shall only repaint the screen. No Render, no calculations, no updates. // This is intended for very fast immediate screen refresh. // // MapDirty is set true by: // - TriggerRedraws() in calculations thread // - RefreshMap() in drawthread generally // extern POINT startScreen, targetScreen; extern bool OnFastPanning; // While we are moving in bitblt mode, ignore RefreshMap requests from LK // unless a timeout was triggered by MapWndProc itself. if (OnFastPanning) { MapDirty=false; } // We must check if we are on FastPanning, because we may be in pan mode even while // the menu buttons are active and we are using them, accessing other functions. // In that case, without checking OnFastPanning, we would fall back here and repaint // with bitblt everytime, while instead we were asked a simple fastrefresh! // // Notice: we could be !MapDirty without OnFastPanning, of course! // if (!MapDirty && !ForceRenderMap && OnFastPanning && !first_run) { if (!mode.Is(Mode::MODE_TARGET_PAN) && mode.Is(Mode::MODE_PAN)) { const int fromX=startScreen.x-targetScreen.x; const int fromY=startScreen.y-targetScreen.y; PixelRect clipSourceArea(MapRect); // Source Rectangle RasterPoint clipDestPoint(clipSourceArea.GetOrigin()); // destination origin position PixelRect WhiteRectV(MapRect); // vertical White band (left or right) PixelRect WhiteRectH(MapRect); // horizontal White band (top or bottom) if (fromX<0) { clipSourceArea.right += fromX; // negative fromX clipDestPoint.x -= fromX; WhiteRectV.right = WhiteRectV.left - fromX; WhiteRectH.left = WhiteRectV.right; } else { clipSourceArea.left += fromX; WhiteRectV.left = WhiteRectV.right - fromX; WhiteRectH.right = WhiteRectV.left; } if (fromY<0) { clipSourceArea.bottom += fromY; // negative fromX clipDestPoint.y -= fromY; WhiteRectH.bottom = WhiteRectH.top - fromY; } else { clipSourceArea.top += fromY; WhiteRectH.top = WhiteRectH.bottom - fromY; } #ifndef USE_GDI ScopeLock Lock(BackBuffer_Mutex); #endif BackBufferSurface.Whiteness(WhiteRectV.left, WhiteRectV.top, WhiteRectV.GetSize().cx, WhiteRectV.GetSize().cy); BackBufferSurface.Whiteness(WhiteRectH.left, WhiteRectH.top, WhiteRectH.GetSize().cx, WhiteRectH.GetSize().cy); BackBufferSurface.Copy(clipDestPoint.x,clipDestPoint.y, clipSourceArea.GetSize().cx, clipSourceArea.GetSize().cy, DrawSurface, clipSourceArea.left,clipSourceArea.top); const RasterPoint centerscreen = { ScreenSizeX/2, ScreenSizeY/2 }; DrawMapScale(BackBufferSurface,MapRect,false); DrawCrossHairs(BackBufferSurface, centerscreen, MapRect); lastdrawwasbitblitted=true; } else { // THIS IS NOT GOING TO HAPPEN! // // The map was not dirty, and we are not in fastpanning mode. // FastRefresh! We simply redraw old bitmap. // #ifndef USE_GDI ScopeLock Lock(BackBuffer_Mutex); #endif DrawSurface.CopyTo(BackBufferSurface); lastdrawwasbitblitted=true; } // Now we can clear the flag. If it was off already, no problems. // OnFastPanning=false; MainWindow.Redraw(MapRect); continue; } else { // // Else the map wasy dirty, and we must render it.. // Notice: if we were fastpanning, than the map could not be dirty. // #if 1 // --------------------- EXPERIMENTAL, CHECK ZOOM IS WORKING IN PNA static unsigned lasthere=0; // Only for special case: PAN mode, map not dirty (including requests for zooms!) // not in the ForceRenderMap run and last time was a real rendering. THEN, at these conditions, // we simply redraw old bitmap, for the scope of accelerating touch response. // In fact, if we are panning the map while rendering, there would be an annoying delay. // This is using lastdrawwasbitblitted if (INPAN && !MapDirty && !lastdrawwasbitblitted && !ForceRenderMap && !first_run) { // In any case, after 5 seconds redraw all if ( (LKHearthBeats-8) >lasthere ) { lasthere=LKHearthBeats; goto _dontbitblt; } #ifndef USE_GDI ScopeLock Lock(BackBuffer_Mutex); #endif DrawSurface.CopyTo(BackBufferSurface); const RasterPoint centerscreen = { ScreenSizeX/2, ScreenSizeY/2 }; DrawMapScale(BackBufferSurface,MapRect,false); DrawCrossHairs(BackBufferSurface, centerscreen, MapRect); MainWindow.Redraw(MapRect); continue; } #endif // -------------------------- _dontbitblt: MapDirty = false; PanRefreshed=true; } // MapDirty lastdrawwasbitblitted=false; MapWindow::UpdateInfo(&GPS_INFO, &CALCULATED_INFO); RenderMapWindow(DrawSurface, MapRect); { #ifndef USE_GDI ScopeLock Lock(BackBuffer_Mutex); #endif if (!ForceRenderMap && !first_run) { DrawSurface.CopyTo(BackBufferSurface); } // Draw cross sight for pan mode, in the screen center, // after a full repaint while not fastpanning if (mode.AnyPan() && !mode.Is(Mode::MODE_TARGET_PAN) && !OnFastPanning) { POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(BackBufferSurface,MapRect,false); DrawCompass(BackBufferSurface, MapRect, DisplayAngle); DrawCrossHairs(BackBufferSurface, centerscreen, MapRect); } } UpdateTimeStats(false); // we do caching after screen update, to minimise perceived delay // UpdateCaches is updating topology bounds when either forced (only here) // or because MapWindow::ForceVisibilityScan is set true. const ScreenProjection _Proj; UpdateCaches(_Proj, first_run); first_run=false; ForceRenderMap = false; if (ProgramStarted==psInitDone) { ProgramStarted = psFirstDrawDone; } MainWindow.Redraw(MapRect); } // Big LOOP #if TESTBENCH StartupStore(_T("... Thread_Draw terminated\n")); #endif THREADEXIT = TRUE; }
BOOL devInit(LPTSTR CommandLine){ int i; TCHAR DeviceName[DEVNAMESIZE+1]; PDeviceDescriptor_t pDevNmeaOut = NULL; static bool doinit=true; for (i=0; i<NUMDEV; i++){ DeviceList[i].Port = -1; DeviceList[i].fhLogFile = NULL; DeviceList[i].Name[0] = '\0'; DeviceList[i].ParseNMEA = NULL; DeviceList[i].PutMacCready = NULL; DeviceList[i].DirectLink = NULL; DeviceList[i].PutBugs = NULL; DeviceList[i].PutBallast = NULL; DeviceList[i].Open = NULL; DeviceList[i].Close = NULL; DeviceList[i].Init = NULL; DeviceList[i].LinkTimeout = NULL; DeviceList[i].Declare = NULL; DeviceList[i].IsLogger = devIsFalseReturn; DeviceList[i].IsGPSSource = devIsFalseReturn; DeviceList[i].IsBaroSource = devIsFalseReturn; DeviceList[i].IsRadio = devIsFalseReturn; DeviceList[i].PutVoice = (int (*)(struct DeviceDescriptor_t *,TCHAR *))devIsFalseReturn; DeviceList[i].PortNumber = i; DeviceList[i].PutQNH = NULL; DeviceList[i].OnSysTicker = NULL; DeviceList[i].pDevPipeTo = NULL; DeviceList[i].PutVolume = NULL; DeviceList[i].PutFreqActive = NULL; DeviceList[i].PutFreqStandby = NULL; DeviceList[i].IsCondor = devIsFalseReturn; DeviceList[i].Disabled = true; ComPortStatus[i]=CPS_UNUSED; // 100210 ComPortHB[i]=0; // counter if (doinit) { ComPortRx[i]=0; ComPortTx[i]=0; ComPortErrTx[i]=0; ComPortErrRx[i]=0; ComPortErrors[i]=0; doinit=false; } } pDevPrimaryBaroSource = NULL; pDevSecondaryBaroSource=NULL; ReadDeviceSettings(0, DeviceName); #ifdef DEBUG_DEVSETTING StartupStore(_T(".......... ReadDeviceSetting 0, DeviceName=<%s>\n"),DeviceName); #endif PortIndex1 = 0; SpeedIndex1 = 2; Bit1Index=(BitIndex_t)bit8N1; ReadPort1Settings(&PortIndex1,&SpeedIndex1,&Bit1Index); //if (_tcslen(DeviceName)>0) // removed 110530 if (wcscmp(DeviceName,_T(DEV_DISABLED_NAME))!=0) { DeviceList[0].Disabled=false; StartupStore(_T(". Device A is <%s> Port=%s%s"),DeviceName,COMMPort[PortIndex1],NEWLINE); } else { DeviceList[0].Disabled=true; StartupStore(_T(". Device A is DISABLED.%s"),NEWLINE); } for (i=DeviceRegisterCount-1; i>=0; i--) { if (DeviceList[0].Disabled) break; if ((_tcscmp(DeviceRegister[i].Name, DeviceName) == 0)) { ComPort *Com = new ComPort(0); // remember: Port1 is the port used by device A, port1 may be Com3 or Com1 etc // this is port 1, so index 0 for us. if (!Com->Initialize(COMMPort[PortIndex1], dwSpeed[SpeedIndex1],Bit1Index,0)) { delete Com; ComPortStatus[0]=CPS_OPENKO; break; } ComPortStatus[0]=CPS_OPENOK; DeviceRegister[i].Installer(devA()); if ((pDevNmeaOut == NULL) && (DeviceRegister[i].Flags & (1l << dfNmeaOut))){ pDevNmeaOut = devA(); } devA()->Com = Com; devInit(devA()); devOpen(devA(), 0); if (devIsBaroSource(devA())) { if (pDevPrimaryBaroSource == NULL){ pDevPrimaryBaroSource = devA(); } else if (pDevSecondaryBaroSource == NULL){ pDevSecondaryBaroSource = devA(); } } break; } } ReadDeviceSettings(1, DeviceName); #ifdef DEBUG_DEVSETTING StartupStore(_T(".......... ReadDeviceSetting 1, DeviceName=<%s>\n"),DeviceName); #endif PortIndex2 = 0; SpeedIndex2 = 2, Bit2Index=(BitIndex_t)bit8N1; ReadPort2Settings(&PortIndex2,&SpeedIndex2, &Bit2Index); //if (_tcslen(DeviceName)>0) // removed 110530 if (wcscmp(DeviceName,_T(DEV_DISABLED_NAME))!=0) { DeviceList[1].Disabled=false; StartupStore(_T(". Device B is <%s> Port=%s%s"),DeviceName,COMMPort[PortIndex2],NEWLINE); } else { DeviceList[1].Disabled=true; StartupStore(_T(". Device B is DISABLED.%s"),NEWLINE); } for (i=DeviceRegisterCount-1; i>=0; i--) { if (PortIndex1 == PortIndex2) break; if (DeviceList[1].Disabled) break; if ((_tcscmp(DeviceRegister[i].Name, DeviceName) == 0)) { ComPort *Com = new ComPort(1); // this is port 2, so index 1 for us if (!Com->Initialize(COMMPort[PortIndex2], dwSpeed[SpeedIndex2],Bit2Index,1)) { // 100210 delete Com; ComPortStatus[1]=CPS_OPENKO; break; } ComPortStatus[1]=CPS_OPENOK; DeviceRegister[i].Installer(devB()); if ((pDevNmeaOut == NULL) && (DeviceRegister[i].Flags & (1l << dfNmeaOut))){ pDevNmeaOut = devB(); } devB()->Com = Com; devInit(devB()); devOpen(devB(), 1); if (devIsBaroSource(devB())) { if (pDevPrimaryBaroSource == NULL){ pDevPrimaryBaroSource = devB(); } else if (pDevSecondaryBaroSource == NULL){ pDevSecondaryBaroSource = devB(); } } break; } } if (pDevNmeaOut != NULL){ if (pDevNmeaOut == devA()){ devB()->pDevPipeTo = devA(); } if (pDevNmeaOut == devB()){ devA()->pDevPipeTo = devB(); } } return(TRUE); }
// This will NOT be called from PC versions void InstallSystem() { TCHAR srcdir[MAX_PATH]; TCHAR srcfile[MAX_PATH]; #ifdef UNDER_CE TCHAR dstdir[MAX_PATH]; TCHAR maindir[MAX_PATH]; TCHAR dstfile[MAX_PATH]; TCHAR tbuf[MAX_PATH*3]; dstdir[0]='\0'; #endif bool failure=false; #if TESTBENCH StartupStore(_T(". Welcome to InstallSystem v1.2%s"),NEWLINE); #endif SystemPath(srcdir,TEXT(LKD_SYSTEM)); // We now test for a single file existing inside the directory, called _DIRECTORYNAME // because GetFileAttributes can be very slow or hang if checking a directory. In any case testing a file is // much more faster. _stprintf(srcfile,TEXT("%s%s_SYSTEM"),srcdir, _T(DIRSEP)); if ( !lk::filesystem::exist(srcfile) ) { StartupStore(_T("------ InstallSystem ERROR could not find valid system directory <%s>%s"),srcdir,NEWLINE); // 091104 StartupStore(_T("------ Missing checkfile <%s>%s"),srcfile,NEWLINE); failure=true; } else { #if TESTBENCH StartupStore(_T(". InstallSystem source directory <%s> is available%s"),srcdir,NEWLINE); #endif } if ( failure ) { StartupStore(_T("------ WARNING: NO font will be installed on device (and thus wrong text size displayed)%s"),NEWLINE); } else { #ifdef PNA if (GlobalModelType == MODELTYPE_PNA_HP31X) { // 091109 StartupStore(_T(". InstallSystem checking desktop links for HP31X%s"),NEWLINE); _stprintf(dstdir,TEXT("\\Windows\\Desktop")); if ( !lk::filesystem::isDirectory(dstdir) ) { // FIX StartupStore(_T("------ Desktop directory <%s> NOT found! Is this REALLY an HP31X?%s"),dstdir,NEWLINE); } else { _stprintf(srcfile,TEXT("%s\\LK8_HP310.lnk"),srcdir); _stprintf(dstfile,TEXT("%s\\LK8000.lnk"),dstdir); if ( lk::filesystem::exist(dstfile) ) { StartupStore(_T(". Link to LK8000 already found on the desktop, ok.%s"),NEWLINE); } else { StartupStore(_T(". Installing <%s>%s"),srcfile,NEWLINE); if (!lk::filesystem::copyFile(srcfile,dstfile,true)) { StartupStore(_T("------ Could not install in <%s>. Strange.%s"),dstfile,NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T(". Installed <%s> link.%s"),dstfile,NEWLINE); } #if 0 _stprintf(srcfile,TEXT("%s\\LK8SIM_HP310.lnk"),srcdir); _stprintf(dstfile,TEXT("%s\\SIM.lnk"),dstdir); if ( lk::filesystem::exist(dstfile) ) { StartupStore(_T(". Link to SIM LK8000 already found on the desktop, ok.%s"),NEWLINE); } else { StartupStore(_T(". Installing <%s>%s"),srcfile,NEWLINE); if (!lk::filesystem::copyFile(srcfile,dstfile,true)) { StartupStore(_T("------ Could not install in <%s>. Strange.%s"),dstfile,NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T(". Installed <%s> link.%s"),dstfile,NEWLINE); } #endif _stprintf(srcfile,TEXT("%s\\BT_HP310.lnk"),srcdir); _stprintf(dstfile,TEXT("%s\\BlueTooth.lnk"),dstdir); if ( lk::filesystem::exist(dstfile) ) { StartupStore(_T(". Link to BlueTooth already found on the desktop, ok.%s"),NEWLINE); } else { StartupStore(_T(". Installing <%s>%s"),srcfile,NEWLINE); if (!lk::filesystem::copyFile(srcfile,dstfile,true)) { StartupStore(_T("------ Could not install in <%s>. Strange.%s"),dstfile,NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T(". Installed <%s> link.%s"),dstfile,NEWLINE); } _stprintf(srcfile,TEXT("%s\\NAV_HP310.lnk"),srcdir); _stprintf(dstfile,TEXT("%s\\CarNav.lnk"),dstdir); if ( lk::filesystem::exist(dstfile) ) { StartupStore(_T(". Link to Car Navigator already found on the desktop, ok.%s"),NEWLINE); } else { StartupStore(_T(". Installing <%s>%s"),srcfile,NEWLINE); if (!lk::filesystem::copyFile(srcfile,dstfile,true)) { StartupStore(_T("------ Could not install in <%s>. Strange.%s"),dstfile,NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T(". Installed <%s> link.%s"),dstfile,NEWLINE); } _stprintf(srcfile,TEXT("%s\\TLOCK_HP310.lnk"),srcdir); _stprintf(dstfile,TEXT("%s\\TouchLock.lnk"),dstdir); if ( lk::filesystem::exist(dstfile) ) { StartupStore(_T(". Link to TouchLock already found on the desktop, ok.%s"),NEWLINE); } else { StartupStore(_T(". Installing <%s>%s"),srcfile,NEWLINE); if (!lk::filesystem::copyFile(srcfile,dstfile,true)) { StartupStore(_T("------ Could not install in <%s>. Strange.%s"),dstfile,NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T(". Installed <%s> link.%s"),dstfile,NEWLINE); } } } #endif } #ifdef UNDER_CE // search for the main system directory on the real device // Remember that SHGetSpecialFolder works differently on CE platforms, and you cannot check for result. // We need to verify if directory does really exist. // SHGetSpecialFolderPath(MainWindow, dstdir, CSIDL_WINDOWS, false); if ( _tcslen(dstdir) <6) { _stprintf(tbuf,_T("------ InstallSystem PROBLEM: cannot locate the Windows folder, got string:<%s>%s"),dstdir,NEWLINE); StartupStore(tbuf); StartupStore(_T("------ InstallSystem attempting to use default \"\\Windows\" but no warranty!%s"),NEWLINE); _stprintf(dstdir,TEXT("\\Windows")); // 091118 } else { StartupStore(_T(". InstallSystem: Windows path reported from device is: <%s>%s"),dstdir,NEWLINE); } _tcscpy(maindir,dstdir); // we are shure that \Windows does exist already. TCHAR fontdir[MAX_PATH]; fontdir[0] = _T('\0'); dstdir[0] = _T('\0'); #ifdef PNA if ( GetFontPath(fontdir) == FALSE ) { StartupStore(_T(". Special RegKey for fonts not found on this PNA, using standard folder.%s"), NEWLINE); // SHGetSpecialFolderPath(MainWindow, dstdir, CSIDL_FONTS, false); if ( _tcslen(dstdir) <5 ) { _stprintf(tbuf,_T("------ PROBLEM: cannot locate the Fonts folder, got string:<%s>%s"),dstdir,NEWLINE); StartupStore(tbuf); _stprintf(tbuf,_T("------ Attempting to use directory <%s> as a fallback%s"),maindir,NEWLINE); StartupStore(tbuf); _tcscpy(dstdir,maindir); } } else { StartupStore(_T(". RegKey Font directory is <%s>%s"),fontdir,NEWLINE); lk::filesystem::createDirectory(fontdir); _tcscpy(dstdir,fontdir); } #else UNUSED(fontdir); // this is not working correctly on PNA, it is reporting Windows Fonts even with another value in regkey SHGetSpecialFolderPath(MainWindow.Handle(), dstdir, CSIDL_FONTS, false); if ( _tcslen(dstdir) <5 ) { _stprintf(tbuf,_T("------ PROBLEM: cannot locate the Fonts folder, got string:<%s>%s"),dstdir,NEWLINE); StartupStore(tbuf); _stprintf(tbuf,_T("------ Attempting to use directory <%s> as a fallback%s"),maindir,NEWLINE); StartupStore(tbuf); _tcscpy(dstdir,maindir); } #endif _stprintf(tbuf,_T(". InstallSystem: Copy/Check Fonts from <%s> to <%s>%s"), srcdir, dstdir,NEWLINE); StartupStore(tbuf); // on PNAs sometimes FolderPath is reported correctly, but the directory is not existing! // this is not needed really on PNA, but doesnt hurt lk::filesystem::createDirectory(dstdir); // 100820 // we cannot check directory existance without the risk of hanging for many seconds // we can only rely on singe real file existance, not on directories #if TESTBENCH StartupStore(_T(". Checking TAHOMA font%s"),NEWLINE); #endif _stprintf(srcfile,TEXT("%s\\TAHOMA.TTF"),srcdir); _stprintf(dstfile,TEXT("%s\\TAHOMA.TTF"),dstdir); if ( lk::filesystem::exist(dstfile) ) { #if TESTBENCH StartupStore(_T(". Font TAHOMA.TTF is already installed%s"),NEWLINE); #endif } else { if ( !lk::filesystem::copyFile(srcfile,dstfile,false) ) { StartupStore(_T("------ Could not copy TAHOMA.TTF on device, not good.%s"),NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T("... Font TAHOMA.TTF installed on device%s"),NEWLINE); } // not needed, cannot overwrite tahoma while in use! Tahoma bold not used for some reason in this case. // Problem solved, look at FontPath !! #if TESTBENCH StartupStore(_T(". Checking TAHOMABD font%s"),NEWLINE); #endif _stprintf(srcfile,TEXT("%s\\TAHOMABD.TTF"),srcdir); _stprintf(dstfile,TEXT("%s\\TAHOMABD.TTF"),dstdir); if ( lk::filesystem::exist(dstfile) ) { #if TESTBENCH StartupStore(_T(". Font TAHOMABD.TTF is already installed%s"),NEWLINE); #endif } else { if ( !lk::filesystem::copyFile(srcfile,dstfile,false)) { StartupStore(_T("------ Could not copy TAHOMABD.TTF on device, not good.%s"),NEWLINE); StartupStore(_T("------ Error code was: %ld%s"),GetLastError(),NEWLINE); } else StartupStore(_T("... Font TAHOMABD.TTF installed on device%s"),NEWLINE); } #endif #if TESTBENCH StartupStore(_T(". InstallSystem completed OK%s"),NEWLINE); #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 }
// mode: 0 normal Change the topology scale of Category with newScale. // mode: 1 zoom more or less for the category with newScale (newScale is the zoom increment). // mode: 2 zoom more or less for all categories (tCategory is ignored, newScale is the zoom increment for all items) // mode: 3 reset default zoom for Category (newScale is ignored) // mode: 4 reset default zoom for all Categories (Category is ignored, newScale is ignored) void ChangeZoomTopology(int iCategory, double newScale, short cztmode) { if (LKTopo<1) return; LockTerrainDataGraphics(); if (cztmode==0) { for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { if ( TopoStore[z]->scaleCategory == iCategory ) { #if DEBUG_LKTOPO StartupStore(_T("... ChangeZoomTopology zindex=%d, categ=%d oldscale=%f newscale=%f%s"),z,iCategory, TopoStore[z]->scaleThreshold, newScale,NEWLINE); #endif TopoStore[z]->scaleThreshold = newScale; } } } UnlockTerrainDataGraphics(); return; } if (cztmode==1) { for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { if ( TopoStore[z]->scaleCategory == iCategory ) { #if DEBUG_LKTOPO StartupStore(_T("... ChangeZoomTopology: zindex=%d, categ=%d oldscale=%f increment=%f%s"),z,iCategory, TopoStore[z]->scaleThreshold, newScale,NEWLINE); #endif TopoStore[z]->scaleThreshold += newScale; } } } UnlockTerrainDataGraphics(); return; } if (cztmode==2) { for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { #if DEBUG_LKTOPO StartupStore(_T("... ChangeZoomTopology for all: zindex=%d, categ=%d oldscale=%f increment=%f%s"),z,iCategory, TopoStore[z]->scaleThreshold, newScale,NEWLINE); #endif TopoStore[z]->scaleThreshold += newScale; } } UnlockTerrainDataGraphics(); return; } if (cztmode==3) { for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { if ( TopoStore[z]->scaleCategory == iCategory ) { #if DEBUG_LKTOPO StartupStore(_T("... ChangeZoomTopology default zindex=%d, categ=%d oldscale=%f default=%f%s"), z,iCategory, TopoStore[z]->scaleThreshold, TopoStore[z]->scaleDefaultThreshold,NEWLINE); #endif TopoStore[z]->scaleThreshold = TopoStore[z]->scaleDefaultThreshold; } } } UnlockTerrainDataGraphics(); return; } if (cztmode==4) { for (int z=0; z<MAXTOPOLOGY; z++) { if (TopoStore[z]) { #if DEBUG_LKTOPO StartupStore(_T("... ChangeZoomTopology all default zindex=%d, categ=%d oldscale=%f default=%f%s"), z,iCategory, TopoStore[z]->scaleThreshold, TopoStore[z]->scaleDefaultThreshold,NEWLINE); #endif // 130207 categories 5 and 10 are using DefaultThreshold for polygon paint, // and scaleThreshold for labels only. Upon reset, we should use the original // LKTopoZoom settings, because the Default is always fixed to 100! // Otherwise on reset we get 99.. even if we set LKTopoZoom to something else. // This is needed if we want to have a startup setting different from default // for these 05 and 10 categories only. // Sorry but water areas and labels are not easy to manage because we want to paint // blue all the way, but not also their labels. // Notice that since LKTopoZoom is saved to configuration, we cannot use it for reset! // This is why we have a special define DEFAULT_WATER_LABELS_THRESHOLD switch(TopoStore[z]->scaleCategory) { case 5: TopoStore[z]->scaleThreshold = DEFAULT_WATER_LABELS_THRESHOLD; break; case 10: TopoStore[z]->scaleThreshold = DEFAULT_WATER_LABELS_THRESHOLD; break; default: TopoStore[z]->scaleThreshold = TopoStore[z]->scaleDefaultThreshold; break; } } } UnlockTerrainDataGraphics(); return; } UnlockTerrainDataGraphics(); }
DWORD MapWindow::DrawThread (LPVOID lpvoid) { FILETIME CreationTime, ExitTime, StartKernelTime, EndKernelTime, StartUserTime, EndUserTime ; while ((!ProgramStarted) || (!Initialised)) { Sleep(100); } // THREADRUNNING = FALSE; THREADEXIT = FALSE; // Reset common topology and waypoint label declutter, first init. Done also in other places. ResetLabelDeclutter(); GetClientRect(hWndMapWindow, &MapRect); // Default draw area is full screen, no opacity DrawRect=MapRect; UpdateTimeStats(true); SetBkMode(hdcDrawWindow,TRANSPARENT); SetBkMode(hDCTemp,OPAQUE); SetBkMode(hDCMask,OPAQUE); // paint draw window black to start SelectObject(hdcDrawWindow, GetStockObject(BLACK_PEN)); Rectangle(hdcDrawWindow,MapRect.left,MapRect.top, MapRect.right,MapRect.bottom); BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); // This is just here to give fully rendered start screen UpdateInfo(&GPS_INFO, &CALCULATED_INFO); MapDirty = true; UpdateTimeStats(true); zoom.RequestedScale(zoom.Scale()); zoom.ModifyMapScale(); FillScaleListForEngineeringUnits(); bool lastdrawwasbitblitted=false; bool first_run=true; // // Big LOOP // while (!CLOSETHREAD) { WaitForSingleObject(drawTriggerEvent, 5000); ResetEvent(drawTriggerEvent); if (CLOSETHREAD) break; // drop out without drawing if ((!THREADRUNNING) || (!GlobalRunning)) { Sleep(100); continue; } // This is also occuring on resolution change if (LKSW_ReloadProfileBitmaps) { #if TESTBENCH StartupStore(_T(".... SWITCH: ReloadProfileBitmaps detected\n")); #endif // This is needed to update resolution change GetClientRect(hWndMapWindow, &MapRect); DrawRect=MapRect; FillScaleListForEngineeringUnits(); LKUnloadProfileBitmaps(); LKLoadProfileBitmaps(); LKUnloadFixedBitmaps(); LKLoadFixedBitmaps(); MapWindow::zoom.Reset(); // This will reset the function for the new ScreenScale PolygonRotateShift((POINT*)NULL,0,0,0,DisplayAngle+1); // Restart from moving map if (MapSpaceMode!=MSM_WELCOME) SetModeType(LKMODE_MAP, MP_MOVING); LKSW_ReloadProfileBitmaps=false; // These should be better checked. first_run is forcing also cache update for topo. ForceRenderMap=true; first_run=true; } GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&StartKernelTime,&StartUserTime); // Until MapDirty is set true again, we shall only repaint the screen. No Render, no calculations, no updates. // This is intended for very fast immediate screen refresh. // // MapDirty is set true by: // - TriggerRedraws() in calculations thread // - RefreshMap() in drawthread generally // extern int XstartScreen, YstartScreen, XtargetScreen, YtargetScreen; extern bool OnFastPanning; // While we are moving in bitblt mode, ignore RefreshMap requests from LK // unless a timeout was triggered by MapWndProc itself. if (OnFastPanning) { MapDirty=false; } // We must check if we are on FastPanning, because we may be in pan mode even while // the menu buttons are active and we are using them, accessing other functions. // In that case, without checking OnFastPanning, we would fall back here and repaint // with bitblt everytime, while instead we were asked a simple fastrefresh! // // Notice: we could be !MapDirty without OnFastPanning, of course! // if (!MapDirty && !ForceRenderMap && OnFastPanning && !first_run) { if (!mode.Is(Mode::MODE_TARGET_PAN) && mode.Is(Mode::MODE_PAN)) { int fromX=0, fromY=0; fromX=XstartScreen-XtargetScreen; fromY=YstartScreen-YtargetScreen; BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, WHITENESS); BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, fromX,fromY, // source SRCCOPY); POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCrossHairs(hdcScreen, centerscreen, MapRect); lastdrawwasbitblitted=true; } else { // THIS IS NOT GOING TO HAPPEN! // // The map was not dirty, and we are not in fastpanning mode. // FastRefresh! We simply redraw old bitmap. // BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); lastdrawwasbitblitted=true; } // Now we can clear the flag. If it was off already, no problems. OnFastPanning=false; continue; } else { // // Else the map wasy dirty, and we must render it.. // Notice: if we were fastpanning, than the map could not be dirty. // #if 1 // --------------------- EXPERIMENTAL, CHECK ZOOM IS WORKING IN PNA static double lasthere=0; // Only for special case: PAN mode, map not dirty (including requests for zooms!) // not in the ForceRenderMap run and last time was a real rendering. THEN, at these conditions, // we simply redraw old bitmap, for the scope of accelerating touch response. // In fact, if we are panning the map while rendering, there would be an annoying delay. // This is using lastdrawwasbitblitted if (INPAN && !MapDirty && !lastdrawwasbitblitted && !ForceRenderMap && !first_run) { // In any case, after 5 seconds redraw all if ( (LKHearthBeats-8) >lasthere ) { lasthere=LKHearthBeats; goto _dontbitblt; } BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCrossHairs(hdcScreen, centerscreen, MapRect); continue; } #endif // -------------------------- _dontbitblt: MapDirty = false; PanRefreshed=true; } // MapDirty lastdrawwasbitblitted=false; MapWindow::UpdateInfo(&GPS_INFO, &CALCULATED_INFO); RenderMapWindow(MapRect); if (!ForceRenderMap && !first_run) { BitBlt(hdcScreen, 0, 0, MapRect.right-MapRect.left, MapRect.bottom-MapRect.top, hdcDrawWindow, 0, 0, SRCCOPY); InvalidateRect(hWndMapWindow, &MapRect, false); } // Draw cross sight for pan mode, in the screen center, // after a full repaint while not fastpanning if (mode.AnyPan() && !mode.Is(Mode::MODE_TARGET_PAN) && !OnFastPanning) { POINT centerscreen; centerscreen.x=ScreenSizeX/2; centerscreen.y=ScreenSizeY/2; DrawMapScale(hdcScreen,MapRect,false); DrawCompass(hdcScreen, MapRect, DisplayAngle); DrawCrossHairs(hdcScreen, centerscreen, MapRect); } UpdateTimeStats(false); // we do caching after screen update, to minimise perceived delay // UpdateCaches is updating topology bounds when either forced (only here) // or because MapWindow::ForceVisibilityScan is set true. UpdateCaches(first_run); first_run=false; ForceRenderMap = false; if (ProgramStarted==psInitDone) { ProgramStarted = psFirstDrawDone; } if ( (GetThreadTimes( hDrawThread, &CreationTime, &ExitTime,&EndKernelTime,&EndUserTime)) == 0) { Cpu_Draw=9999; } else { Cpustats(&Cpu_Draw,&StartKernelTime, &EndKernelTime, &StartUserTime, &EndUserTime); } } // Big LOOP #if TESTBENCH StartupStore(_T("... Thread_Draw terminated\n")); #endif THREADEXIT = TRUE; return 0; }
// Loads a new task from scratch. // This is called on startup by the even manager because in DEFAULT MENU we have a GCE event // configured to load Default.tsk for STARTUP_SIMULATOR and STARTUP_REAL. // Until we change this, which would be a good thing because these configuration are unnecessary , // we must use the FullResetAsked trick. void LoadNewTask(LPCTSTR szFileName) { HANDLE hFile; TASK_POINT Temp; START_POINT STemp; DWORD dwBytesRead; int i; bool TaskInvalid = false; bool WaypointInvalid = false; bool TaskLoaded = false; char taskinfo[LKPREAMBOLSIZE+1]; // 100207 bool oldversion=false; // 100207 TCHAR taskFileName[MAX_PATH]; LockTaskData(); ClearTask(); if (FullResetAsked) { #if TESTBENCH StartupStore(_T("... LoadNewTask detected FullResetAsked, attempt to load DEMO.TSK\n")); #endif // Clear the flag, forever. FullResetAsked=false; _tcscpy(taskFileName,_T("%LOCAL_PATH%\\\\_Tasks\\DEMO.TSK")); ExpandLocalPath(taskFileName); } else { _tcscpy(taskFileName,szFileName); } StartupStore(_T(". LoadNewTask <%s>%s"),taskFileName,NEWLINE); hFile = CreateFile(taskFileName,GENERIC_READ,0, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); if(hFile!= INVALID_HANDLE_VALUE ) { // Defaults int old_StartLine = StartLine; int old_SectorType = SectorType; DWORD old_SectorRadius = SectorRadius; DWORD old_StartRadius = StartRadius; int old_AutoAdvance = AutoAdvance; double old_AATTaskLength = AATTaskLength; BOOL old_AATEnabled = AATEnabled; DWORD old_FinishRadius = FinishRadius; int old_FinishLine = FinishLine; bool old_EnableMultipleStartPoints = EnableMultipleStartPoints; TaskLoaded = true; if(!ReadFile(hFile,&taskinfo,LKPREAMBOLSIZE,&dwBytesRead, (OVERLAPPED *)NULL)) { TaskInvalid = true; goto goEnd; } // task version check if ( (taskinfo[0]!= 'L') || (taskinfo[1]!= 'K') || (taskinfo[2]!=LKTASKVERSION) ) { TaskInvalid = true; oldversion = true; goto goEnd; } for(i=0;i<OLD_MAXTASKPOINTS;i++) { if(!ReadFile(hFile,&Temp,sizeof(OLD_TASK_POINT),&dwBytesRead, (OVERLAPPED *)NULL)) { TaskInvalid = true; break; } if(i < MAXTASKPOINTS) { memcpy(&Task[i],&Temp, sizeof(OLD_TASK_POINT)); if( !ValidNotResWayPoint(Temp.Index) && (Temp.Index != -1) ) { // 091213 // Task is only invalid here if the index is out of range // of the waypoints and not equal to -1. // (Because -1 indicates a null task item) WaypointInvalid = true; } } } if (!TaskInvalid) { if (!ReadFile(hFile,&AATEnabled,sizeof(BOOL),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&AATTaskLength,sizeof(double),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } // ToDo review by JW // 20060521:sgi added additional task parameters if (!ReadFile(hFile,&FinishRadius,sizeof(FinishRadius),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&FinishLine,sizeof(FinishLine),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&StartRadius,sizeof(StartRadius),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&StartLine,sizeof(StartLine),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&SectorType,sizeof(SectorType),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&SectorRadius,sizeof(SectorRadius),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&AutoAdvance,sizeof(AutoAdvance),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } if (!ReadFile(hFile,&EnableMultipleStartPoints,sizeof(bool),&dwBytesRead,(OVERLAPPED*)NULL)) { TaskInvalid = true; } for(i=0;i<MAXSTARTPOINTS;i++) { if(!ReadFile(hFile,&STemp,sizeof(START_POINT),&dwBytesRead, (OVERLAPPED *)NULL)) { TaskInvalid = true; break; } if( ValidNotResWayPoint(STemp.Index) || (STemp.Index==-1) ) { // 091213 memcpy(&StartPoints[i],&STemp, sizeof(START_POINT)); } else { WaypointInvalid = true; StartupStore(_T("--- LoadNewTask: invalid waypoint=%d found%s"),STemp.Index,NEWLINE); // 091213 } } // search for waypoints... if (!TaskInvalid) { if (!LoadTaskWaypoints(hFile) && WaypointInvalid) { // couldn't lookup the waypoints in the file and we know there are invalid waypoints TaskInvalid = true; StartupStore(_T(". LoadTaskNew: cant locate waypoint in file, and invalid wp in task file%s"),NEWLINE); } } } // TimeGate config if (!TaskInvalid) { TaskInvalid = !ReadFile(hFile, &PGOpenTimeH, sizeof (PGOpenTimeH), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { TaskInvalid = !ReadFile(hFile, &PGOpenTimeM, sizeof (PGOpenTimeM), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { InitActiveGate(); // PGOpenTime is Calculated ! int tmp; TaskInvalid = !ReadFile(hFile, &tmp, sizeof (tmp), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { PGCloseTime=86399; // PGCloseTime is Calculated ! int tmp; TaskInvalid = !ReadFile(hFile, &tmp, sizeof (tmp), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { TaskInvalid = !ReadFile(hFile, &PGGateIntervalTime, sizeof (PGGateIntervalTime), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { TaskInvalid = !ReadFile(hFile, &PGNumberOfGates, sizeof (PGNumberOfGates), &dwBytesRead, (OVERLAPPED*) NULL); } if (!TaskInvalid) { TaskInvalid = !ReadFile(hFile, &PGStartOut, sizeof (PGStartOut), &dwBytesRead, (OVERLAPPED*) NULL); } goEnd: CloseHandle(hFile); if (TaskInvalid) { if (oldversion) StartupStore(_T("------ Task is invalid: old task format%s"),NEWLINE); else StartupStore(_T("------ Task is invalid%s"),NEWLINE); StartLine = old_StartLine; SectorType = old_SectorType; SectorRadius = old_SectorRadius; StartRadius = old_StartRadius; AutoAdvance = old_AutoAdvance; AATTaskLength = old_AATTaskLength; AATEnabled = old_AATEnabled; FinishRadius = old_FinishRadius; FinishLine = old_FinishLine; EnableMultipleStartPoints = old_EnableMultipleStartPoints; } } else { StartupStore(_T("... LoadNewTask: file <%s> not found%s"),taskFileName,NEWLINE); // 091213 TaskInvalid = true; } if (TaskInvalid) { ClearTask(); } RefreshTask(); if (!ValidTaskPoint(0)) { ActiveWayPoint = 0; } UnlockTaskData(); if (TaskInvalid && TaskLoaded) { if (oldversion) { // LKTOKEN _@M360_ = "Invalid old task format!" MessageBoxX(hWndMapWindow, gettext(TEXT("_@M360_")), // LKTOKEN _@M396_ = "Load task" gettext(TEXT("_@M396_")), MB_OK|MB_ICONEXCLAMATION); } else { // LKTOKEN _@M264_ = "Error in task file!" MessageBoxX(hWndMapWindow, gettext(TEXT("_@M264_")), // LKTOKEN _@M396_ = "Load task" gettext(TEXT("_@M396_")), MB_OK|MB_ICONEXCLAMATION); } } else { #if TESTBENCH StartupStore(_T("------ Task is Loaded%s"),NEWLINE); #endif TaskModified = false; TargetModified = false; _tcscpy(LastTaskFileName, taskFileName); } }
short MapWindow::GetVisualGlidePoints(unsigned short numslots) { #if BUGSTOP LKASSERT(numslots <= MAXBSLOT); #else if (numslots > MAXBSLOT) numslots = MAXBSLOT; #endif static short currentFilledNumber = -1; static double tmpSlotBrgDiff[MAXBSLOT + 1]; int i; // RESET COMMAND by passing 0, normally by EVENT_NEWRUN if (numslots == 0) { #if DEBUG_GVG StartupStore(_T("...... GVGP: RESET\n")); #endif for (i = 0; i < MAXBSLOT; i++) { slotWpIndex[i] = INVALID_VALUE; } currentFilledNumber = INVALID_VALUE; ResetVisualGlideGlobals(); return INVALID_VALUE; } bool ndr = NearestDataReady; NearestDataReady = false; // No data ready.. // if cfn is -1 we did not ever calculate it yet // otherwise 0 or >0 means use what we have already in the list if (!ndr) { #if DEBUG_GVG StartupStore(_T("...... GVGP: no data ready, currentFN=%d\n"), currentFilledNumber); #endif return currentFilledNumber; } if (SortedNumber <= 0) { #if DEBUG_GVG StartupStore(_T("...... GVGP: SortedNumber is 0, no available wpts in this range!\n")); #endif return 0; } int *pindex; int wpindex = 0; pindex = SortedTurnpointIndex; // // Reset content // currentFilledNumber = 0; for (i = 0; i < MAXBSLOT; i++) { slotWpIndex[i] = INVALID_VALUE; tmpSlotBrgDiff[i] = -999; } // // set up fine tuned parameters for this run // int maxgratio = 1, mingratio = 1; double maxdistance = 300; // in METERS, not in KM! if (ISPARAGLIDER) { maxgratio = (int) (GlidePolar::bestld / 2); mingratio = (int) (GlidePolar::bestld * 1.5); maxdistance = 100; } if (ISGLIDER) { maxgratio = (int) (GlidePolar::bestld / 2); mingratio = (int) (GlidePolar::bestld * 1.5); maxdistance = 300; } if (ISGAAIRCRAFT) { maxgratio = (int) (GlidePolar::bestld / 2); mingratio = (int) (GlidePolar::bestld * 2); maxdistance = 300; } if (ISCAR) { maxgratio = 1; mingratio = 999; maxdistance = 100; } // // WE USE THE 2.3 PAGE (Nearest turnpoints) sorted by DIRECTION // // We do this in several passes. #define MAXPHASES 4 unsigned short phase = 1; #if DEBUG_GVG StartupStore(_T("GVGP: USING %d Sorted Items available\n"), SortedNumber); int count = 0; #endif _tryagain: for (i = 0; i < numslots; i++) { LKASSERT(phase <= MAXPHASES); #if DEBUG_GVG if (i >= SortedNumber) { StartupStore(_T("...... GVGP: PHASE %d warning not enough SortedNumber (%d) for i=%d\n"), phase, SortedNumber, i); } #endif // Did we found at least one valid in current phase? Otherwise we skip the rest of numslots. // And we pass directly to the next phase. bool found = false; // look up for an empty slot, needed if running after phase 1 if (slotWpIndex[i] != INVALID_VALUE) continue; // browse results for the best usable items for (int k = 0; k < SortedNumber; k++) { wpindex = *(pindex + k); if (!ValidWayPoint(wpindex)) { // since we are not synced with DoNearest update cycle, we might fall here while it // has reset the sorted list. No worry, in the worst case we miss a waypoint printed // for a second, and the list might be inaccurate for the current second. // But in the next run it will be ok, because at the end of its run, the DoNearest // will be setting DataReady flag on and we shall update correctly. continue; } #if DEBUG_GVG count++; #endif // did we already use it? bool alreadyused = false; for (int j = 0; j < numslots; j++) { if (slotWpIndex[j] == INVALID_VALUE) break; if (slotWpIndex[j] == wpindex) { alreadyused = true; break; } } if (alreadyused) continue; // unused one, decide if good or not // We do this in 3 phases.. double distance = WayPointCalc[wpindex].Distance; double brgdiff = WayPointCalc[wpindex].Bearing - DrawInfo.TrackBearing; if (brgdiff < -180.0) { brgdiff += 360.0; } else { if (brgdiff > 180.0) brgdiff -= 360.0; } double abrgdiff = brgdiff; if (abrgdiff < 0) abrgdiff *= -1; #if 0 // do we already have a wp with same bearing? for (int j = 0; j < numslots; j++) { if ((int) tmpSlotBrgDiff[j] == (int) brgdiff) { //StartupStore(_T("%s with bdiff=%d already used\n"),WayPointList[wpindex].Name,(int)brgdiff); alreadyused = true; break; } } if (alreadyused) continue; #endif // Careful: we are selecting abrgdiff from a list that is tuned to max 60, so ok. // DIRECTIONRANGE definition in DoNearest // Then we make a selective insertion, in several steps // First, we pick mountain passes and task points, generally priority #1 points // accepted from +-45 deg, but only if they are not absolutely unreachable if (phase == 1) { if (abrgdiff > 45) continue; // if we are practically over the waypoint, skip it if (distance < maxdistance) continue; // Consider only Mt.Passes and task points not below us... if ((WayPointList[wpindex].Style == STYLE_MTPASS) || ((WayPointList[wpindex].InTask) && (distance > 100))) { // ... that are not within an obvious glide ratio // (considering even strong headwind, we want a very positive arrival) if (WayPointCalc[wpindex].AltArriv[AltArrivMode] > 150) { if (WayPointCalc[wpindex].GR <= (maxgratio / 1.5)) continue; } if (WayPointCalc[wpindex].AltArriv[AltArrivMode]<-100) { if (WayPointCalc[wpindex].GR >= mingratio) continue; } goto _takeit; } continue; } // Second we take anything not obviously reachable if (phase == 2) { if (abrgdiff > 45) continue; if (distance < maxdistance) continue; if (WayPointCalc[wpindex].AltArriv[AltArrivMode] > 150) { if (WayPointCalc[wpindex].GR <= (maxgratio)) continue; } goto _takeit; } if (phase == 3) { if (abrgdiff > 45) continue; if (distance < maxdistance) continue; goto _takeit; } // else we accept anything, in the original sort order _takeit: // ok good, use it slotWpIndex[i] = wpindex; tmpSlotBrgDiff[i] = brgdiff; found = true; #if DEBUG_GVG StartupStore(_T("PHASE %d slot [%d] of %d : wp=%d <%s> brg=%f\n"), phase, i, numslots, wpindex, WayPointList[wpindex].Name, brgdiff); #endif currentFilledNumber++; break; } // for all sorted wps if (!found) { #if DEBUG_GVG StartupStore(_T("PHASE %d nothing found during search (stop at slot %d), advance to next phase\n"), phase, i >= numslots ? numslots - 1 : i); #endif break; } if (currentFilledNumber >= numslots) { #if DEBUG_GVG StartupStore(_T("PHASE %d stop search, all slots taken\n"), phase); #endif break; } } // for all slots to be filled if ((currentFilledNumber < numslots) && (phase < MAXPHASES)) { #if DEBUG_GVG StartupStore(_T("PHASE %d filled %d of %d slots, going phase %d\n"), phase, currentFilledNumber, numslots, phase + 1); #endif phase++; goto _tryagain; } #if DEBUG_GVG else { StartupStore(_T("PHASE %d filled %d of %d slots\n"), phase, currentFilledNumber, numslots); } StartupStore(_T("TOTAL COUNTS=%d\n"), count); #endif // // All wpts in the array are shuffled, unsorted by direction. // We must reposition them horizontally, using their bearing // int tmpSlotWpIndex[MAXBSLOT + 1]; for (i = 0; i < MAXBSLOT; i++) tmpSlotWpIndex[i] = INVALID_VALUE; #if DEBUG_GVG for (i = 0; i < numslots; i++) { StartupStore(_T(">>> [%d] %f (wp=%d)\n"), i, tmpSlotBrgDiff[i], slotWpIndex[i]); } #endif bool invalid = true, valid = false; unsigned short g; for (unsigned short nslot = 0; nslot < numslots; nslot++) { g = 0; double minim = 999; valid = false; #if DEBUGSORT StartupStore(_T(".... Slot [%d]:\n"), nslot); #endif for (unsigned short k = 0; k < numslots; k++) { if (tmpSlotBrgDiff[k] <= minim) { // is this already used? invalid = false; if (slotWpIndex[k] == -1) { #if DEBUGSORT StartupStore(_T(".... not using g=%d, it is an invalid waypoint\n"), k); #endif continue; } for (unsigned short n = 0; n < nslot; n++) { if (tmpSlotWpIndex[n] == slotWpIndex[k]) { #if DEBUGSORT StartupStore(_T(".... not using g=%d, it is already used in newslot=%d\n"), k, n); #endif invalid = true; continue; } } if (invalid || !ValidWayPoint(slotWpIndex[k])) continue; // We do have a valid choice g = k; minim = tmpSlotBrgDiff[k]; #if DEBUGSORT StartupStore(_T(".... minim=%f g=%d\n"), minim, g); #endif valid = true; } } if (valid) { tmpSlotWpIndex[nslot] = slotWpIndex[g]; #if DEBUGSORT StartupStore(_T(".... FINAL for SLOT %d: minim=%f g=%d\n"), nslot, minim, g); #endif } #if DEBUGSORT else { StartupStore(_T(".... FINAL for SLOT %d: no valid point\n"), nslot); } #endif } for (i = 0; i < numslots; i++) { slotWpIndex[i] = tmpSlotWpIndex[i]; } return currentFilledNumber; }
static BOOL PWES0(PDeviceDescriptor_t d, TCHAR *String, NMEA_INFO *pGPS) { /* Sent by Westerboer VW1150 combining data stream from Flarm and VW1020. RMZ is being sent too, which is a problem. $PWES0,22,10,8,18,17,6,1767,1804,1073,1073,116,106 A B C D E F G H I J K L A Device 21 = VW1000, 21 = VW 1010, 22 = VW1020, 23 = VW1030 B vario *10 = 2.2 m/s C average vario *10 = 1.0 m/s D netto vario *10 = 1.8 m/s E average netto vario *10 = 1.7 m/s F stf = -999.. 999 (neg faster.. slower) G baro altitude = 1767 m H baro altitude calibrated by user? I IAS kmh *10 = 107.3 kmh J TAS kmh *10 ? K battery V *10 = 11.6 V L OAT * 10 = 10.6 C */ TCHAR ctemp[180]; double vtas, vias; double altqne, altqnh; static bool initqnh=true; #ifdef DEVICE_SERIAL static int NoMsg =0; // static int HardwareId = 0; if(_tcslen(String) < 180) if(((pGPS->SerialNumber == 0) || (oldSerial != SerialNumber)) && (NoMsg < 5)) { NoMsg++ ; NMEAParser::ExtractParameter(String,ctemp,0); pGPS->HardwareId= (int)StrToDouble(ctemp,NULL); switch (pGPS->HardwareId) { case 21: _tcscpy(d->Name, TEXT("VW1010")); break; case 22: _tcscpy(d->Name, TEXT("VW1020")); break; case 23: _tcscpy(d->Name, TEXT("VW1030")); break; default: _tcscpy(d->Name, TEXT("Westerboer")); break; } StartupStore(_T(". %s\n"),ctemp); _stprintf(ctemp, _T("%s DETECTED"), d->Name); oldSerial = pGPS->SerialNumber; DoStatusMessage(ctemp); StartupStore(_T(". %s\n"),ctemp); } #endif // instant vario NMEAParser::ExtractParameter(String,ctemp,1); pGPS->Vario = StrToDouble(ctemp,NULL)/10; pGPS->VarioAvailable = TRUE; // netto vario NMEAParser::ExtractParameter(String,ctemp,3); if (ctemp[0] != '\0') { pGPS->NettoVario = StrToDouble(ctemp,NULL)/10; pGPS->NettoVarioAvailable = TRUE; } else pGPS->NettoVarioAvailable = FALSE; // Baro altitudes. To be verified, because I have no docs from Westerboer of any kind. NMEAParser::ExtractParameter(String,ctemp,6); altqne = StrToDouble(ctemp,NULL); NMEAParser::ExtractParameter(String,ctemp,7); altqnh = StrToDouble(ctemp,NULL); // AutoQNH will take care of setting an average QNH if nobody does it for a while if (initqnh) { // if wester has qnh set by user qne and qnh are of course different if (altqne != altqnh) { QNH=FindQNH(altqne,altqnh); CAirspaceManager::Instance().QnhChangeNotify(QNH); StartupStore(_T(". Using WESTERBOER QNH %f%s"),QNH,NEWLINE); initqnh=false; } else { // if locally QNH was set, either by user of by AutoQNH, stop processing QNH from Wester if ( (QNH <= 1012) || (QNH>=1014)) initqnh=false; // else continue entering initqnh until somebody changes qnh in either Wester or lk8000 } } UpdateBaroSource( pGPS, 0,d, AltitudeToQNHAltitude(altqne)); // IAS and TAS NMEAParser::ExtractParameter(String,ctemp,8); vias = StrToDouble(ctemp,NULL)/36; NMEAParser::ExtractParameter(String,ctemp,9); vtas = StrToDouble(ctemp,NULL)/36; if (vias >1) { pGPS->TrueAirspeed = vtas; pGPS->IndicatedAirspeed = vias; pGPS->AirspeedAvailable = TRUE; } else pGPS->AirspeedAvailable = FALSE; // external battery voltage NMEAParser::ExtractParameter(String,ctemp,10); pGPS->ExtBatt1_Voltage = StrToDouble(ctemp,NULL)/10; // OAT NMEAParser::ExtractParameter(String,ctemp,11); pGPS->OutsideAirTemperature = StrToDouble(ctemp,NULL)/10; pGPS->TemperatureAvailable=TRUE; TriggerVarioUpdate(); return TRUE; }
//#define CUPDEBUG bool ParseCUPWayPointString(TCHAR *String,WAYPOINT *Temp) { TCHAR ctemp[(COMMENT_SIZE*2)+1]; // must be bigger than COMMENT_SIZE! TCHAR *pToken; TCHAR TempString[READLINE_LENGTH+1]; TCHAR OrigString[READLINE_LENGTH+1]; TCHAR Tname[NAME_SIZE+1]; int flags=0; unsigned int i, j; bool ishome=false; // 100310 // strtok does not return empty fields. we create them here with special char #define DUMCHAR '|' Temp->Visible = true; // default all waypoints visible at start Temp->FarVisible = true; Temp->Format = LKW_CUP; Temp->Number = WayPointList.size(); Temp->FileNum = globalFileNum; #if BUGSTOP // This should never happen LKASSERT(_tcslen(String) < sizeof(OrigString)); #endif LK_tcsncpy(OrigString, String,READLINE_LENGTH); // if string is too short do nothing if (_tcslen(OrigString)<11) return false; #ifdef CUPDEBUG StartupStore(_T("OLD:<%s>%s"),OrigString,NEWLINE); #endif for (i=0,j=0; i<_tcslen(OrigString); i++) { // skip last comma, and avoid overruning the end if ( (i+1)>= _tcslen(OrigString)) break; if ( (OrigString[i] == _T(',')) && (OrigString[i+1] == _T(',')) ) { TempString[j++] = _T(','); TempString[j++] = _T(DUMCHAR); continue; } /* we need terminations for comments if ( OrigString[i] == _T('\r') ) continue; if ( OrigString[i] == _T('\n') ) continue; */ TempString[j++] = OrigString[i]; } TempString[j] = _T('\0'); #ifdef CUPDEBUG StartupStore(_T("NEW:<%s>%s"),TempString,NEWLINE); #endif // ---------------- NAME ---------------- pToken = _tcstok(TempString, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>NAME_SIZE) { pToken[NAME_SIZE-1]= _T('\0'); } _tcscpy(Temp->Name, pToken); CleanCupCode(Temp->Name); #ifdef CUPDEBUG StartupStore(_T(" CUP NAME=<%s>%s"),Temp->Name,NEWLINE); #endif // ---------------- CODE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>CUPSIZE_CODE) pToken[CUPSIZE_CODE-1]= _T('\0'); _tcscpy(Temp->Code, pToken); for (i=_tcslen(Temp->Code)-1; i>1; i--) if (Temp->Code[i]==' ') Temp->Code[i]=0; else break; _tcscpy(Tname,Temp->Code); for (j=0, i=0; i<_tcslen(Tname); i++) //if (Tname[i]!='\"') Temp->Code[j++]=Tname[i]; if ( (Tname[i]!='\"') && (Tname[i]!=DUMCHAR) ) Temp->Code[j++]=Tname[i]; Temp->Code[j]= _T('\0'); if (_tcslen(Temp->Code)>5) { // 100310 if ( _tcscmp(Temp->Code,_T("LKHOME")) == 0 ) { StartupStore(_T(". Found LKHOME inside CUP waypoint <%s>%s"),Temp->Name,NEWLINE); ishome=true; } } #ifdef CUPDEBUG StartupStore(_T(" CUP CODE=<%s>%s"),Temp->Code,NEWLINE); #endif // ---------------- COUNTRY ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; LK_tcsncpy(Temp->Country,pToken,CUPSIZE_COUNTRY); if (_tcslen(Temp->Country)>3) { Temp->Country[3]= _T('\0'); } if ((_tcslen(Temp->Country) == 1) && Temp->Country[0]==DUMCHAR) Temp->Country[0]=_T('\0'); #ifdef CUPDEBUG StartupStore(_T(" CUP COUNTRY=<%s>%s"),Temp->Country,NEWLINE); #endif // ---------------- LATITUDE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Latitude = CUPToLat(pToken); if((Temp->Latitude > 90) || (Temp->Latitude < -90)) { return false; } #ifdef CUPDEBUG StartupStore(_T(" CUP LATITUDE=<%f>%s"),Temp->Latitude,NEWLINE); #endif // ---------------- LONGITUDE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Longitude = CUPToLon(pToken); if((Temp->Longitude > 180) || (Temp->Longitude < -180)) { return false; } #ifdef CUPDEBUG StartupStore(_T(" CUP LONGITUDE=<%f>%s"),Temp->Longitude,NEWLINE); #endif // ---------------- ELEVATION ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Altitude = ReadAltitude(pToken); #ifdef CUPDEBUG StartupStore(_T(" CUP ELEVATION=<%f>%s"),Temp->Altitude,NEWLINE); #endif if (Temp->Altitude == -9999){ Temp->Altitude=0; } // ---------------- STYLE ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; Temp->Style = (int)_tcstol(pToken,NULL,10); switch(Temp->Style) { case 2: // airfield grass case 4: // glider site case 5: // airfield solid flags = AIRPORT; flags += LANDPOINT; break; case 3: // outlanding flags = LANDPOINT; break; default: flags = TURNPOINT; break; } if (ishome) flags += HOME; Temp->Flags = flags; #ifdef CUPDEBUG StartupStore(_T(" CUP STYLE=<%d> flags=%d %s"),Temp->Style,Temp->Flags,NEWLINE); #endif // ---------------- RWY DIRECTION ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if ((_tcslen(pToken) == 1) && (pToken[0]==DUMCHAR)) Temp->RunwayDir=-1; else Temp->RunwayDir = (int)AngleLimit360(_tcstol(pToken, NULL, 10)); #ifdef CUPDEBUG StartupStore(_T(" CUP RUNWAY DIRECTION=<%d>%s"),Temp->RunwayDir,NEWLINE); #endif // ---------------- RWY LENGTH ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if ((_tcslen(pToken) == 1) && (pToken[0]==DUMCHAR)) Temp->RunwayLen = -1; else Temp->RunwayLen = (int)ReadLength(pToken); #ifdef CUPDEBUG StartupStore(_T(" CUP RUNWAY LEN=<%d>%s"),Temp->RunwayLen,NEWLINE); #endif // ---------------- AIRPORT FREQ ------------------ pToken = _tcstok(NULL, TEXT(",")); if (pToken == NULL) return false; if (_tcslen(pToken)>CUPSIZE_FREQ) pToken[CUPSIZE_FREQ-1]= _T('\0'); _tcscpy(Temp->Freq, pToken); TrimRight(Temp->Freq); _tcscpy(Tname,Temp->Freq); for (j=0, i=0; i<_tcslen(Tname); i++) if ( (Tname[i]!='\"') && (Tname[i]!=DUMCHAR) ) Temp->Freq[j++]=Tname[i]; Temp->Freq[j]= _T('\0'); #ifdef CUPDEBUG StartupStore(_T(" CUP FREQ=<%s>%s"),Temp->Freq,NEWLINE); #endif // ---------------- COMMENT ------------------ pToken = _tcstok(NULL, TEXT("\n\r")); if (pToken != NULL) { if (_tcslen(pToken)>=COMMENT_SIZE) pToken[COMMENT_SIZE-1]= _T('\0'); // remove trailing spaces and CR LF _tcscpy(ctemp, pToken); for (i=_tcslen(ctemp)-1; i>1; i--) { if ( (ctemp[i]==' ') || (ctemp[i]=='\r') || (ctemp[i]=='\n') ) ctemp[i]=0; else break; } // now remove " " (if there) for (j=0, i=0; i<_tcslen(ctemp); i++) if (ctemp[i]!='\"') ctemp[j++]=ctemp[i]; ctemp[j]= _T('\0'); if (_tcslen(ctemp) >0 ) { if (Temp->Comment) { free(Temp->Comment); } Temp->Comment = (TCHAR*)malloc((_tcslen(ctemp)+1)*sizeof(TCHAR)); if (Temp->Comment) _tcscpy(Temp->Comment, ctemp); } #ifdef CUPDEBUG StartupStore(_T(" CUP COMMENT=<%s>%s"),Temp->Comment,NEWLINE); #endif } else { Temp->Comment=NULL; // useless } if(Temp->Altitude <= 0) { WaypointAltitudeFromTerrain(Temp); } if (Temp->Details) { free(Temp->Details); } return true; }