예제 #1
0
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);
        }
    }
}
예제 #2
0
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);
   
}
예제 #3
0
파일: TopView.cpp 프로젝트: brunotl/LK8000
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;

}
예제 #4
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;
}
예제 #5
0
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

}
예제 #6
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);
}
예제 #7
0
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;
}
예제 #8
0
//
// 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);
}
예제 #9
0
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
}