PixelRect GetButtonPosition(unsigned MenuID, const PixelRect& rcScreen) { PixelRect rc = rcScreen; rc.Grow(-1); // remove Margin unsigned i = MenuID - 1; assert(i < MenuButtons.size()); const PixelScalar row = ScreenLandscape ? LandscapeLayout[i].row : PortraitLayout[i].row; const PixelScalar col = ScreenLandscape ? LandscapeLayout[i].col :PortraitLayout[i].col; const PixelScalar nbRow = ScreenLandscape ? 5 : 7; const PixelScalar nbCol = ScreenLandscape ? 5 : 4; const PixelSize size = { std::min<PixelScalar>((rc.GetSize().cx-(nbCol-1))/nbCol, NIBLSCALE(80)), std::min<PixelScalar>((rc.GetSize().cy-nbRow-1)/nbRow, NIBLSCALE(40)) }; const double x_interval = (rc.GetSize().cx - size.cx * nbCol) / (nbCol-1); const double y_interval = (rc.GetSize().cy - size.cy * nbRow) / (nbRow-1); const RasterPoint origin = { rc.left + (PixelScalar)(col * (size.cx + x_interval)), rc.top + (PixelScalar)(row * (size.cy + y_interval)) }; return PixelRect(origin, size); }
void WidgetDialog::AutoSize() { const PixelRect parent_rc = GetParentClientRect(); const PixelSize parent_size = parent_rc.GetSize(); widget.Prepare(); PixelSize min_size = widget.Get()->GetMinimumSize(); min_size.cy += GetTitleHeight(); PixelSize max_size = widget.Get()->GetMaximumSize(); max_size.cy += GetTitleHeight(); const PixelScalar min_height_with_buttons = min_size.cy + Layout::GetMaximumControlHeight(); const PixelScalar max_height_with_buttons = max_size.cy + Layout::GetMaximumControlHeight(); if (/* need full dialog height even for minimum widget height? */ min_height_with_buttons >= parent_size.cy || /* try to avoid putting buttons left on portrait screens; try to comply with maximum widget height only on landscape screens */ (parent_size.cx > parent_size.cy && max_height_with_buttons >= parent_size.cy)) { /* need full height, buttons must be left */ PixelRect rc = parent_rc; if (max_size.cy < parent_size.cy) rc.bottom = rc.top + max_size.cy; PixelRect remaining = buttons.LeftLayout(rc); PixelSize remaining_size = remaining.GetSize(); if (remaining_size.cx > max_size.cx) rc.right -= remaining_size.cx - max_size.cx; Move(rc); widget.Move(buttons.LeftLayout()); return; } /* see if buttons fit at the bottom */ PixelRect rc = parent_rc; if (max_size.cx < parent_size.cx) rc.right = rc.left + max_size.cx; PixelRect remaining = buttons.BottomLayout(rc); PixelSize remaining_size = remaining.GetSize(); if (remaining_size.cy > max_size.cy) rc.bottom -= remaining_size.cy - max_size.cy; Move(rc); widget.Move(buttons.BottomLayout()); }
void KeyboardWidget::PrepareSize(const PixelRect &rc) { const PixelSize new_size = rc.GetSize(); button_width = new_size.cx / 10; button_height = new_size.cy / 5; }
void Window::Create(ContainerWindow *parent, PixelRect rc, const WindowStyle window_style) { assert(IsScreenInitialized()); assert(rc.left <= rc.right); assert(rc.right - rc.left < 0x8000); assert(rc.top <= rc.bottom); assert(rc.bottom - rc.top < 0x8000); double_clicks = window_style.double_clicks; this->parent = parent; position = rc.GetOrigin(); size = rc.GetSize(); tab_stop = window_style.tab_stop; control_parent = window_style.control_parent; visible = window_style.visible; enabled = window_style.enabled; has_border = window_style.has_border; text_style = window_style.text_style; if (parent != NULL) parent->AddChild(*this); OnCreate(); OnResize(size); }
static void Draw(Canvas &canvas) { PixelRect rc = canvas.GetRect(); rc.Grow(-0.2 * rc.GetSize().cx); /* draw the banner text with a large font */ Font small_font; small_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed.ttf", (rc.GetSize().cy / 25)); canvas.Select(small_font); canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundTransparent(); const TCHAR *const text = _T("Powered Off"); const PixelSize text_size = canvas.CalcTextSize(text); const RasterPoint text_pos = { rc.left + 16, rc.bottom - 16 - text_size.cy }; canvas.DrawText(text_pos.x, text_pos.y, text); Font big_font; big_font.LoadFile("/opt/LK8000/share/fonts/DejaVuSansCondensed-Bold.ttf", (rc.GetSize().cy / 10)); canvas.Select(big_font); const TCHAR *const text2 = _T("LK8000"); const PixelSize text2_size = canvas.CalcTextSize(text2); const RasterPoint text2_pos = { (rc.left + rc.GetSize().cx + text2_size.cx) / 2, (rc.top + (rc.GetSize().cy / 10)) }; canvas.DrawText(text2_pos.x, text2_pos.y, text2); const double Scale = (double)rc.GetSize().cx / (double)bird_size.cx; RasterPoint polygon[array_size(bird_polygon)] = {}; std::transform(std::begin(bird_polygon), std::end(bird_polygon), std::begin(polygon), [Scale, rc, text2_size, text2_pos]( const RasterPoint& pt ) { return RasterPoint(pt.x*Scale + rc.left, pt.y*Scale + text2_pos.y + text2_size.cy); }); canvas.SelectBlackBrush(); canvas.DrawPolygon(polygon, array_size(polygon)); }
void KeyboardWidget::OnResize(const PixelRect &rc) { const PixelSize new_size = rc.GetSize(); button_width = new_size.cx / 10; button_height = new_size.cy / 5; ResizeButtons(); MoveButtons(rc); }
InfoBoxLayout::Layout InfoBoxLayout::Calculate(PixelRect rc, InfoBoxSettings::Geometry geometry) { const PixelSize screen_size = rc.GetSize(); geometry = ValidateGeometry(geometry, screen_size); Layout layout; layout.geometry = geometry; layout.landscape = screen_size.cx > screen_size.cy; layout.count = geometry_counts[(unsigned)geometry]; assert(layout.count <= InfoBoxSettings::Panel::MAX_CONTENTS); CalcInfoBoxSizes(layout, screen_size, geometry); layout.ClearVario(); unsigned right = rc.right; switch (geometry) { case InfoBoxSettings::Geometry::SPLIT_8: case InfoBoxSettings::Geometry::OBSOLETE_SPLIT_8: if (layout.landscape) { rc.left = MakeLeftColumn(layout, layout.positions, 4, rc.left, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions + 4, 4, rc.right, rc.top, rc.bottom); } else { rc.top = MakeTopRow(layout, layout.positions, 4, rc.left, rc.right, rc.top); rc.bottom = MakeBottomRow(layout, layout.positions + 4, 4, rc.left, rc.right, rc.bottom); } break; case InfoBoxSettings::Geometry::BOTTOM_8_VARIO: layout.vario.left = rc.right - layout.control_size.cx; layout.vario.right = rc.right; layout.vario.top = rc.bottom - layout.control_size.cy * 2; layout.vario.bottom = rc.bottom; right = layout.vario.left; /* fall through */ case InfoBoxSettings::Geometry::BOTTOM_RIGHT_8: case InfoBoxSettings::Geometry::OBSOLETE_BOTTOM_RIGHT_8: if (layout.landscape) { rc.right = MakeRightColumn(layout, layout.positions + 4, 4, rc.right, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions, 4, rc.right, rc.top, rc.bottom); } else { rc.bottom = MakeBottomRow(layout, layout.positions + 4, 4, rc.left, right, rc.bottom); rc.bottom = MakeBottomRow(layout, layout.positions, 4, rc.left, right, rc.bottom); } break; case InfoBoxSettings::Geometry::TOP_8_VARIO: layout.vario.left = rc.right - layout.control_size.cx; layout.vario.right = rc.right; layout.vario.top = rc.top; layout.vario.bottom = rc.top + layout.control_size.cy * 2; right = layout.vario.left; /* fall through */ case InfoBoxSettings::Geometry::TOP_LEFT_8: case InfoBoxSettings::Geometry::OBSOLETE_TOP_LEFT_8: if (layout.landscape) { rc.left = MakeLeftColumn(layout, layout.positions, 4, rc.left, rc.top, rc.bottom); rc.left = MakeLeftColumn(layout, layout.positions + 4, 4, rc.left, rc.top, rc.bottom); } else { rc.top = MakeTopRow(layout, layout.positions, 4, rc.left, right, rc.top); rc.top = MakeTopRow(layout, layout.positions + 4, 4, rc.left, right, rc.top); } break; case InfoBoxSettings::Geometry::LEFT_6_RIGHT_3_VARIO: layout.vario.left = rc.right - layout.control_size.cx; layout.vario.right = rc.right; layout.vario.top = 0; layout.vario.bottom = layout.vario.top + layout.control_size.cy * 3; rc.left = MakeLeftColumn(layout, layout.positions, 6, rc.left, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions + 6, 3, rc.right, rc.top + 3 * layout.control_size.cy, rc.bottom); break; case InfoBoxSettings::Geometry::LEFT_12_RIGHT_3_VARIO: layout.vario.left = rc.right - layout.control_size.cx; layout.vario.right = rc.right; layout.vario.top = 0; layout.vario.bottom = layout.vario.top + layout.control_size.cy * 3; rc.right = MakeRightColumn(layout, layout.positions + 6, 3, rc.right, rc.top + 3 * layout.control_size.cy, rc.bottom); layout.control_size.cx = layout.control_size.cy * 1.1; rc.left = MakeLeftColumn(layout, layout.positions, 6, rc.left, rc.top, rc.bottom); rc.left = MakeLeftColumn(layout, layout.positions + 9, 6, rc.left, rc.top, rc.bottom); break; case InfoBoxSettings::Geometry::BOTTOM_RIGHT_12: case InfoBoxSettings::Geometry::OBSOLETE_BOTTOM_RIGHT_12: if (layout.landscape) { rc.right = MakeRightColumn(layout, layout.positions + 6, 6, rc.right, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions, 6, rc.right, rc.top, rc.bottom); } else { rc.bottom = MakeBottomRow(layout, layout.positions + 6, 6, rc.left, rc.right, rc.bottom); rc.bottom = MakeBottomRow(layout, layout.positions, 6, rc.left, rc.right, rc.bottom); } break; case InfoBoxSettings::Geometry::TOP_LEFT_12: if (layout.landscape) { rc.left = MakeLeftColumn(layout, layout.positions, 6, rc.left, rc.top, rc.bottom); rc.left = MakeLeftColumn(layout, layout.positions + 6, 6, rc.left, rc.top, rc.bottom); } else { rc.top = MakeTopRow(layout, layout.positions, 6, rc.left, rc.right, rc.top); rc.top = MakeTopRow(layout, layout.positions + 6, 6, rc.left, rc.right, rc.top); } break; case InfoBoxSettings::Geometry::RIGHT_16: rc.right = MakeRightColumn(layout, layout.positions + 8, 8, rc.right, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions, 8, rc.right, rc.top, rc.bottom); break; case InfoBoxSettings::Geometry::RIGHT_24: rc.right = MakeRightColumn(layout, layout.positions + 16, 8, rc.right, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions + 8, 8, rc.right, rc.top, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions, 8, rc.right, rc.top, rc.bottom); break; case InfoBoxSettings::Geometry::RIGHT_9_VARIO: layout.vario.left = rc.right - layout.control_size.cx; layout.vario.right = rc.right; layout.vario.top = 0; layout.vario.bottom = layout.vario.top + layout.control_size.cy * 3; rc.right = MakeRightColumn(layout, layout.positions + 6, 3, rc.right, rc.top + 3 * layout.control_size.cy, rc.bottom); rc.right = MakeRightColumn(layout, layout.positions, 6, rc.right, rc.top, rc.bottom); break; case InfoBoxSettings::Geometry::RIGHT_5: rc.right = MakeRightColumn(layout, layout.positions, 5, rc.right, rc.top, rc.bottom); break; case InfoBoxSettings::Geometry::TOP_LEFT_4: case InfoBoxSettings::Geometry::OBSOLETE_TOP_LEFT_4: if (layout.landscape) rc.left = MakeLeftColumn(layout, layout.positions, 4, rc.left, rc.top, rc.bottom); else rc.top = MakeTopRow(layout, layout.positions, 4, rc.left, rc.right, rc.top); break; case InfoBoxSettings::Geometry::BOTTOM_RIGHT_4: case InfoBoxSettings::Geometry::OBSOLETE_BOTTOM_RIGHT_4: if (layout.landscape) rc.right = MakeRightColumn(layout, layout.positions, 4, rc.right, rc.top, rc.bottom); else rc.bottom = MakeBottomRow(layout, layout.positions, 4, rc.left, rc.right, rc.bottom); break; }; layout.remaining = rc; return layout; }
static void OnTaskPaintListItem(WindowControl * Sender, LKSurface& Surface){ int n = UpLimit - LowLimit; TCHAR sTmp[120]; TCHAR wpName[120]; TCHAR landableStr[5] = TEXT(" [X]"); // LKTOKEN _@M1238_ "L" landableStr[2] = MsgToken(1238)[0]; LockTaskData(); const PixelRect rcClient(Sender->GetClientRect()); const int w0 = rcClient.GetSize().cx - DLGSCALE(1); const int w1 = Surface.GetTextWidth(TEXT(" 000km")); _stprintf(sTmp, _T(" 000%s"), MsgToken(2179)); const int w2 = Surface.GetTextWidth(sTmp); const int TextMargin = (rcClient.GetSize().cy - Surface.GetTextHeight(TEXT("A"))) / 2; const int p1 = w0-w1-w2- rcClient.GetSize().cy - DLGSCALE(2); const int p2 = w0-w2- rcClient.GetSize().cy - DLGSCALE(2); const PixelRect rc = { 0, 0, rcClient.GetSize().cy, rcClient.GetSize().cy }; if (DrawListIndex < n){ int i = LowLimit + DrawListIndex; // if ((WayPointList[Task[i].Index].Flags & LANDPOINT) >0) // MapWindow::DrawRunway(hDC, &WayPointList[Task[i].Index], rc, 3000,true); MapWindow::DrawTaskPicto(Surface, DrawListIndex, rc, 2500); if (Task[i].Index>=0) { _stprintf(wpName, TEXT("%s%s"), WayPointList[Task[i].Index].Name, (WayPointList[Task[i].Index].Flags & LANDPOINT) ? landableStr : TEXT("")); if (AATEnabled && ValidTaskPoint(i+1) && (i>0)) { if (Task[i].AATType==0 || Task[i].AATType==3) { _stprintf(sTmp, TEXT("%s %.1f"), wpName, Task[i].AATCircleRadius*DISTANCEMODIFY); } else { if(Task[i].AATType==2 && DoOptimizeRoute()) { _stprintf(sTmp, TEXT("%s %.1f/1"), wpName, Task[i].PGConeSlope); } else { _stprintf(sTmp, TEXT("%s %.1f"), wpName, Task[i].AATSectorRadius*DISTANCEMODIFY); } } } else { _stprintf(sTmp, TEXT("%s"), wpName); } Surface.SetBackgroundTransparent(); Surface.SetTextColor(RGB_BLACK); Surface.DrawTextClip(rc.right + DLGSCALE(2), TextMargin, sTmp, p1-DLGSCALE(4)); _stprintf(sTmp, TEXT("%.0f %s"),Task[i].Leg*DISTANCEMODIFY,Units::GetDistanceName()); Surface.DrawText(rc.right+p1+w1-Surface.GetTextWidth(sTmp), TextMargin, sTmp); _stprintf(sTmp, TEXT("%d%s"), iround(Task[i].InBound),MsgToken(2179)); Surface.DrawText(rc.right +p2+w2-Surface.GetTextWidth(sTmp), TextMargin, sTmp); } } else { Surface.SetTextColor(RGB_BLACK); // if (DrawListIndex==n) { // patchout 091126 if (DrawListIndex==n && UpLimit < MAXTASKPOINTS) { // patch 091126 // LKTOKEN _@M832_ = "add waypoint" _stprintf(sTmp, TEXT(" (%s)"), MsgToken(832)); Surface.DrawText(rc.right +DLGSCALE(2), TextMargin, sTmp); } else if ((DrawListIndex==n+1) && ValidTaskPoint(0)) { if (!AATEnabled || ISPARAGLIDER) { // LKTOKEN _@M735_ = "Total:" Surface.DrawText(rc.right +DLGSCALE(2), TextMargin, MsgToken(735)); _stprintf(sTmp, TEXT("%.0f %s%s"), lengthtotal*DISTANCEMODIFY, Units::GetDistanceName(), fai_ok?_T(" FAI"):_T("")); Surface.DrawText(rc.right +p1+w1-Surface.GetTextWidth(sTmp), TextMargin, sTmp); } else { double d1 = CALCULATED_INFO.TaskDistanceToGo; if ((CALCULATED_INFO.TaskStartTime>0.0) && (CALCULATED_INFO.Flying) && (ActiveTaskPoint>0)) { d1 += CALCULATED_INFO.TaskDistanceCovered; } if (d1==0.0) { d1 = CALCULATED_INFO.AATTargetDistance; } _stprintf(sTmp, TEXT("%s %.0f min %.0f (%.0f) %s"), // LKTOKEN _@M735_ = "Total:" MsgToken(735), AATTaskLength*1.0, DISTANCEMODIFY*lengthtotal, DISTANCEMODIFY*d1, Units::GetDistanceName()); Surface.DrawText(rc.right +DLGSCALE(2), TextMargin, sTmp); } } } UnlockTaskData(); }
// // FUNCTION: InitInstance() // // PURPOSE: creates main window // // COMMENTS: // // In this function, we create and display the main program window. // BOOL InitInstance() { extern bool CommandResolution; if(!IsEmbedded() && !CommandResolution) { ScreenSizeX = 800; ScreenSizeY = 480; } #if defined(ENABLE_SDL) && defined(USE_FULLSCREEN) #if (SDL_MAJOR_VERSION >= 2) SDL_DisplayMode mode = {}; if(SDL_GetCurrentDisplayMode(0, &mode) == 0) { ScreenSizeX = mode.w; ScreenSizeY = mode.h; } else { fprintf(stderr, "SDL_GetCurrentDisplayMode() has failed: %s\n", ::SDL_GetError()); } #else ScreenSizeX = 0; ScreenSizeY = 0; #endif #endif PreloadInitialisation(true); RECT WindowSize; #ifdef __linux__ WindowSize=WindowResize(ScreenSizeX, ScreenSizeY); #endif #ifdef WIN32 #ifdef UNDER_CE WindowSize=WindowResize( GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); #else WindowSize=WindowResize(ScreenSizeX, ScreenSizeY); #endif #endif if (!goInstallSystem) Poco::Thread::sleep(50); // 091119 #if TESTBENCH StartupStore(TEXT(". Create main window%s"),NEWLINE); #endif if(!MainWindow.Create(WindowSize)) { StartupStore(TEXT(". FAILURE: Create main window%s"),NEWLINE); return FALSE; } const PixelRect rc(MainWindow.GetClientRect()); ScreenSizeX = rc.GetSize().cx; ScreenSizeY = rc.GetSize().cy; InitLKScreen(); InitLKFonts(); // causing problems with CreateButtonLabels? LKLoadFixedBitmaps(); LKLoadProfileBitmaps(); LKObjects_Create(); ButtonLabel::CreateButtonLabels(rc); ButtonLabel::SetLabelText(0,TEXT("MODE")); extern void InitLKFonts(); // reload updating LK fonts after loading profile for fontquality InitLKFonts(); ButtonLabel::SetFont(MapWindowBoldFont); Message::Initialize(rc); // creates window, sets fonts MainWindow.SetVisible(true); return TRUE; }
// // FUNCTION: InitInstance() // // PURPOSE: creates main window // // COMMENTS: // // In this function, we create and display the main program window. // BOOL InitInstance() { extern bool CommandResolution; if(!IsEmbedded() && !CommandResolution) { ScreenSizeX = 800; ScreenSizeY = 480; } #if defined(ENABLE_SDL) && defined(USE_FULLSCREEN) #if (SDL_MAJOR_VERSION >= 2) SDL_DisplayMode mode = {}; if(SDL_GetCurrentDisplayMode(0, &mode) == 0) { ScreenSizeX = mode.w; ScreenSizeY = mode.h; } else { fprintf(stderr, "SDL_GetCurrentDisplayMode() has failed: %s\n", ::SDL_GetError()); } #else ScreenSizeX = 0; ScreenSizeY = 0; #endif #endif PreloadInitialisation(true); RECT WindowSize; #ifdef __linux__ #ifdef USE_VIDEOCORE uint32_t iWidth, iHeight; if(graphics_get_display_size(0, &iWidth, &iHeight) >= 0) { ScreenSizeX=iWidth; ScreenSizeY=iHeight; } #endif #ifdef ANDROID const PixelSize Size = native_view->GetSize(); ScreenSizeX=Size.cx; ScreenSizeY=Size.cy; #endif WindowSize=WindowResize(ScreenSizeX, ScreenSizeY); #endif #ifdef WIN32 #if defined(UNDER_CE) || defined(USE_FULLSCREEN) WindowSize=WindowResize( GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); #else WindowSize=WindowResize(ScreenSizeX, ScreenSizeY); #endif #endif #if TESTBENCH StartupStore(TEXT(". Create main window%s"),NEWLINE); #endif if(!MainWindow.Create(WindowSize)) { StartupStore(TEXT(". FAILURE: Create main window%s"),NEWLINE); return FALSE; } const PixelRect rc(MainWindow.GetClientRect()); ScreenSizeX = rc.GetSize().cx; ScreenSizeY = rc.GetSize().cy; ScreenHasChanged(); InitLKScreen(); InitLKFonts(); // causing problems with CreateButtonLabels? LKLoadFixedBitmaps(); LKLoadProfileBitmaps(); LKObjects_Create(); ButtonLabel::CreateButtonLabels(rc); ButtonLabel::SetFont(MapWindowBoldFont); Message::Initialize(rc); // creates window, sets fonts MainWindow.SetVisible(true); return TRUE; }
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); }