static void OnPaintComboPopupListItem(WindowControl * Sender, LKSurface& Surface) { if (Sender) { if (ComboListPopup->ComboPopupDrawListIndex >= 0 && ComboListPopup->ComboPopupDrawListIndex < ComboListPopup->ComboPopupItemCount) { // Fill Background with Highlight color if Selected Item if (!Sender->HasFocus() && ComboListPopup->ComboPopupItemIndex == ComboListPopup->ComboPopupDrawListIndex) { RECT rc = Sender->GetClientRect(); Surface.FillRect(&rc, LKBrush_Higlighted); } const int w = Sender->GetWidth(); const int h = Sender->GetHeight(); const TCHAR* szText = ComboListPopup->ComboPopupItemList[ComboListPopup->ComboPopupDrawListIndex]->StringValueFormatted; Surface.SetBackgroundTransparent(); Surface.SetTextColor(RGB_BLACK); const int xText = 3 * ScreenScale; const int yText = (h - Surface.GetTextHeight(szText)) / 2; Surface.DrawTextClip(xText, yText, szText, w - ScreenScale * 5); } } }
static void OnProgressPaint(WindowControl * Sender, LKSurface& Surface) { RECT PrintAreaR = Sender->GetClientRect(); const auto oldFont = Surface.SelectObject(MapWindowBoldFont); Surface.FillRect(&PrintAreaR, LKBrush_Petrol); // Create text area // we cannot use LKPen here because they are not still initialised for startup menu. no problem LKPen hP(PEN_SOLID,NIBLSCALE(1),RGB_GREEN); auto ohP = Surface.SelectObject(hP); const auto ohB = Surface.SelectObject(LKBrush_Petrol); Surface.Rectangle(PrintAreaR.left,PrintAreaR.top,PrintAreaR.right,PrintAreaR.bottom); Surface.SelectObject(ohP); hP.Release(); hP.Create(PEN_SOLID,NIBLSCALE(1),RGB_BLACK); ohP = Surface.SelectObject(hP); Surface.SelectObject(LK_HOLLOW_BRUSH); InflateRect(&PrintAreaR, -NIBLSCALE(2), -NIBLSCALE(2)); Surface.Rectangle(PrintAreaR.left,PrintAreaR.top,PrintAreaR.right,PrintAreaR.bottom); Surface.SetTextColor(RGB_WHITE); Surface.SetBackgroundTransparent(); InflateRect(&PrintAreaR, -NIBLSCALE(2), -NIBLSCALE(2)); const TCHAR* text = Sender->GetCaption(); Surface.DrawText(text, &PrintAreaR, DT_VCENTER|DT_SINGLELINE); Surface.SelectObject(ohB); Surface.SelectObject(ohP); Surface.SelectObject(oldFont); }
int MapWindow::SharedTopView(LKSurface& Surface, DiagrammStruct* psDia , double fAS_Bearing, double fWP_Bearing) { int iOldDisplayOrientation = DisplayOrientation; DiagrammStruct m_Dia = *psDia; const RECT& rct = m_Dia.rc; unsigned short getsideviewpage=GetSideviewPage(); LKASSERT(getsideviewpage<NUMBER_OF_SHARED_MULTIMAPS); LKASSERT(Current_Multimap_SizeY!=SIZE0); DisplayOrientation = GetMMNorthUp(getsideviewpage); switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: break; case NORTHUP: default: m_Dia.fXMin = -m_Dia.fXMax; break; } double fOldScale = zoom.Scale(); const auto hfOld = Surface.SelectObject(LK8PanelUnitFont); if(zoom.AutoZoom()) zoom.AutoZoom(false); double fFact = 1.25 ; #ifdef INIT_CASE switch(ScreenSize) { case ss800x480: fFact=0.750; break; case ss640x480: fFact=0.938; break; case ss480x272: fFact=0.708; break; case ss400x240: fFact=0.750; break; case ss320x240: fFact=0.938; break; case ss480x800: fFact=1.250; break; case ss480x640: fFact=1.250; break; case ss272x480: fFact=1.250; break; case ss240x400: fFact=1.250; break; case ss240x320: fFact=1.250; break; default: fFact=1.000; break; } #endif if((ScreenSizeX > 0) && (ScreenSizeY > 0)) { if(ScreenSizeX > ScreenSizeY) fFact = (double)ScreenSizeY/(double)ScreenSizeX * 1.250; } PanLatitude = DrawInfo.Latitude; PanLongitude = DrawInfo.Longitude; switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: DisplayAngle = AngleLimit360(fAS_Bearing +270.0); DisplayAircraftAngle = AngleLimit360(fWP_Bearing); break; case NORTHUP: default: DisplayAngle = 0; if( getsideviewpage == IM_HEADING || getsideviewpage==IM_VISUALGLIDE) DisplayAircraftAngle = AngleLimit360(fAS_Bearing); else DisplayAircraftAngle = AngleLimit360(DrawInfo.TrackBearing); break; } int iOldLocator = EnableThermalLocator; EnableThermalLocator =0; /*******/ #warning "wrong place for do that, always bad idea to change layout inside drawing fonctions !" MapWindow::ChangeDrawRect(rct); // set new area for terrain and topology /*******/ zoom.RequestedScale((m_Dia.fXMax -m_Dia.fXMin) * fFact * (DISTANCEMODIFY)/10.0f); POINT Orig = { CalcDistanceCoordinat(0.0, (DiagrammStruct*) &m_Dia),(rct.bottom-rct.top)/2}; POINT Orig_Aircraft= {0,0}; zoom.ModifyMapScale(); zoom.UpdateMapScale(); const ScreenProjection _Proj = CalculateScreenPositions( Orig, rct, &Orig_Aircraft); CalculateScreenPositionsAirspace(rct, _Proj); bool terrainpainted=false; if (IsMultimapTerrain() && DerivedDrawInfo.TerrainValid && RasterTerrain::isTerrainLoaded() ) { LKTextBlack=false; BlackScreen=false; LockTerrainDataGraphics(); DrawTerrain(Surface, rct, _Proj, GetAzimuth(), 40.0); UnlockTerrainDataGraphics(); terrainpainted=true; } else { // We fill up the background wity chosen empty map color Surface.FillRect(&rct, hInvBackgroundBrush[BgMapColor]); // We force LK painting black values on screen depending on the background color in use // blackscreen would force everything to be painted white, instead LKTextBlack=BgMapColorTextBlack[BgMapColor]; if (BgMapColor>6 ) BlackScreen=true; else BlackScreen=false; } ResetLabelDeclutter(); // We reduce screen cluttering for some cases.. short olddecluttermode=DeclutterMode; if (Current_Multimap_SizeY==SIZE4) goto _nomoredeclutter; if (Current_Multimap_SizeY<SIZE3) { DeclutterMode+=2; } else { if (Current_Multimap_SizeY==SIZE3) DeclutterMode++; } if (DeclutterMode>dmVeryHigh) DeclutterMode=dmVeryHigh; _nomoredeclutter: if (IsMultimapTopology()) { // Do not print topology labels, to be used with another config later! // SaturateLabelDeclutter(); DrawTopology(Surface, rct, _Proj); } else { // No topology is desired, but terrain requires water areas nevertheless if (terrainpainted) { DrawTopology(Surface, rct, _Proj, true); // water only! } } if (IsMultimapAirspace()) { DrawAirSpace(Surface, rct, _Proj); // full screen, to hide clipping effect on low border } if (Flags_DrawTask && MapSpaceMode!=MSM_MAPASP && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTaskAAT(Surface, rct); DrawTask(Surface, rct, _Proj, Orig_Aircraft); } if (IsMultimapWaypoints()) { DrawWaypointsNew(Surface,rct); } if (Flags_DrawFAI) DrawFAIOptimizer(Surface, rct, _Proj, Orig_Aircraft); DeclutterMode=olddecluttermode; // set it back correctly /* THIS STUFF DOES NOT WORK IN SHARED MAPS, YET NEED FIXING LatLon2Screen for shared maps using Sideview #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) DrawTerrainAbove(hdc, rct); #endif */ // // Stuff for MAPTRK only (M1) if (MapSpaceMode==MSM_MAPTRK) { if(IsMultimapTerrain() || IsMultimapTopology() ) { if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) DrawGlideThroughTerrain(Surface, rct, _Proj); } if (extGPSCONNECT) DrawBearing(Surface, rct, _Proj); // Wind arrow if (IsMultimapOverlaysGauges()) DrawWindAtAircraft2(Surface, Orig_Aircraft, rct); } if (MapSpaceMode==MSM_MAPWPT) { if (extGPSCONNECT) DrawBearing(Surface, rct, _Proj); } switch(GetMMNorthUp(getsideviewpage)) { case NORTHUP: default: DrawCompass( Surface, rct, 0); break; case TRACKUP: if(getsideviewpage == IM_HEADING || getsideviewpage == IM_VISUALGLIDE) DrawCompass( Surface, rct, DrawInfo.TrackBearing-90.0); else DrawCompass( Surface, rct, DisplayAngle); break; } /**************************************************************************************************** * draw vertical line ****************************************************************************************************/ POINT line[2]; line[0].x = rct.left; line[0].y = Orig_Aircraft.y-1; line[1].x = rct.right; line[1].y = line[0].y; switch(GetMMNorthUp(getsideviewpage)) { case TRACKUP: // Are we are not topview fullscreen? if (Current_Multimap_SizeY<SIZE4 && !(MapSpaceMode==MSM_VISUALGLIDE)) { Surface.DrawDashLine(NIBLSCALE(1), line[0], line[1], Sideview_TextColor, rct); } else { if (TrackBar) { DrawHeadUpLine(Surface, Orig, rct, psDia->fXMin ,psDia->fXMax); if (ISGAAIRCRAFT) DrawFuturePos(Surface, Orig, rct, true); } } break; case NORTHUP: default: if (TrackBar) { DrawHeadUpLine(Surface, Orig, rct, psDia->fXMin ,psDia->fXMax); if (ISGAAIRCRAFT) DrawFuturePos(Surface, Orig, rct, true); } break; } DrawAircraft(Surface, Orig_Aircraft); // M3 has sideview always on, so wont apply here, and no need to check if (Current_Multimap_SizeY==SIZE4) { DrawMapScale(Surface,rct,0); } MapWindow::zoom.RequestedScale(fOldScale); EnableThermalLocator = iOldLocator; DisplayOrientation = iOldDisplayOrientation; Surface.SelectObject(hfOld); return 0; }
void MapWindow::DrawVisualGlide(LKSurface& Surface, const DiagrammStruct& sDia) { const RECT& rci = sDia.rc; unsigned short numboxrows = 1; #if BUGSTOP LKASSERT(Current_Multimap_SizeY < SIZE4); #endif switch (Current_Multimap_SizeY) { case SIZE0: case SIZE1: numboxrows = 3; break; case SIZE2: numboxrows = 2; break; case SIZE3: numboxrows = 1; break; case SIZE4: return; default: LKASSERT(0); break; } if (!ScreenLandscape) { numboxrows++; if (numboxrows > 3) numboxrows = 3; } TCHAR tmpT[30]; line1Font = LK8VisualTopFont; line2Font = LK8VisualBotFont; SIZE textSizeTop, textSizeBot; Surface.SelectObject(line1Font); _stprintf(tmpT, _T("MMMM")); Surface.GetTextSize(tmpT, &textSizeTop); Surface.SelectObject(line2Font); _stprintf(tmpT, _T("55.5%s 79%s%s "), Units::GetDistanceName(), MsgToken(2179), MsgToken(2183)); Surface.GetTextSize(tmpT, &textSizeBot); // we can cut the waypoint name, but not the value data, so we use the second row of data // to size the box for everything. maxtSizeX = textSizeBot.cx; int a = (rci.right-rci.left) / (textSizeBot.cx+BOXINTERVAL); int b = (rci.right-rci.left) - a * (textSizeBot.cx)-(BOXINTERVAL * (a + 1)); boxSizeX = textSizeBot.cx + (b / (a + 1)); boxSizeY = textSizeTop.cy + 1; // single line (wp name) + distance from bottombar if (numboxrows > 1) { boxSizeY += (textSizeBot.cy * (numboxrows - 1)) - NIBLSCALE(2); if (numboxrows > 2) boxSizeY -= NIBLSCALE(1); } #if DEBUG_SCR StartupStore(_T("boxX=%d boxY=%d \n"), boxSizeX, boxSizeY); #endif #if DEBUG_SCR StartupStore(_T("VG AREA LTRB: %d,%d %d,%d\n"), rci.left, rci.top, rci.right, rci.bottom); #endif const auto oldBrush = Surface.SelectObject(LKBrush_White); const auto oldPen = Surface.SelectObject(LK_BLACK_PEN); BrushReference brush_back; if (!INVERTCOLORS) { brush_back = LKBrush_Black; } else { brush_back = LKBrush_Nlight; } Surface.FillRect(&rci, brush_back); POINT center, p1, p2; center.y = rci.top + (rci.bottom - rci.top) / 2; center.x = rci.left + (rci.right - rci.left) / 2; // numSlotX is the number items we can print horizontally. unsigned short numSlotX = (rci.right - rci.left) / (boxSizeX + BOXINTERVAL); if (numSlotX > MAXBSLOT) numSlotX = MAXBSLOT; #if BUGSTOP LKASSERT(numSlotX > 0); #endif if (numSlotX == 0) return; unsigned short boxInterval = ((rci.right - rci.left)-(boxSizeX * numSlotX)) / (numSlotX + 1); unsigned short oddoffset = ( (rci.right-rci.left) - (boxSizeX * numSlotX) - boxInterval * (numSlotX + 1)) / 2; /* #if BUGSTOP // not really harmful LKASSERT(oddoffset<=boxInterval); #endif */ #if DEBUG_SCR StartupStore(_T("numSlotX=%d ScreenSizeX=%d boxSizeX=%d interval=%d offset=%d\n"), numSlotX, ScreenSizeX, boxSizeX, boxInterval, oddoffset); #endif unsigned int t; // The horizontal grid unsigned int slotCenterX[MAXBSLOT + 1]; for (t = 0; t < numSlotX; t++) { slotCenterX[t] = (t * boxSizeX) + boxInterval * (t + 1)+(boxSizeX / 2) + oddoffset+rci.left; #if DEBUG_SCR StartupStore(_T("slotCenterX[%d]=%d\n"), t, slotCenterX[t]); #endif } // Vertical coordinates of each up/down subwindow, excluding center line int upYtop = rci.top; #if MIDCENTER int upYbottom = center.y + (boxSizeY / 2); int downYtop = center.y - (boxSizeY / 2); #else int upYbottom = center.y - CENTERYSPACE; int downYtop = center.y + CENTERYSPACE; #endif int upSizeY = upYbottom - upYtop - (boxSizeY); ; int downYbottom = rci.bottom; int downSizeY = downYbottom - downYtop - (boxSizeY); ; #if 0 // Reassign dynamically the vertical scale for each subwindow size double vscale = 1000 * (100 - Current_Multimap_SizeY) / 100; #else // Set the vertical range double vscale; if (Units::GetUserAltitudeUnit() == unFeet) vscale = (1000 / TOFEET); else vscale = 300.0; #endif Surface.SetBackgroundTransparent(); RECT trc = rci; // Top part of visual rect, target is over us=unreachable=red trc.top = rci.top; trc.bottom = center.y - 1; #ifndef DITHER RenderSky(Surface, trc, RGB_WHITE, LKColor(150, 255, 150), GC_NO_COLOR_STEPS / 2); #else RenderSky(Surface, trc, RGB_WHITE, RGB_WHITE, GC_NO_COLOR_STEPS / 2); #endif // Bottom part, target is below us=reachable=green trc.top = center.y + 1; trc.bottom = rci.bottom; #ifndef DITHER RenderSky(Surface, trc, LKColor(255, 150, 150), RGB_WHITE, GC_NO_COLOR_STEPS / 2); #else RenderSky(Surface, trc, RGB_WHITE, RGB_WHITE,GC_NO_COLOR_STEPS / 2); #endif // Draw center line p1.x = rci.left + 1; p1.y = center.y; p2.x = rci.right - 1; p2.y = center.y; Surface.SelectObject(LKPen_Black_N1); Surface.DrawSolidLine(p1, p2, rci); #if DEBUG_SCR StartupStore(_T("... Center line: Y=%d\n"), center.y); #endif Surface.SelectObject(line1Font); Surface.SelectObject(LKPen_Black_N0); ResetVisualGlideGlobals(); short res = GetVisualGlidePoints(numSlotX); if (res == INVALID_VALUE) { #if DEBUG_DVG StartupStore(_T("...... GVGP says not ready, wait..\n")); #endif return; } if (res == 0) { #if DEBUG_DVG StartupStore(_T("...... GVGP says no data available!\n")); #endif return; } // Print them all! int offset = (boxSizeY / 2) + CENTERYSPACE; LKBrush bcolor; LKColor rgbcolor, textcolor; int wp; unsigned short zeroslot = 0; double minbrgdiff = 999.0; double minabrgdiff = 999.0; // absolute never negative for (unsigned short n = 0; n < numSlotX; n++) { wp = slotWpIndex[n]; if (!ValidWayPoint(wp)) { // empty slot nothing to print continue; } double brgdiff = WayPointCalc[wp].Bearing - DrawInfo.TrackBearing; // this check is worthless if (brgdiff < -180.0) { brgdiff += 360.0; } else { if (brgdiff > 180.0) brgdiff -= 360.0; } double abrgdiff = brgdiff; if (abrgdiff < 0) abrgdiff *= -1; if (abrgdiff < minabrgdiff) { zeroslot = n; minabrgdiff = abrgdiff; minbrgdiff = brgdiff; } } // Draw vertical line #define DEGRANGE 10 // degrees left and right to perfect target if (minabrgdiff < 1) { p1.x = slotCenterX[zeroslot]; } else { // set fullscale range if (minabrgdiff > DEGRANGE) { minabrgdiff = DEGRANGE; if (minbrgdiff < 0) minbrgdiff = -1 * DEGRANGE; else minbrgdiff = DEGRANGE; } // we shift of course in the opposite direction p1.x = slotCenterX[zeroslot]-(int) ((boxSizeX / (DEGRANGE * 2)) * minbrgdiff); } p2.x = p1.x; p1.y = rci.top + 1; p2.y = rci.bottom - 1; Surface.SelectObject(LKPen_Black_N1); Surface.DrawSolidLine(p1, p2, rci); for (unsigned short n = 0; n < numSlotX; n++) { wp = slotWpIndex[n]; if (!ValidWayPoint(wp)) { // empty slot nothing to print continue; } #if DEBUG_DVG StartupStore(_T("... DVG PRINT [%d]=%d <%s>\n"), n, wp, WayPointList[wp].Name); #endif Sideview_VGWpt[n] = wp; double altdiff = WayPointCalc[wp].AltArriv[AltArrivMode]; int ty; #if DEBUG_SCR StartupStore(_T("... wp=<%s>\n"), WayPointList[wp].Name); #endif // Since terrain can be approximated due to low precision maps, or waypoint position or altitude error, // we have a common problem: we get an obstacle to get to the waypoint because it is // positioned "BELOW" the terrain itself. We try to reduce this problem here. #define SAFETERRAIN 50 // Positive arrival altitude for the waypoint, upper window if (altdiff >= 0) { if (altdiff == 0)altdiff = 1; double d = vscale / altdiff; if (d == 0) d = 1; ty = upYbottom - (int) ((double) upSizeY / d)-(boxSizeY / 2); #if DEBUG_SCR StartupStore(_T("... upYbottom=%d upSizeY=%d / (vscale=%f/altdiff=%f = %f) =- %d ty=%d offset=%d\n"), upYbottom, upSizeY, vscale, altdiff, d, (int) ((double) upSizeY / d), ty, offset); #endif if ((ty - offset) < upYtop) ty = upYtop + offset; if ((ty + offset) > upYbottom) ty = upYbottom - offset; #if DEBUG_SCR StartupStore(_T("... upYtop=%d upYbottom=%d final ty=%d\n"), upYtop, upYbottom, ty); #endif // // This is too confusing. We want simple colors, not shaded // rgbcolor = MixColors( LKColor(50,255,50), LKColor(230,255,230), altdiff/(vscale-50)); // if (altdiff <= SAFETERRAIN) { rgbcolor = RGB_LIGHTYELLOW; } else { if (!CheckLandableReachableTerrainNew(&DrawInfo, &DerivedDrawInfo, WayPointCalc[wp].Distance, WayPointCalc[wp].Bearing)) { rgbcolor = RGB_LIGHTRED; } else { #ifdef DITHER rgbcolor = RGB_WHITE; #else rgbcolor = RGB_LIGHTGREEN; #endif } } bcolor.Create(rgbcolor); } else { double d = vscale / altdiff; if (d == 0) d = -1; ty = downYtop - (int) ((double) downSizeY / d)+(boxSizeY / 2); // - because the left part is negative, we are really adding. if ((ty - offset) < downYtop) ty = downYtop + offset; if ((ty + offset) > downYbottom) ty = downYbottom - offset; #ifdef DITHER rgbcolor = RGB_WHITE; // negative part, no need to render dark #else rgbcolor = RGB_LIGHTRED; #endif bcolor.Create(rgbcolor); } TCHAR line2[40], line3[40]; TCHAR value[40], unit[30]; TCHAR name[NAME_SIZE + 1]; double ar = (WayPointCalc[wp].AltArriv[AltArrivMode] * ALTITUDEMODIFY); _tcscpy(name, WayPointList[wp].Name); CharUpper(name); if (IsSafetyAltitudeInUse(wp)) textcolor = RGB_DARKBLUE; else textcolor = RGB_BLACK; switch (numboxrows) { case 0: #if BUGSTOP LKASSERT(0); #endif return; case 1: // 1 line: waypoint name VGTextInBox(Surface, n, 1, name, NULL, NULL, slotCenterX[n], ty, textcolor, bcolor); break; case 2: // 2 lines: waypoint name + altdiff LKFormatAltDiff(wp, false, value, unit); // Should we print also the GR? if ((ar >= -9999 && ar <= 9999) && (WayPointCalc[wp].GR < MAXEFFICIENCYSHOW)) { if (ar >= -999 && ar <= 999) _stprintf(line2, _T("%s "), value); else _stprintf(line2, _T("%s "), value); LKFormatGR(wp, false, value, unit); _tcscat(line2, value); } else { _stprintf(line2, _T("%s ---"), value); } VGTextInBox(Surface, n, 2, name, line2, NULL, slotCenterX[n], ty, textcolor, bcolor); break; case 3: // 3 lines: waypoint name + dist + altdiff LKFormatDist(wp, false, value, unit); _stprintf(line2, _T("%s%s"), value, unit); LKFormatBrgDiff(wp, false, value, unit); _stprintf(tmpT, _T(" %s%s"), value, unit); _tcscat(line2, tmpT); LKFormatAltDiff(wp, false, value, unit); // Should we print also the GR? if ((ar >= -9999 && ar <= 9999) && (WayPointCalc[wp].GR < MAXEFFICIENCYSHOW)) { if (ar >= -999 && ar <= 999) _stprintf(line3, _T("%s "), value); else _stprintf(line3, _T("%s "), value); LKFormatGR(wp, false, value, unit); _tcscat(line3, value); } else { _stprintf(line3, _T("%s ---"), value); } VGTextInBox(Surface, n, 3, name, line2, line3, slotCenterX[n], ty, textcolor, bcolor); break; default: #if BUGSTOP LKASSERT(0); #endif return; } } // for numSlotX // Cleanup and return Surface.SelectObject(oldBrush); Surface.SelectObject(oldPen); return; }
void MapWindow::RenderMapWindowBg(LKSurface& Surface, const RECT& rc) { if ( (LKSurface::AlphaBlendSupported() && BarOpacity < 100) || mode.AnyPan() ) { RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY}; MapWindow::ChangeDrawRect(newRect); } else { RECT newRect = {0, 0, ScreenSizeX, ScreenSizeY - BottomSize - (ScreenSizeY-MapRect.bottom)-1}; MapWindow::ChangeDrawRect(newRect); } if (QUICKDRAW) { goto _skip_calcs; } // Here we calculate arrival altitude, GD etc for map waypoints. Splitting with multicalc will result in delayed // updating of visible landables, for example. The nearest pages do this separately, with their own sorting. // Basically we assume -like for nearest- that values will not change that much in the multicalc split time. // Target and tasks are recalculated in real time in any case. Nearest too. LKCalculateWaypointReachable(false); _skip_calcs: if (PGZoomTrigger) { if (!mode.Is(Mode::MODE_PANORAMA)) { mode.Special(Mode::MODE_SPECIAL_PANORAMA, true); LastZoomTrigger = DrawInfo.Time; Message::AddMessage(1000, 3, gettext(TEXT("_@M872_"))); // LANDSCAPE ZOOM FOR 20s LKSound(TEXT("LK_TONEUP.WAV")); } else { // previously called, see if time has passed if (DrawInfo.Time > (LastZoomTrigger + 20.0)) { // time has passed, lets go back LastZoomTrigger = 0; // just for safety mode.Special(Mode::MODE_SPECIAL_PANORAMA, false); PGZoomTrigger = false; Message::AddMessage(1500, 3, gettext(TEXT("_@M873_"))); // BACK TO NORMAL ZOOM LKSound(TEXT("LK_TONEDOWN.WAV")); } } } // // "Checkpoint Charlie" // This is were we process stuff for anything else but main map. // We let the calculations run also for MapSpace modes. // But for multimaps, we can also draw some more stuff.. // We are also sent back here from next code, when we detect that // the MapSpace mode has changed from MAP to something else while we // were rendering. // QuickRedraw: // if (DONTDRAWTHEMAP) { const bool isMultimap = IsMultiMapShared(); // DrawMapSpace can change "MapSpaceMode", get this before. DrawMapSpace(Surface, rc); // Is this a "shared map" environment? if (isMultimap) { // Shared map, of course not MSN_MAP, since dontdrawthemap was checked // if (IsMultimapOverlaysGauges()) { RenderOverlayGauges(Surface, rc); } if (IsMultimapOverlaysText()) { DrawLook8000(Surface, rc); } } else { // Not in map painting environment // ex. nearest pages, but also MAPRADAR.. } // DrawBottomBar(Surface, rc); #ifdef DRAWDEBUG DrawDebug(hdc, rc); #endif // no need to do SelectObject as at the bottom of function return; } POINT Orig, Orig_Aircraft; CalculateOrigin(rc, &Orig); const ScreenProjection _Proj = CalculateScreenPositions(Orig, rc, &Orig_Aircraft); // When no terrain is painted, set a background0 // Remember that in this case we have plenty of cpu time to spend for best result if (!IsMultimapTerrain() || !DerivedDrawInfo.TerrainValid || !RasterTerrain::isTerrainLoaded()) { // We force LK painting black values on screen depending on the background color in use // TODO make it an array once settled // blackscreen would force everything to be painted white, instead LKTextBlack = BgMapColorTextBlack[BgMapColor]; if (BgMapColor > 6) BlackScreen = true; else BlackScreen = false; } else { LKTextBlack = false; BlackScreen = false; } // Logic of DONTDRAWTHEMAP is the following: // We are rendering the screen page here. If we are here, we passed Checkpoint Charlie. // So we were, at charlie, in MSM_MAP: preparing the main map stuff. // If we detect that MapSpace has CHANGED while we were doing our job here, // it means that the user has clicked meanwhile. He desires another page, so let's // reset our intentions and go back to beginning, or nearby.. // We have a new job to do, for another MapSpace, no more MAP. if (DONTDRAWTHEMAP) { goto QuickRedraw; } bool terrainpainted = false; if ((IsMultimapTerrain() && (DerivedDrawInfo.TerrainValid) && RasterTerrain::isTerrainLoaded()) ) { // sunelevation is never used, it is still a todo in Terrain double sunelevation = 40.0; double sunazimuth = GetAzimuth(); LockTerrainDataGraphics(); if (DONTDRAWTHEMAP) { // 100318 UnlockTerrainDataGraphics(); goto QuickRedraw; } if(DrawTerrain(Surface, DrawRect, _Proj, sunazimuth, sunelevation)) { terrainpainted = true; } if (DONTDRAWTHEMAP) { UnlockTerrainDataGraphics(); goto QuickRedraw; } if (!QUICKDRAW) { // SHADED terrain unreachable, aka glide amoeba. This is not the outlined perimeter! #ifdef GTL2 if (((FinalGlideTerrain == 2) || (FinalGlideTerrain == 4)) && DerivedDrawInfo.TerrainValid) { #else if ((FinalGlideTerrain == 2) && DerivedDrawInfo.TerrainValid) { #endif DrawTerrainAbove(Surface, DrawRect); } } UnlockTerrainDataGraphics(); } // // REMINDER: WE ARE IN MAIN MAP HERE: MSM_MAP ONLY, OR PANNING MODE! // MAPSPACEMODE CAN STILL CHANGE, DUE TO USER INPUT. BUT WE GOT HERE IN // EITHER PAN OR MSM_MAP. // if (DONTDRAWTHEMAP) { goto QuickRedraw; } if(!terrainpainted) { // fill background.. Surface.FillRect(&rc, hInvBackgroundBrush[BgMapColor]); } if (IsMultimapTopology()) { DrawTopology(Surface, DrawRect, _Proj); } else { // If no topology wanted, but terrain painted, we paint only water stuff if (terrainpainted) DrawTopology(Surface, DrawRect, _Proj, true); } #if 0 StartupStore(_T("... Experimental1=%.0f\n"), Experimental1); StartupStore(_T("... Experimental2=%.0f\n"), Experimental2); Experimental1 = 0.0; Experimental2 = 0.0; #endif // Topology labels are printed first, using OLD wps positions from previous run! // Reset for topology labels decluttering engine occurs also in another place here! ResetLabelDeclutter(); if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTaskAAT(Surface, DrawRect); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if (IsMultimapAirspace()) { DrawAirSpace(Surface, rc, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // In QUICKDRAW dont draw trail, thermals, glide terrain if (QUICKDRAW) { goto _skip_stuff; } DrawThermalEstimate(Surface, DrawRect, _Proj); if (OvertargetMode == OVT_THER) DrawThermalEstimateMultitarget(Surface, DrawRect, _Proj); // draw red cross on glide through terrain marker if (FinalGlideTerrain && DerivedDrawInfo.TerrainValid) { DrawGlideThroughTerrain(Surface, DrawRect, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } _skip_stuff: if (IsMultimapAirspace() && AirspaceWarningMapLabels) { DrawAirspaceLabels(Surface, DrawRect, _Proj, Orig_Aircraft); if (DONTDRAWTHEMAP) { // 100319 goto QuickRedraw; } } if (IsMultimapWaypoints()) { DrawWaypointsNew(Surface, DrawRect); } if (TrailActive) { LKDrawLongTrail(Surface, Orig_Aircraft, DrawRect); // NEED REWRITING LKDrawTrail(Surface, DrawRect, _Proj); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } if ((Flags_DrawTask || TargetDialogOpen) && ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTask(Surface, DrawRect, _Proj, Orig_Aircraft); } if (Flags_DrawFAI) { if (MapWindow::DerivedDrawInfo.Flying) { // FAI optimizer does not depend on tasks, being based on trace DrawFAIOptimizer(Surface, DrawRect, _Proj, Orig_Aircraft); } else { // not flying => show FAI sectors for the task if (ValidTaskPoint(ActiveTaskPoint) && ValidTaskPoint(1)) { DrawTaskSectors(Surface, DrawRect, _Proj); } } } // In QUICKDRAW do not paint other useless stuff if (QUICKDRAW) { if (extGPSCONNECT) DrawBearing(Surface, DrawRect, _Proj); goto _skip_2; } // --------------------------------------------------- DrawTeammate(Surface, rc, _Proj); if (extGPSCONNECT) { DrawBestCruiseTrack(Surface, Orig_Aircraft); DrawBearing(Surface, DrawRect, _Proj); } // draw wind vector at aircraft if (NOTANYPAN) { DrawWindAtAircraft2(Surface, Orig_Aircraft, DrawRect); } else if (mode.Is(Mode::MODE_TARGET_PAN)) { DrawWindAtAircraft2(Surface, Orig, rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // Draw traffic and other specifix LK gauges LKDrawFLARMTraffic(Surface, DrawRect, _Proj, Orig_Aircraft); // --------------------------------------------------- _skip_2: if (NOTANYPAN) { if (IsMultimapOverlaysGauges()) { RenderOverlayGauges(Surface, rc); } if (TrackBar) { DrawHeading(Surface, Orig, DrawRect); if (ISGAAIRCRAFT) { DrawFuturePos(Surface, Orig, DrawRect); } } if (ISGAAIRCRAFT) { DrawHSIarc(Surface, Orig, DrawRect); } if (IsMultimapOverlaysText()) { DrawLook8000(Surface, rc); } DrawBottomBar(Surface, rc); } if (DONTDRAWTHEMAP) { goto QuickRedraw; } // Draw glider or paraglider if (extGPSCONNECT) { DrawAircraft(Surface, Orig_Aircraft); } #if USETOPOMARKS // marks on top... DrawMarks(hdc, rc); #endif if (!INPAN) { DrawMapScale(Surface, rc, zoom.BigZoom()); // unused BigZoom DrawCompass(Surface, rc, DisplayAngle); } #ifdef DRAWDEBUG DrawDebug(hdc, rc); #endif }
void MapWindow::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 MapWindow::DrawAspNearest(LKSurface& Surface, const RECT& rc) { SIZE ASPTextSize, DSTextSize, BETextSize, TYTextSize, ACTextSize, HLTextSize, MITextSize; SIZE phdrTextSize; TCHAR Buffer[LKSIZEBUFFERLARGE]; static RECT s_sortBox[6]; static TCHAR Buffer1[MAXNEARAIRSPACES][MAXAIRSPACENUMPAGES][30], Buffer2[MAXNEARAIRSPACES][MAXAIRSPACENUMPAGES][12]; static TCHAR Buffer3[MAXNEARAIRSPACES][MAXAIRSPACENUMPAGES][12]; static TCHAR Buffer4[MAXNEARAIRSPACES][MAXAIRSPACENUMPAGES][12], Buffer5[MAXNEARAIRSPACES][MAXAIRSPACENUMPAGES][12]; static short s_maxnlname; static TCHAR s_trailspace[3]; short i, j, k, iRaw, wlen, rli=0, curpage, drawn_items_onpage; double value; LKColor rcolor; // column0 starts after writing 1:2 (ModeIndex:CURTYPE+1) with a different font.. static short Column0; static short Column1, Column2, Column3, Column4, Column5; static POINT p1, p2; static short s_rawspace; static unsigned short lincr; // Printable area for live nearest values static short left,right,bottom; // one for each mapspace, no matter if 0 and 1 are unused // we lock to current mapspace for this drawing short curmapspace=MapSpaceMode; static int AspNumraws=0; static bool usetwolines=0; // Vertical and horizontal spaces #define INTERRAW 1 #define HEADRAW NIBLSCALE(6) BrushReference sortbrush; RECT invsel; if (INVERTCOLORS) { sortbrush=LKBrush_LightGreen; } else { sortbrush=LKBrush_DarkGreen; } if (DoInit[MDI_DRAWASPNEAREST]) { usetwolines=UseTwoLines; // Set screen borders to avoid writing on extreme pixels if ( !ScreenLandscape ) { // Portrait mode can work on two rows left=rc.left+NIBLSCALE(1); right=rc.right-NIBLSCALE(1); bottom=rc.bottom-BottomSize-NIBLSCALE(2); s_maxnlname=7; _stprintf(Buffer,TEXT("AKSJSMMMM")); } else { left=rc.left+NIBLSCALE(5); right=rc.right-NIBLSCALE(5); bottom=rc.bottom-BottomSize; s_maxnlname=15; _stprintf(Buffer,TEXT("ABCDEF GHIJK-LM")); // now resize for tuning on resolutions if (ScreenSize == ss320x240) s_maxnlname=9; if (ScreenSize == ss400x240) s_maxnlname=10; } Buffer[s_maxnlname]='\0'; /// WPT is now AIRSPACE name Surface.SelectObject(LK8InfoBigFont); // Text font for Nearest was LK8Title Surface.GetTextSize(Buffer, _tcslen(Buffer), &ASPTextSize); // DST is always distance _stprintf(Buffer,TEXT("000.0")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &DSTextSize); // Bearing _stprintf(Buffer,TEXT("<<123")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &BETextSize); // TYPE, 4 letters printed #define LKASP_TYPE_LEN 4 _stprintf(Buffer,TEXT("CTRA")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &TYTextSize); // Flags can be SFE, three chars _stprintf(Buffer,TEXT("SFE")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &ACTextSize); Surface.SelectObject(LK8InfoNormalFont); _stprintf(Buffer,TEXT("MMMM")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &HLTextSize); Surface.SelectObject(LK8PanelMediumFont); _stprintf(Buffer,TEXT("1.1")); Surface.GetTextSize(Buffer, _tcslen(Buffer), &MITextSize); short afterwpname=left+ASPTextSize.cx+NIBLSCALE(5); short intercolumn=(right-afterwpname- DSTextSize.cx-BETextSize.cx-TYTextSize.cx-ACTextSize.cx)/3; // Col0 is where ASP 1/3 can be written, after ModeIndex:Curtype Column0=MITextSize.cx+LEFTLIMITER+NIBLSCALE(5); Column1=left; // WP align left if (ScreenLandscape || !usetwolines) { Column2=afterwpname+TYTextSize.cx; // TY align right Column3=Column2+intercolumn+DSTextSize.cx; // DS align right Column4=Column3+intercolumn+BETextSize.cx; // BE align right Column5=Column4+intercolumn+ACTextSize.cx; // AC align right } else { Surface.SelectObject(LK8PanelMediumFont); Surface.GetTextSize(_T("2.4_ASP_3/3_"), 12, &phdrTextSize); int s=(rc.right - phdrTextSize.cx)/4; Column5= right - NIBLSCALE(2); Column4= Column5 - s; Column3= Column4 - s; Column2= Column3 - s; } if ( !ScreenLandscape ) { if (usetwolines) { lincr=2; TopSize=rc.top+HEADRAW*2+ASPTextSize.cy; } else { lincr=1; TopSize=rc.top+HEADRAW*2+HLTextSize.cy; } p1.x=0; p1.y=TopSize; p2.x=rc.right; p2.y=p1.y; TopSize+=HEADRAW; AspNumraws=(bottom - TopSize) / (ASPTextSize.cy+(INTERRAW*2)); if (AspNumraws>MAXNEARAIRSPACES) AspNumraws=MAXNEARAIRSPACES; s_rawspace=(ASPTextSize.cy+INTERRAW); Column5=rc.right-NIBLSCALE(1)-1; _tcscpy(s_trailspace,_T("")); } else { lincr=1; TopSize=rc.top+HEADRAW*2+HLTextSize.cy; p1.x=0; p1.y=TopSize; p2.x=rc.right; p2.y=p1.y; TopSize+=HEADRAW/2; AspNumraws=(bottom - TopSize) / (ASPTextSize.cy+INTERRAW); if (AspNumraws>MAXNEARAIRSPACES) AspNumraws=MAXNEARAIRSPACES; s_rawspace=(ASPTextSize.cy+INTERRAW); _tcscpy(s_trailspace,_T(" ")); } #define INTERBOX intercolumn/2 s_sortBox[0].left=Column0; if (!ScreenLandscape && usetwolines) { s_sortBox[0].right=phdrTextSize.cx; } else { if ( !ScreenLandscape ) s_sortBox[0].right= left+ASPTextSize.cx-NIBLSCALE(2); else s_sortBox[0].right=left+ASPTextSize.cx-NIBLSCALE(10); } s_sortBox[0].top=2; s_sortBox[0].bottom=p1.y; SortBoxX[MSM_AIRSPACES][0]=s_sortBox[0].right; if (!ScreenLandscape && usetwolines) { s_sortBox[1].left=s_sortBox[0].right; } else { if ( !ScreenLandscape ) s_sortBox[1].left=Column1+afterwpname-INTERBOX; else s_sortBox[1].left=Column1+afterwpname-INTERBOX-NIBLSCALE(2); } if (!ScreenLandscape && usetwolines) s_sortBox[1].right=Column2+NIBLSCALE(2); else s_sortBox[1].right=Column2+INTERBOX; s_sortBox[1].top=2; s_sortBox[1].bottom=p1.y; SortBoxX[MSM_AIRSPACES][1]=s_sortBox[1].right; if (!ScreenLandscape && usetwolines) { s_sortBox[2].left=Column2+NIBLSCALE(2); s_sortBox[2].right=Column3+NIBLSCALE(2); } else { s_sortBox[2].left=Column2+INTERBOX; s_sortBox[2].right=Column3+INTERBOX; } s_sortBox[2].top=2; s_sortBox[2].bottom=p1.y; SortBoxX[MSM_AIRSPACES][2]=s_sortBox[2].right; if (!ScreenLandscape && usetwolines) { s_sortBox[3].left=Column3+NIBLSCALE(2); s_sortBox[3].right=Column4+NIBLSCALE(2); } else { s_sortBox[3].left=Column3+INTERBOX; s_sortBox[3].right=Column4+INTERBOX; } s_sortBox[3].top=2; s_sortBox[3].bottom=p1.y; SortBoxX[MSM_AIRSPACES][3]=s_sortBox[3].right; if (!ScreenLandscape && usetwolines) { s_sortBox[4].left=Column4+NIBLSCALE(2); s_sortBox[4].right=rc.right-1; } else { s_sortBox[4].left=Column4+INTERBOX; s_sortBox[4].right=rc.right-1; } s_sortBox[4].top=2; s_sortBox[4].bottom=p1.y; SortBoxX[MSM_AIRSPACES][4]=s_sortBox[4].right; SortBoxY[MSM_AIRSPACES]=p1.y; AspNumpages=roundupdivision(MAXNEARAIRSPACES*lincr, AspNumraws); if (AspNumpages>MAXAIRSPACENUMPAGES) AspNumpages=MAXAIRSPACENUMPAGES; else if (AspNumpages<1) AspNumpages=1; SelectedRaw[MSM_AIRSPACES]=0; SelectedPage[MSM_AIRSPACES]=0; DoInit[MDI_DRAWASPNEAREST]=false; return; } // doinit bool ndr; ndr=DoAirspaces(&DrawInfo, &DerivedDrawInfo); AspNumpages=roundupdivision(LKNumAirspaces*lincr, AspNumraws); if (AspNumpages>MAXAIRSPACENUMPAGES) AspNumpages=MAXAIRSPACENUMPAGES; else if (AspNumpages<1) AspNumpages=1; curpage=SelectedPage[curmapspace]; if (curpage<0||curpage>=MAXAIRSPACENUMPAGES) { // TODO also >Numpages SelectedPage[curmapspace]=0; LKevent=LKEVENT_NONE; return; } switch (LKevent) { case LKEVENT_NONE: break; case LKEVENT_ENTER: LKevent=LKEVENT_NONE; i=LKSortedAirspaces[SelectedRaw[curmapspace] + (curpage*AspNumraws/lincr)]; if ( ValidAirspace(i)) { CCriticalSection::CGuard guard(CAirspaceManager::Instance().MutexRef()); CAirspaceManager::Instance().PopupAirspaceDetail(LKAirspaces[i].Pointer); } LKevent=LKEVENT_NONE; return; break; case LKEVENT_DOWN: if (++SelectedRaw[curmapspace] >=AspNumraws) SelectedRaw[curmapspace]=0; break; case LKEVENT_UP: if (--SelectedRaw[curmapspace] <0) SelectedRaw[curmapspace]=AspNumraws-1; break; case LKEVENT_PAGEUP: LKevent=LKEVENT_NONE; break; case LKEVENT_PAGEDOWN: LKevent=LKEVENT_NONE; break; case LKEVENT_NEWRUN: for (i=0; i<MAXNEARAIRSPACES; i++) { for (k=0; k<MAXAIRSPACENUMPAGES; k++) { _stprintf(Buffer1[i][k], _T("----------------------------")); // max 30 Buffer1[i][k][s_maxnlname+7]='\0'; // some more dashes _stprintf(Buffer2[i][k],_T("----")); _stprintf(Buffer3[i][k],_T("----")); _stprintf(Buffer4[i][k],_T("----")); _stprintf(Buffer5[i][k],_T(" ")); } } break; case LKEVENT_NEWPAGE: break; default: LKevent=LKEVENT_NONE; break; } if (INVERTCOLORS) Surface.DrawLine(PEN_SOLID, NIBLSCALE(1), p1, p2, RGB_GREEN, rc); else Surface.DrawLine(PEN_SOLID, NIBLSCALE(1), p1, p2, RGB_DARKGREEN, rc); Surface.SelectObject(LK8InfoNormalFont); // Heading line short cursortbox=SortedMode[curmapspace]; if ( !ScreenLandscape ) { // portrait mode Surface.FillRect(&s_sortBox[cursortbox], sortbrush); _stprintf(Buffer,TEXT("%d.%d"),ModeIndex,CURTYPE+1); Surface.SelectObject(LK8PanelMediumFont); LKWriteText(Surface, Buffer, LEFTLIMITER, rc.top+TOPLIMITER , 0, WTMODE_NORMAL, WTALIGN_LEFT, RGB_LIGHTGREEN, false); Surface.SelectObject(LK8InfoNormalFont); _stprintf(Buffer,TEXT("%s %d/%d"), gettext(TEXT("_@M1642_")), curpage+1, AspNumpages); // ASP if (cursortbox == 0) LKWriteText(Surface, Buffer, Column0, HEADRAW-NIBLSCALE(1) , 0, WTMODE_NORMAL, WTALIGN_LEFT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column0, HEADRAW-NIBLSCALE(1) , 0, WTMODE_NORMAL, WTALIGN_LEFT, RGB_LIGHTGREEN, false); _tcscpy(Buffer,gettext(TEXT("_@M752_"))); // Type if (cursortbox==1) LKWriteText(Surface, Buffer, Column2, HEADRAW , 0, WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column2, HEADRAW , 0, WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); _tcscpy(Buffer,gettext(TEXT("_@M1300_"))); // Dist if (cursortbox==2) LKWriteText(Surface, Buffer, Column3, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column3, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); _tcscpy(Buffer,gettext(TEXT("_@M1301_"))); // Dir if (cursortbox==3) LKWriteText(Surface, Buffer, Column4, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column4, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); // Active mode _tcscpy(Buffer,TEXT("*")); if (cursortbox==4) LKWriteText(Surface, Buffer, Column5, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column5, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); } else { Surface.FillRect(&s_sortBox[cursortbox], sortbrush); _stprintf(Buffer,TEXT("%d.%d"),ModeIndex,CURTYPE+1); Surface.SelectObject(LK8PanelMediumFont); LKWriteText(Surface, Buffer, LEFTLIMITER, rc.top+TOPLIMITER , 0, WTMODE_NORMAL, WTALIGN_LEFT, RGB_LIGHTGREEN, false); Surface.SelectObject(LK8InfoNormalFont); _stprintf(Buffer,TEXT("%s %d/%d"), gettext(TEXT("_@M1642_")), curpage+1, AspNumpages); // ASP if (cursortbox==0) LKWriteText(Surface, Buffer, Column0, HEADRAW-NIBLSCALE(1) , 0,WTMODE_NORMAL, WTALIGN_LEFT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column0, HEADRAW-NIBLSCALE(1) , 0,WTMODE_NORMAL, WTALIGN_LEFT, RGB_LIGHTGREEN, false); _tcscpy(Buffer,gettext(TEXT("_@M752_"))); // Type if (cursortbox==1) LKWriteText(Surface, Buffer, Column2, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column2, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); _tcscpy(Buffer,gettext(TEXT("_@M1300_"))); // Dist if (cursortbox==2) LKWriteText(Surface, Buffer, Column3, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column3, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); _tcscpy(Buffer,gettext(TEXT("_@M1301_"))); // dir if (cursortbox==3) LKWriteText(Surface, Buffer, Column4, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column4, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); _stprintf(Buffer,TEXT("*")); if (cursortbox==4) LKWriteText(Surface, Buffer, Column5, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_BLACK, false); else LKWriteText(Surface, Buffer, Column5, HEADRAW , 0,WTMODE_NORMAL, WTALIGN_RIGHT, RGB_WHITE, false); } // landscape mode Surface.SelectObject(LK8InfoBigFont); // Text font for Nearest int *psortedindex; psortedindex=LKSortedAirspaces; for (i=0, j=0, drawn_items_onpage=0; i<AspNumraws; j++, i+=lincr) { iRaw=TopSize+(s_rawspace*i); short curraw=(curpage*AspNumraws); if (!ScreenLandscape && usetwolines) { curraw/=2; curraw+=j; } else { curraw+=i; } if (curraw>=MAXNEARAIRSPACES) break; rli=*(psortedindex+curraw); if (!ndr) { goto KeepOldValues; } if ( ValidAirspace(rli) ) { // // AIRSPACE NAME // wlen=_tcslen(LKAirspaces[rli].Name); if (!ScreenLandscape && usetwolines) { LK_tcsncpy(Buffer, LKAirspaces[rli].Name, 15); } else { if (wlen>s_maxnlname) { LK_tcsncpy(Buffer, LKAirspaces[rli].Name, s_maxnlname); } else { LK_tcsncpy(Buffer, LKAirspaces[rli].Name, wlen); } } CharUpper(Buffer); _tcscpy(Buffer1[i][curpage],Buffer); // // AIRSPACE TYPE // wlen=_tcslen(LKAirspaces[rli].Type); if (wlen>LKASP_TYPE_LEN) { LK_tcsncpy(Buffer, LKAirspaces[rli].Type, LKASP_TYPE_LEN); } else { LK_tcsncpy(Buffer, LKAirspaces[rli].Type, wlen); } CharUpper(Buffer); _tcscpy(Buffer2[i][curpage],Buffer); // // AIRSPACE DISTANCE // switch(LKAirspaces[rli].WarningLevel) { case awYellow: value=LKAirspaces[rli].Distance*DISTANCEMODIFY; if (!ScreenLandscape && usetwolines) _stprintf(Buffer3[i][curpage],TEXT("%0.1lf%s!"),value,Units::GetDistanceName()); else _stprintf(Buffer3[i][curpage],TEXT("%0.1lf!"),value); break; case awRed: _stprintf(Buffer3[i][curpage],TEXT("IN")); break; default: value=LKAirspaces[rli].Distance*DISTANCEMODIFY; if (!ScreenLandscape && usetwolines) _stprintf(Buffer3[i][curpage],TEXT("%0.1lf%s"),value,Units::GetDistanceName()); else _stprintf(Buffer3[i][curpage],TEXT("%0.1lf"),value); break; } // // AIRSPACE BEARING DIFFERENCE, OR BEARING IF CIRCLING // if (!MapWindow::mode.Is(MapWindow::Mode::MODE_CIRCLING)) { value = LKAirspaces[rli].Bearing - DrawInfo.TrackBearing; if (value < -180.0) value += 360.0; else if (value > 180.0) value -= 360.0; if (value > 1) _stprintf(Buffer4[i][curpage], TEXT("%2.0f%s%s"), value, gettext(_T("_@M2179_")), gettext(_T("_@M2183_"))); else if (value < -1) _stprintf(Buffer4[i][curpage], TEXT("%s%2.0f%s"), gettext(_T("_@M2182_")), -value, gettext(_T("_@M2179_"))); else _stprintf(Buffer4[i][curpage], TEXT("%s%s"), gettext(_T("_@M2182_")), gettext(_T("_@M2183_"))); } else _stprintf(Buffer4[i][curpage], TEXT("%2.0f%s"), LKAirspaces[rli].Bearing, gettext(_T("_@M2179_"))); // // AIRSPACE FLAGS // TCHAR aspflags[5]; _stprintf(aspflags,_T("%s%s%s%s"), LKAirspaces[rli].Selected ? _T("S") : _T(""), LKAirspaces[rli].Flyzone ? _T("F") : _T(" "), LKAirspaces[rli].Enabled ? _T("E") : _T("D"), s_trailspace); if (!ScreenLandscape && usetwolines) _stprintf(Buffer5[i][curpage], TEXT("*%s"), aspflags); else _stprintf(Buffer5[i][curpage], TEXT("%s"), aspflags); } else { _stprintf(Buffer1[i][curpage], _T("----------------------------")); // max 30 Buffer1[i][curpage][s_maxnlname+7]='\0'; // some more dashes _stprintf(Buffer2[i][curpage],_T("----")); _stprintf(Buffer3[i][curpage],_T("----")); _stprintf(Buffer4[i][curpage],_T("----")); _stprintf(Buffer5[i][curpage],_T(" ")); } KeepOldValues: if ( ValidAirspace(rli) ) { drawn_items_onpage++; switch(LKAirspaces[rli].WarningLevel) { case awYellow: rcolor=RGB_LIGHTYELLOW; Surface.SelectObject(LK8InfoBigItalicFont); break; case awRed: rcolor=RGB_LIGHTRED; Surface.SelectObject(LK8InfoBigItalicFont); break; case awNone: default: rcolor=RGB_WHITE; Surface.SelectObject(LK8InfoBigFont); break; } } else { rcolor=RGB_GREY; } if (ScreenLandscape || !usetwolines) { LKWriteText(Surface, Buffer1[i][curpage], Column1, iRaw , 0, WTMODE_NORMAL, WTALIGN_LEFT, rcolor, false); LKWriteText(Surface, Buffer2[i][curpage], Column2, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); LKWriteText(Surface, Buffer3[i][curpage], Column3, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); LKWriteText(Surface, Buffer4[i][curpage], Column4, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); LKWriteText(Surface, Buffer5[i][curpage], Column5, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); } else { LKWriteText(Surface, Buffer1[i][curpage], Column1, iRaw , 0, WTMODE_NORMAL, WTALIGN_LEFT, rcolor, false); LKWriteText(Surface, Buffer2[i][curpage], Column5, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); iRaw+=s_rawspace; unsigned int iCol=ScreenSizeX/3; LKWriteText(Surface, Buffer3[i][curpage], iCol, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); LKWriteText(Surface, Buffer4[i][curpage], iCol*2, iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); LKWriteText(Surface, Buffer5[i][curpage], right-IBLSCALE(2), iRaw , 0, WTMODE_NORMAL, WTALIGN_RIGHT, rcolor, false); } } if (LKevent==LKEVENT_NEWRUN || LKevent==LKEVENT_NEWPAGE ) { LKevent=LKEVENT_NONE; return; } if (drawn_items_onpage>0) { if (SelectedRaw[curmapspace] <0 || SelectedRaw[curmapspace]>(AspNumraws-1)) { return; } if (SelectedRaw[curmapspace] >= drawn_items_onpage) { if (LKevent==LKEVENT_DOWN) SelectedRaw[curmapspace]=0; else if (LKevent==LKEVENT_UP) SelectedRaw[curmapspace]=drawn_items_onpage-1; else { // DoStatusMessage(_T("Cant find valid raw")); not needed anymore SelectedRaw[curmapspace]=0; } } invsel.left=left; invsel.right=right; if (!ScreenLandscape && usetwolines) invsel.top=TopSize+(s_rawspace*SelectedRaw[curmapspace]*lincr); else invsel.top=TopSize+(s_rawspace*SelectedRaw[curmapspace])+NIBLSCALE(2); invsel.bottom=TopSize+(s_rawspace*(SelectedRaw[curmapspace]*lincr+1))-NIBLSCALE(1); if (!ScreenLandscape && usetwolines) invsel.bottom+=s_rawspace; Surface.InvertRect(invsel); } LKevent=LKEVENT_NONE; return; }
// // Called by LKDrawLook8000, this is what happens when we change mapspace mode, advancing through types. // We paint infopages, nearest, tri, etc.etc. // Normally there is plenty of cpu available because the map is not even calculated. // This is why we bring to the Draw thread, in the nearest pages case, also calculations. // void MapWindow::DrawMapSpace(LKSurface& Surface, const RECT& rc) { BrushReference hB; TextInBoxMode_t TextDisplayMode = {0}; TCHAR Buffer[LKSIZEBUFFERLARGE*2]; #ifdef DRAWLKSTATUS bool dodrawlkstatus=false; #endif #ifndef DITHER if (MapSpaceMode==MSM_WELCOME) { if (INVERTCOLORS) hB=LKBrush_Petrol; else hB=LKBrush_Mlight; } else { if (INVERTCOLORS) hB=LKBrush_Mdark; else hB=LKBrush_Mlight; } #else if (INVERTCOLORS) hB=LKBrush_Black; else hB=LKBrush_White; #endif const auto oldfont = Surface.SelectObject(LKINFOFONT); // save font if (MapSpaceMode==MSM_WELCOME) { LKBitmap WelcomeBitmap = LoadSplash(_T("LKPROFILE")); if(WelcomeBitmap) { DrawSplash(Surface, WelcomeBitmap); } } else { Surface.FillRect(&rc, hB); } // Paint borders in green, but only in nearest pages and welcome, and not in DITHER mode // In case we want it in dithered mode, some changes are ready to be used. #ifndef DITHER if (MapSpaceMode==MSM_WELCOME || (!IsMultiMap() && MapSpaceMode!=MSM_MAP) ) { #ifdef DITHER LKPen BorderPen(PEN_SOLID, ScreenThinSize, INVERTCOLORS?RGB_WHITE:RGB_BLACK); #else LKPen BorderPen(PEN_SOLID, ScreenThinSize, INVERTCOLORS?RGB_GREEN:RGB_DARKGREEN); #endif auto OldPen = Surface.SelectObject(BorderPen); auto OldBrush = Surface.SelectObject(LK_HOLLOW_BRUSH); Surface.Rectangle(rc.left, rc.top, rc.right, rc.bottom - BottomSize); Surface.SelectObject(OldPen); Surface.SelectObject(OldBrush); } #endif #ifdef DRAWLKSTATUS if (LKevent==LKEVENT_NEWRUN) dodrawlkstatus=true; #endif // We are entering mapspacemodes with no initial check on configured subpages. // Thus we need to ensure that the page is really available, or find the first valid. // However, this will prevent direct customkey access to pages! // Instead, we do it when we call next page from InfoPageChange // if (!ConfIP[ModeIndex][CURTYPE]) NextModeType(); switch (MapSpaceMode) { case MSM_WELCOME: #if 0 SetModeType(LKMODE_MAP,MP_MOVING); RefreshMap(); break; #endif #if (1) if (!DrawInfo.NAVWarning) { static double firsttime=DrawInfo.Time; // delayed automatic exit from welcome mode if ( DrawInfo.Time > (firsttime+3.0) ) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; LKSound(_T("LK_BEEP1.WAV")); RefreshMap(); break; } } #endif if(GlobalModelType==MODELTYPE_PNA_MINIMAP) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } DrawWelcome8000(Surface, rc); break; case MSM_MAPTRK: SetSideviewPage(IM_HEADING); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPWPT: #if 0 // If there is no destination, force jump to the map if (GetOvertargetIndex()<0) { SetModeType(LKMODE_MAP,MP_MOVING); LKevent=LKEVENT_NONE; break; } #endif SetSideviewPage(IM_NEXT_WP); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPASP: SetSideviewPage(IM_NEAR_AS); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPRADAR: LKDrawMultimap_Radar(Surface,rc); break; case MSM_VISUALGLIDE: SetSideviewPage(IM_VISUALGLIDE); LKDrawMultimap_Asp(Surface,rc); break; case MSM_MAPTEST: LKDrawMultimap_Test(Surface,rc); break; case MSM_LANDABLE: case MSM_NEARTPS: case MSM_AIRPORTS: case MSM_COMMON: case MSM_RECENT: case MSM_AIRSPACES: case MSM_THERMALS: case MSM_TRAFFIC: DrawNearest(Surface, rc); break; case MSM_MAP: break; case MSM_INFO_THERMAL: case MSM_INFO_CRUISE: case MSM_INFO_TASK: case MSM_INFO_AUX: case MSM_INFO_TRI: case MSM_INFO_HSI: case MSM_INFO_TRF: case MSM_INFO_TARGET: case MSM_INFO_CONTEST: DrawInfoPage(Surface,rc, false); break; default: memset((void*)&TextDisplayMode, 0, sizeof(TextDisplayMode)); TextDisplayMode.Color = RGB_WHITE; TextDisplayMode.NoSetFont = 1; TextDisplayMode.AlligneCenter = 1; Surface.SelectObject(LK8TargetFont); _stprintf(Buffer,TEXT("MapSpaceMode=%d"),MapSpaceMode); TextInBox(Surface, &rc, Buffer, (rc.right+rc.left)/2, NIBLSCALE(50) , &TextDisplayMode, false); break; } #ifdef DRAWLKSTATUS // no need to clear dodrawlkstatus, it is already reset at each run if (dodrawlkstatus) DrawLKStatus(hdc, rc); #endif Surface.SelectObject(oldfont); }
void RenderAirspaceTerrain(LKSurface& Surface, double PosLat, double PosLon, double brg, DiagrammStruct* psDiag) { RECT rc = psDiag->rc; //rc.bottom +=BORDER_Y; double range = psDiag->fXMax - psDiag->fXMin; // km double hmax = psDiag->fYMax; double lat, lon; int i, j; if (!IsDithered() && IsMultimapTerrain()) { RenderSky(Surface, rc, SKY_HORIZON_COL, SKY_SPACE_COL, GC_NO_COLOR_STEPS); } else { Surface.FillRect(&rc, MapWindow::hInvBackgroundBrush[BgMapColor]); } FindLatitudeLongitude(PosLat, PosLon, brg, psDiag->fXMin, &lat, &lon); POINT apTerrainPolygon[AIRSPACE_SCANSIZE_X + 4] = {}; double d_lat[AIRSPACE_SCANSIZE_X] = {}; double d_lon[AIRSPACE_SCANSIZE_X] = {}; double d_h[AIRSPACE_SCANSIZE_X] = {}; #define FRAMEWIDTH 2 RasterTerrain::Lock(); // want most accurate rounding here RasterTerrain::SetTerrainRounding(0, 0); double fj; for (j = 0; j < AIRSPACE_SCANSIZE_X; j++) { // scan range fj = (double) j * 1.0 / (double) (AIRSPACE_SCANSIZE_X - 1); FindLatitudeLongitude(lat, lon, brg, range*fj, &d_lat[j], &d_lon[j]); d_h[j] = RasterTerrain::GetTerrainHeight(d_lat[j], d_lon[j]); if (d_h[j] == TERRAIN_INVALID) d_h[j] = 0; //@ 101027 BUGFIX hmax = max(hmax, d_h[j]); } RasterTerrain::Unlock(); /******************************************************************************** * scan line ********************************************************************************/ if (IsMultimapAirspace()) Sideview_iNoHandeldSpaces = CAirspaceManager::Instance().ScanAirspaceLineList(d_lat, d_lon, d_h, Sideview_pHandeled, MAX_NO_SIDE_AS); // Sideview_pHandeled[GC_MAX_NO]; else Sideview_iNoHandeldSpaces = 0; #if BUGSTOP LKASSERT(Sideview_iNoHandeldSpaces < MAX_NO_SIDE_AS); #endif if (Sideview_iNoHandeldSpaces >= MAX_NO_SIDE_AS) Sideview_iNoHandeldSpaces = MAX_NO_SIDE_AS - 1; /******************************************************************************** * bubble sort to start with biggest airspaces ********************************************************************************/ int iSizeLookupTable[MAX_NO_SIDE_AS]; for (i = 0; i < Sideview_iNoHandeldSpaces; i++) iSizeLookupTable[i] = i; for (i = 0; i < Sideview_iNoHandeldSpaces; i++) { #if BUGSTOP LKASSERT(iSizeLookupTable[i] < MAX_NO_SIDE_AS); #endif for (j = i; j < Sideview_iNoHandeldSpaces; j++) { #if BUGSTOP LKASSERT(iSizeLookupTable[j] < MAX_NO_SIDE_AS); #endif if (iSizeLookupTable[i] >= MAX_NO_SIDE_AS) continue; if (iSizeLookupTable[j] >= MAX_NO_SIDE_AS) continue; if (Sideview_pHandeled[iSizeLookupTable[i]].iAreaSize < Sideview_pHandeled[iSizeLookupTable[j]].iAreaSize) { int iTmp = iSizeLookupTable[i]; iSizeLookupTable[i] = iSizeLookupTable[j]; iSizeLookupTable[j] = iTmp; } } } /********************************************************************************** * transform into diagram coordinates **********************************************************************************/ double dx1 = (double) (rc.right) / (double) (AIRSPACE_SCANSIZE_X - 1); int x0 = rc.left; LKASSERT(Sideview_iNoHandeldSpaces < MAX_NO_SIDE_AS); for (i = 0; i < Sideview_iNoHandeldSpaces; i++) { Sideview_pHandeled[i].rc.left = (long) ((Sideview_pHandeled[i].rc.left) * dx1) + x0 - FRAMEWIDTH / 2; Sideview_pHandeled[i].rc.right = (long) ((Sideview_pHandeled[i].rc.right) * dx1) + x0 + FRAMEWIDTH / 2; Sideview_pHandeled[i].rc.bottom = CalcHeightCoordinat((double) Sideview_pHandeled[i].rc.bottom, psDiag) + FRAMEWIDTH / 2; Sideview_pHandeled[i].rc.top = CalcHeightCoordinat((double) Sideview_pHandeled[i].rc.top, psDiag) - FRAMEWIDTH / 2; Sideview_pHandeled[i].iMaxBase = Sideview_pHandeled[i].rc.bottom; Sideview_pHandeled[i].iMinTop = Sideview_pHandeled[i].rc.top; int iN = Sideview_pHandeled[i].iNoPolyPts; #if BUGSTOP LKASSERT(iN < GC_MAX_POLYGON_PTS); #endif if (iN >= GC_MAX_POLYGON_PTS) iN = GC_MAX_POLYGON_PTS - 1; if (Sideview_pHandeled[i].bRectAllowed == false) { for (j = 0; j < iN; j++) { Sideview_pHandeled[i].apPolygon[j].x = (long) (((Sideview_pHandeled[i].apPolygon[j].x) * dx1) + x0); Sideview_pHandeled[i].apPolygon[j].y = CalcHeightCoordinat((double) Sideview_pHandeled[i].apPolygon[j].y, psDiag); if (j != iN - 1) { if ((j < iN / 2)) { Sideview_pHandeled[i].iMaxBase = min((long) Sideview_pHandeled[i].iMaxBase, (long) Sideview_pHandeled[i].apPolygon[j].y); } else { Sideview_pHandeled[i].iMinTop = max((long) Sideview_pHandeled[i].iMinTop, (long) Sideview_pHandeled[i].apPolygon[j].y); } } } } } /********************************************************************************** * draw airspaces **********************************************************************************/ const auto oldpen = Surface.SelectObject(LK_NULL_PEN); _TCHAR text [80]; LKASSERT(Sideview_iNoHandeldSpaces < MAX_NO_SIDE_AS); for (int m = 0; m < Sideview_iNoHandeldSpaces; m++) { int iSizeIdx = iSizeLookupTable[m]; #if BUGSTOP LKASSERT(iSizeIdx < MAX_NO_SIDE_AS && iSizeIdx >= 0); #endif if (iSizeIdx >= MAX_NO_SIDE_AS) iSizeIdx = MAX_NO_SIDE_AS - 1; int type = Sideview_pHandeled[iSizeIdx].iType; RECT rcd = Sideview_pHandeled[iSizeIdx].rc; LKColor FrameColor; double fFrameColFact; if (Sideview_pHandeled[iSizeIdx].bEnabled) { Surface.SelectObject(MapWindow::GetAirspaceBrushByClass(type)); Surface.SetTextColor(MapWindow::GetAirspaceColourByClass(type)); fFrameColFact = 0.8; FrameColor = MapWindow::GetAirspaceColourByClass(type); } else { Surface.SelectObject(LKBrush_Hollow); Surface.SetTextColor(RGB_GGREY); FrameColor = RGB_GGREY; fFrameColFact = 1.2; } if (INVERTCOLORS) fFrameColFact *= 0.8; else fFrameColFact *= 1.2; LKColor Color = FrameColor.ChangeBrightness(fFrameColFact); LKPen mpen2(PEN_SOLID, FRAMEWIDTH, Color); const auto oldpen2 = Surface.SelectObject(mpen2); if (Sideview_pHandeled[iSizeIdx].bRectAllowed == true) Surface.Rectangle(rcd.left + 1, rcd.top, rcd.right, rcd.bottom); else Surface.Polygon(Sideview_pHandeled[iSizeIdx].apPolygon, Sideview_pHandeled[iSizeIdx].iNoPolyPts); Surface.SelectObject(oldpen2); if (Sideview_pHandeled[iSizeIdx].bEnabled) Surface.SetTextColor(Sideview_TextColor); // RGB_MENUTITLEFG else Surface.SetTextColor(RGB_GGREY); /*********************************************** * build view overlap for centering text ***********************************************/ rcd.bottom = min(rcd.bottom, Sideview_pHandeled[iSizeIdx].iMaxBase); rcd.top = max(rcd.top, Sideview_pHandeled[iSizeIdx].iMinTop); rcd.left = max(rcd.left, rc.left); rcd.right = min(rcd.right, rc.right); rcd.bottom = min(rcd.bottom, rc.bottom); rcd.top = max(rcd.top, rc.top); SIZE textsize; SIZE aispacesize = {rcd.right - rcd.left, rcd.bottom - rcd.top}; LK_tcsncpy(text, Sideview_pHandeled[iSizeIdx].szAS_Name, NAME_SIZE - 1/* sizeof(text)/sizeof(text[0])*/); Surface.GetTextSize(text, &textsize); int x = rcd.left + aispacesize.cx / 2; ; int y = rcd.top + aispacesize.cy / 2; // int iTextheight = tsize.cy; int iOffset = 0; BOOL blongtext = false; if (aispacesize.cy > (2 * textsize.cy) && (textsize.cx < aispacesize.cx)) { iOffset = textsize.cy / 2; } if ((textsize.cx < aispacesize.cx) && (textsize.cy < aispacesize.cy)) { Surface.DrawText(x - textsize.cx / 2, y - iOffset - textsize.cy / 2, text); blongtext = true; } LK_tcsncpy(text, CAirspaceManager::Instance().GetAirspaceTypeShortText(Sideview_pHandeled[iSizeIdx].iType), NAME_SIZE); Surface.GetTextSize(text, &textsize); if (textsize.cx < aispacesize.cx) { if (2 * textsize.cy < aispacesize.cy) { Surface.DrawText(x - textsize.cx / 2, y + iOffset - textsize.cy / 2, text); } else { if ((textsize.cy < aispacesize.cy) && (!blongtext)) Surface.DrawText(x - textsize.cx / 2, y - iOffset - textsize.cy / 2, text); } } } Surface.SelectObject(oldpen); /********************************************************************************** * draw airspace frames in reversed order **********************************************************************************/ #ifdef OUTLINE_2ND for (int m = 0; m < Sideview_iNoHandeldSpaces; m++) { int iSizeIdx = iSizeLookupTable[Sideview_iNoHandeldSpaces - m - 1]; if (Sideview_pHandeled[iSizeIdx].bEnabled) { #if BUGSTOP LKASSERT(iSizeIdx < MAX_NO_SIDE_AS); #endif if (iSizeIdx >= MAX_NO_SIDE_AS) iSizeIdx = MAX_NO_SIDE_AS - 1; int type = Sideview_pHandeled[iSizeIdx].iType; RECT rcd = Sideview_pHandeled[iSizeIdx].rc; LKColor FrameColor = MapWindow::GetAirspaceColourByClass(type); double fFrameColFact; Surface.SelectObject(LKBrush_Hollow); if (Sideview_pHandeled[iSizeIdx].bEnabled) { // Surface.SelectObject(MapWindow::GetAirspaceBrushByClass(type)); Surface.SetTextColor(MapWindow::GetAirspaceColourByClass(type)); fFrameColFact = 0.8; } else { Surface.SetTextColor(RGB_GGREY); FrameColor = RGB_GGREY; fFrameColFact = 1.2; } if (INVERTCOLORS) fFrameColFact *= 0.8; else fFrameColFact *= 1.2; LKColor lColor = FrameColor.ChangeBrightness(fFrameColFact); LKPen mpen2(PEN_SOLID, FRAMEWIDTH, lColor); const auto oldpen2 = Surface.SelectObject(mpen2); if (Sideview_pHandeled[iSizeIdx].bRectAllowed == true) Surface.Rectangle(rcd.left + 1, rcd.top, rcd.right, rcd.bottom); else Surface.Polygon(Sideview_pHandeled[iSizeIdx].apPolygon, Sideview_pHandeled[iSizeIdx].iNoPolyPts); Surface.SelectObject(oldpen2); } } #endif /************************************************************* * draw ground *************************************************************/ // draw ground /********************************************************************* * draw terrain *********************************************************************/ LKPen hpHorizonGround(PEN_SOLID, IBLSCALE(1) + 1, LKColor(126, 62, 50)); LKBrush hbHorizonGround(GROUND_COLOUR); const auto oldPen = Surface.SelectObject(hpHorizonGround); const auto oldBrush = Surface.SelectObject(hbHorizonGround); for (j = 0; j < AIRSPACE_SCANSIZE_X; j++) { // scan range apTerrainPolygon[j].x = iround(j * dx1) + x0; apTerrainPolygon[j].y = CalcHeightCoordinat(d_h[j], psDiag); } apTerrainPolygon[AIRSPACE_SCANSIZE_X].x = iround(AIRSPACE_SCANSIZE_X * dx1) + x0; ; // x0; apTerrainPolygon[AIRSPACE_SCANSIZE_X].y = CalcHeightCoordinat(0, psDiag); //iBottom; apTerrainPolygon[AIRSPACE_SCANSIZE_X + 1].x = iround(0 * dx1) + x0; //iround(j*dx1)+x0; apTerrainPolygon[AIRSPACE_SCANSIZE_X + 1].y = CalcHeightCoordinat(0, psDiag); //iBottom; apTerrainPolygon[AIRSPACE_SCANSIZE_X + 2] = apTerrainPolygon[0]; static_assert(array_size(apTerrainPolygon) >= AIRSPACE_SCANSIZE_X + 3, "wrong array size"); Surface.Polygon(apTerrainPolygon, AIRSPACE_SCANSIZE_X + 3); Surface.SelectObject(oldPen); Surface.SelectObject(oldBrush); /********************************************************************* * draw sea *********************************************************************/ #ifdef MSL_SEA_DRAW // draw sea if (psDiag->fYMin < GC_SEA_LEVEL_TOLERANCE) { RECT sea = {rc.left, rc.bottom, rc.right, rc.bottom + SV_BORDER_Y}; #ifndef UNDITHER RenderSky(Surface, sea, RGB_STEEL_BLUE, RGB_ROYAL_BLUE, 7); #else RenderSky(Surface, sea, RGB_BLACK, RGB_BLACK, 2); #endif } #else if (psDiag->fYMin < GC_SEA_LEVEL_TOLERANCE) Rectangle(hdc, rc.left, rc.bottom, rc.right, rc.bottom + BORDER_Y); #endif Surface.SetTextColor(Sideview_TextColor); // RGB_MENUTITLEFG }