2020-04-27 11:27:59 -04:00
// MIT License
// Copyright (c) 2020 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2020-05-29 13:39:30 -04:00
// ImPlot v0.3 WIP
2020-05-11 07:12:22 -04:00
/*
API BREAKING CHANGES
= = = = = = = = = = = = = = = = = = = =
Occasionally introducing changes that are breaking the API . We try to make the breakage minor and easy to fix .
Below is a change - log of API breaking changes only . If you are using one of the functions listed , expect to have to fix some code .
When you are not sure about a old symbol or function name , try using the Search / Find function of your IDE to look for comments or references in all implot files .
You can read releases logs https : //github.com/epezent/implot/releases for more details.
2020-06-04 10:56:50 -04:00
- 2020 / 06 / 03 ( 0.3 ) - The signature and behavior of PlotPieChart was changed so that data with sum less than 1 can optionally be normalized . The label format can now be specified as well .
2020-06-02 13:34:14 -04:00
- 2020 / 06 / 01 ( 0.3 ) - SetPalette was changed to ` SetColormap ` for consistency with other plotting libraries . ` RestorePalette ` was removed . Use ` SetColormap ( ImPlotColormap_Default ) ` .
2020-05-31 10:07:24 -04:00
- 2020 / 05 / 31 ( 0.3 ) - Plot functions taking custom ImVec2 * getters were removed . Use the ImPlotPoint * getter versions instead .
2020-05-29 13:39:30 -04:00
- 2020 / 05 / 29 ( 0.3 ) - The signature of ImPlotLimits : : Contains was changed to take two doubles instead of ImVec2
2020-05-16 09:39:43 -04:00
- 2020 / 05 / 16 ( 0.2 ) - All plotting functions were reverted to being prefixed with " Plot " to maintain a consistent VerbNoun style . ` Plot ` was split into ` PlotLine `
2020-05-16 10:14:48 -04:00
and ` PlotScatter ` ( however , ` PlotLine ` can still be used to plot scatter points as ` Plot ` did before . ) . ` Bar ` is not ` PlotBars ` , to indicate
that multiple bars will be plotted .
2020-05-16 09:39:43 -04:00
- 2020 / 05 / 13 ( 0.2 ) - ` ImMarker ` was change to ` ImPlotMarker ` and ` ImAxisFlags ` was changed to ` ImPlotAxisFlags ` .
- 2020 / 05 / 11 ( 0.2 ) - ` ImPlotFlags_Selection ` was changed to ` ImPlotFlags_BoxSelect `
2020-05-12 05:19:04 -04:00
- 2020 / 05 / 11 ( 0.2 ) - The namespace ImGui : : was replaced with ImPlot : : . As a result , the following additional changes were made :
2020-05-16 10:14:48 -04:00
- Functions that were prefixed or decorated with the word " Plot " have been truncated . E . g . , ` ImGui : : PlotBars ` is now just ` ImPlot : : Bar ` .
2020-05-12 05:19:04 -04:00
It should be fairly obvious what was what .
2020-05-13 10:11:25 -04:00
- Some functions have been given names that would have otherwise collided with the ImGui namespace . This has been done to maintain a consistent
style with ImGui . E . g . , ' ImGui : : PushPlotStyleVar ` is now ' ImPlot : : PushStyleVar ' .
2020-05-11 07:12:22 -04:00
- 2020 / 05 / 10 ( 0.2 ) - The following function / struct names were changes :
- ImPlotRange - > ImPlotLimits
- GetPlotRange ( ) - > GetPlotLimits ( )
2020-05-13 10:11:25 -04:00
- SetNextPlotRange - > SetNextPlotLimits
2020-05-11 07:12:22 -04:00
- SetNextPlotRangeX - > SetNextPlotLimitsX
- SetNextPlotRangeY - > SetNextPlotLimitsY
- 2020 / 05 / 10 ( 0.2 ) - Plot queries are pixel based by default . Query rects that maintain relative plot position have been removed . This was done to support multi - y - axis .
*/
2020-04-27 11:27:59 -04:00
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif
2020-05-10 22:43:12 -04:00
# include "implot.h"
# include "imgui_internal.h"
2020-06-01 18:26:32 -04:00
# include <algorithm> //std::min
2020-05-11 07:12:22 -04:00
2020-05-10 22:43:12 -04:00
# ifdef _MSC_VER
# define sprintf sprintf_s
# endif
2020-04-27 11:27:59 -04:00
# define IM_NORMALIZE2F_OVER_ZERO(VX, VY) \
{ \
float d2 = VX * VX + VY * VY ; \
if ( d2 > 0.0f ) { \
float inv_len = 1.0f / ImSqrt ( d2 ) ; \
VX * = inv_len ; \
VY * = inv_len ; \
} \
}
// Special Color used to specific that a plot item color should set determined automatically.
# define IM_COL_AUTO ImVec4(0,0,0,-1)
2020-05-11 07:12:22 -04:00
// The maximum number of support y-axes
# define MAX_Y_AXES 3
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
// static inline float ImLog10(float x) { return log10f(x); }
static inline double ImLog10 ( double x ) { return log10 ( x ) ; }
2020-04-27 11:27:59 -04:00
ImPlotStyle : : ImPlotStyle ( ) {
LineWeight = 1 ;
2020-05-13 10:08:12 -04:00
Marker = ImPlotMarker_None ;
2020-05-16 09:39:43 -04:00
MarkerSize = 4 ;
2020-04-27 11:27:59 -04:00
MarkerWeight = 1 ;
ErrorBarSize = 5 ;
ErrorBarWeight = 1.5 ;
2020-05-09 00:54:16 -04:00
DigitalBitHeight = 8 ;
2020-06-01 16:31:26 -04:00
DigitalBitGap = 4 ;
2020-04-27 11:27:59 -04:00
Colors [ ImPlotCol_Line ] = IM_COL_AUTO ;
Colors [ ImPlotCol_Fill ] = IM_COL_AUTO ;
Colors [ ImPlotCol_MarkerOutline ] = IM_COL_AUTO ;
Colors [ ImPlotCol_MarkerFill ] = IM_COL_AUTO ;
Colors [ ImPlotCol_ErrorBar ] = IM_COL_AUTO ;
Colors [ ImPlotCol_FrameBg ] = IM_COL_AUTO ;
Colors [ ImPlotCol_PlotBg ] = IM_COL_AUTO ;
Colors [ ImPlotCol_PlotBorder ] = IM_COL_AUTO ;
Colors [ ImPlotCol_XAxis ] = IM_COL_AUTO ;
Colors [ ImPlotCol_YAxis ] = IM_COL_AUTO ;
2020-05-11 07:12:22 -04:00
Colors [ ImPlotCol_YAxis2 ] = IM_COL_AUTO ;
Colors [ ImPlotCol_YAxis3 ] = IM_COL_AUTO ;
2020-04-27 11:27:59 -04:00
Colors [ ImPlotCol_Selection ] = ImVec4 ( 1 , 1 , 0 , 1 ) ;
2020-05-04 03:09:33 -04:00
Colors [ ImPlotCol_Query ] = ImVec4 ( 0 , 1 , 0 , 1 ) ;
2020-04-28 00:57:49 -04:00
}
2020-05-16 22:09:36 -04:00
ImPlotRange : : ImPlotRange ( ) {
Min = NAN ;
Max = NAN ;
}
2020-05-11 07:12:22 -04:00
2020-05-29 13:39:30 -04:00
bool ImPlotRange : : Contains ( double v ) const {
2020-05-11 07:12:22 -04:00
return v > = Min & & v < = Max ;
2020-04-28 00:57:49 -04:00
}
2020-05-29 13:39:30 -04:00
double ImPlotRange : : Size ( ) const {
2020-05-11 07:12:22 -04:00
return Max - Min ;
}
ImPlotLimits : : ImPlotLimits ( ) { }
2020-05-31 10:28:34 -04:00
bool ImPlotLimits : : Contains ( const ImPlotPoint & p ) const {
return Contains ( p . x , p . y ) ;
}
2020-05-29 13:39:30 -04:00
bool ImPlotLimits : : Contains ( double x , double y ) const {
return X . Contains ( x ) & & Y . Contains ( y ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
namespace ImPlot {
2020-04-27 11:27:59 -04:00
namespace {
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
// Private Utils
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-06-02 13:34:14 -04:00
template < int Count >
struct OffsetCalculator {
OffsetCalculator ( int * sizes ) {
Offsets [ 0 ] = 0 ;
for ( int i = 1 ; i < Count ; + + i )
Offsets [ i ] = Offsets [ i - 1 ] + sizes [ i - 1 ] ;
}
int Offsets [ Count ] ;
} ;
2020-06-03 15:37:01 -04:00
template < typename T >
void FillRange ( ImVector < T > & buffer , int n , T vmin , T vmax ) {
buffer . resize ( n ) ;
T step = ( vmax - vmin ) / ( n - 1 ) ;
for ( int i = 0 ; i < n ; + + i ) {
buffer [ i ] = vmin + i * step ;
}
}
2020-06-04 10:56:50 -04:00
// Returns true if a flag is set
2020-04-27 11:27:59 -04:00
template < typename TSet , typename TFlag >
inline bool HasFlag ( TSet set , TFlag flag ) {
return ( set & flag ) = = flag ;
}
2020-06-04 10:56:50 -04:00
// Flips a flag in a flagset
2020-05-13 10:11:25 -04:00
template < typename TSet , typename TFlag >
2020-04-27 11:27:59 -04:00
inline void FlipFlag ( TSet & set , TFlag flag ) {
HasFlag ( set , flag ) ? set & = ~ flag : set | = flag ;
}
2020-06-04 10:56:50 -04:00
// Linearly remaps x from [x0 x1] to [y0 y1].
2020-06-01 23:14:22 -04:00
template < typename T >
inline T Remap ( T x , T x0 , T x1 , T y0 , T y1 ) {
2020-04-27 11:27:59 -04:00
return y0 + ( x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) ;
}
2020-06-04 10:56:50 -04:00
// Turns NANs to 0s
2020-05-29 13:39:30 -04:00
inline double ConstrainNan ( double val ) {
2020-05-11 07:12:22 -04:00
return isnan ( val ) ? 0 : val ;
2020-04-27 11:27:59 -04:00
}
2020-06-04 10:56:50 -04:00
// Turns infinity to floating point maximums
2020-05-29 13:39:30 -04:00
inline double ConstrainInf ( double val ) {
return val = = HUGE_VAL ? DBL_MAX : val = = - HUGE_VAL ? - DBL_MAX : val ;
2020-04-27 11:27:59 -04:00
}
2020-06-04 10:56:50 -04:00
// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?)
2020-05-29 13:39:30 -04:00
inline double ConstrainLog ( double val ) {
2020-05-03 01:24:10 -04:00
return val < = 0 ? 0.001f : val ;
2020-04-27 11:27:59 -04:00
}
2020-06-04 10:56:50 -04:00
// Returns true if val is NAN or INFINITY
2020-05-29 13:39:30 -04:00
inline bool NanOrInf ( double val ) {
return val = = HUGE_VAL | | val = = - HUGE_VAL | | isnan ( val ) ;
2020-04-27 11:27:59 -04:00
}
2020-06-04 10:56:50 -04:00
// Computes order of magnitude of double.
// inline int OrderOfMagnitude(double val) {
// return val == 0 ? 0 : (int)(floor(log10(fabs(val))));
// }
// Returns the precision required for a order of magnitude.
// inline int OrderToPrecision(int order) {
// return order > 0 ? 0 : 1 - order;
// }
// Draws vertical text. The position is the bottom left of the text rect.
2020-04-27 11:27:59 -04:00
inline void AddTextVertical ( ImDrawList * DrawList , const char * text , ImVec2 pos , ImU32 text_color ) {
pos . x = IM_ROUND ( pos . x ) ;
pos . y = IM_ROUND ( pos . y ) ;
ImFont * font = GImGui - > Font ;
const ImFontGlyph * glyph ;
2020-05-10 22:43:12 -04:00
for ( char c = * text + + ; c ; c = * text + + ) {
2020-04-27 11:27:59 -04:00
glyph = font - > FindGlyph ( c ) ;
if ( ! glyph )
continue ;
DrawList - > PrimReserve ( 6 , 4 ) ;
DrawList - > PrimQuadUV (
pos + ImVec2 ( glyph - > Y0 , - glyph - > X0 ) , pos + ImVec2 ( glyph - > Y0 , - glyph - > X1 ) ,
pos + ImVec2 ( glyph - > Y1 , - glyph - > X1 ) , pos + ImVec2 ( glyph - > Y1 , - glyph - > X0 ) ,
ImVec2 ( glyph - > U0 , glyph - > V0 ) , ImVec2 ( glyph - > U1 , glyph - > V0 ) ,
ImVec2 ( glyph - > U1 , glyph - > V1 ) , ImVec2 ( glyph - > U0 , glyph - > V1 ) , text_color ) ;
pos . y - = glyph - > AdvanceX ;
}
}
2020-06-04 10:56:50 -04:00
// Calculates the size of vertical text
2020-04-27 11:27:59 -04:00
inline ImVec2 CalcTextSizeVertical ( const char * text ) {
2020-05-12 05:19:04 -04:00
ImVec2 sz = ImGui : : CalcTextSize ( text ) ;
2020-04-27 11:27:59 -04:00
return ImVec2 ( sz . y , sz . x ) ;
}
2020-05-03 01:24:10 -04:00
} // private namespace
//-----------------------------------------------------------------------------
// Forwards
//-----------------------------------------------------------------------------
ImVec4 NextColor ( ) ;
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// Structs
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-06-04 10:56:50 -04:00
// Tick mark info
2020-06-03 10:54:25 -04:00
struct ImPlotTick {
ImPlotTick ( double value , bool major , bool render_label = true ) {
2020-04-27 11:27:59 -04:00
PlotPos = value ;
Major = major ;
RenderLabel = render_label ;
2020-06-03 15:37:01 -04:00
Labeled = false ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
double PlotPos ;
2020-04-27 11:27:59 -04:00
float PixelPos ;
ImVec2 Size ;
2020-05-29 13:39:30 -04:00
int TextOffset ;
2020-05-12 21:45:37 -04:00
bool Major ;
2020-05-29 13:39:30 -04:00
bool RenderLabel ;
2020-06-03 15:37:01 -04:00
bool Labeled ;
2020-04-27 11:27:59 -04:00
} ;
2020-06-04 10:56:50 -04:00
// Axis state information that must persist after EndPlot
2020-04-27 11:27:59 -04:00
struct ImPlotAxis {
2020-05-13 10:11:25 -04:00
ImPlotAxis ( ) {
2020-04-27 11:27:59 -04:00
Dragging = false ;
2020-05-11 07:12:22 -04:00
Range . Min = 0 ;
Range . Max = 1 ;
2020-05-13 10:11:25 -04:00
Divisions = 3 ;
Subdivisions = 10 ;
Flags = PreviousFlags = ImPlotAxisFlags_Default ;
2020-04-27 11:27:59 -04:00
}
bool Dragging ;
2020-05-11 07:12:22 -04:00
ImPlotRange Range ;
2020-04-27 11:27:59 -04:00
int Divisions ;
int Subdivisions ;
2020-05-13 10:08:12 -04:00
ImPlotAxisFlags Flags , PreviousFlags ;
2020-04-27 11:27:59 -04:00
} ;
2020-06-04 10:56:50 -04:00
// Axis state information only needed between BeginPlot/EndPlot
2020-06-04 01:11:43 -04:00
struct ImPlotAxisState {
2020-06-04 10:56:50 -04:00
ImPlotAxis * Axis ;
bool HasRange ;
ImGuiCond RangeCond ;
bool Present ;
int PresentSoFar ;
bool Invert ;
bool LockMin ;
bool LockMax ;
bool Lock ;
ImPlotAxisState ( ImPlotAxis & axis , bool has_range , ImGuiCond range_cond , bool present , int previous_present ) :
Axis ( & axis ) ,
HasRange ( has_range ) ,
RangeCond ( range_cond ) ,
Present ( present ) ,
PresentSoFar ( previous_present + ( Present ? 1 : 0 ) ) ,
Invert ( HasFlag ( Axis - > Flags , ImPlotAxisFlags_Invert ) ) ,
LockMin ( HasFlag ( Axis - > Flags , ImPlotAxisFlags_LockMin ) | | ( HasRange & & RangeCond = = ImGuiCond_Always ) ) ,
LockMax ( HasFlag ( Axis - > Flags , ImPlotAxisFlags_LockMax ) | | ( HasRange & & RangeCond = = ImGuiCond_Always ) ) ,
Lock ( ! Present | | ( ( LockMin & & LockMax ) | | ( HasRange & & RangeCond = = ImGuiCond_Always ) ) )
{ }
ImPlotAxisState ( ) :
Axis ( ) , HasRange ( ) , RangeCond ( ) , Present ( ) , PresentSoFar ( ) , Invert ( ) , LockMin ( ) , LockMax ( ) , Lock ( )
{ }
2020-06-04 01:11:43 -04:00
} ;
struct ImPlotAxisColor {
ImPlotAxisColor ( ) : Major ( ) , Minor ( ) , Txt ( ) { }
ImU32 Major , Minor , Txt ;
} ;
2020-06-04 10:56:50 -04:00
// State information for Plot items
2020-06-04 01:11:43 -04:00
struct ImPlotItem {
ImPlotItem ( ) {
Show = true ;
Highlight = false ;
Color = NextColor ( ) ;
NameOffset = - 1 ;
ID = 0 ;
}
~ ImPlotItem ( ) { ID = 0 ; }
bool Show ;
bool Highlight ;
ImVec4 Color ;
int NameOffset ;
ImGuiID ID ;
} ;
2020-06-04 10:56:50 -04:00
// Holds Plot state information that must persist after EndPlot
2020-05-12 05:19:04 -04:00
struct ImPlotState {
ImPlotState ( ) {
2020-04-30 09:45:03 -04:00
Selecting = Querying = Queried = DraggingQuery = false ;
2020-04-28 21:17:26 -04:00
SelectStart = QueryStart = ImVec2 ( 0 , 0 ) ;
2020-05-11 07:12:22 -04:00
Flags = PreviousFlags = ImPlotFlags_Default ;
2020-04-27 11:27:59 -04:00
ColorIdx = 0 ;
2020-05-11 07:12:22 -04:00
CurrentYAxis = 0 ;
2020-04-27 11:27:59 -04:00
}
ImPool < ImPlotItem > Items ;
ImRect BB_Legend ;
ImVec2 SelectStart ;
2020-05-12 21:45:37 -04:00
bool Selecting ;
2020-04-28 21:17:26 -04:00
bool Querying ;
bool Queried ;
2020-05-12 21:45:37 -04:00
bool DraggingQuery ;
2020-04-28 21:17:26 -04:00
ImVec2 QueryStart ;
2020-06-04 10:56:50 -04:00
ImRect QueryRect ; // relative to BB_Plot!!
2020-05-11 07:12:22 -04:00
2020-04-27 11:27:59 -04:00
ImPlotAxis XAxis ;
2020-05-11 07:12:22 -04:00
ImPlotAxis YAxis [ MAX_Y_AXES ] ;
ImPlotFlags Flags , PreviousFlags ;
2020-04-27 11:27:59 -04:00
int ColorIdx ;
2020-05-11 07:12:22 -04:00
int CurrentYAxis ;
2020-04-27 11:27:59 -04:00
} ;
2020-06-03 10:50:06 -04:00
struct ImPlotNextPlotData {
ImPlotNextPlotData ( ) {
HasXRange = false ;
2020-06-03 15:37:01 -04:00
ShowDefaultTicksX = true ;
2020-06-03 10:50:06 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; + + i ) {
HasYRange [ i ] = false ;
2020-06-03 15:37:01 -04:00
ShowDefaultTicksY [ i ] = true ;
2020-06-03 10:50:06 -04:00
}
}
2020-04-27 11:27:59 -04:00
ImGuiCond XRangeCond ;
2020-05-11 07:12:22 -04:00
ImGuiCond YRangeCond [ MAX_Y_AXES ] ;
2020-04-27 11:27:59 -04:00
bool HasXRange ;
2020-05-11 07:12:22 -04:00
bool HasYRange [ MAX_Y_AXES ] ;
ImPlotRange X ;
ImPlotRange Y [ MAX_Y_AXES ] ;
2020-06-03 15:37:01 -04:00
bool ShowDefaultTicksX ;
bool ShowDefaultTicksY [ MAX_Y_AXES ] ;
2020-04-27 11:27:59 -04:00
} ;
2020-06-04 10:56:50 -04:00
// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot()
2020-04-27 11:27:59 -04:00
struct ImPlotContext {
2020-05-11 07:12:22 -04:00
ImPlotContext ( ) : RenderX ( ) , RenderY ( ) {
2020-06-03 15:37:01 -04:00
ChildWindowMade = false ;
Reset ( ) ;
2020-06-02 13:34:14 -04:00
SetColormap ( ImPlotColormap_Default ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
2020-06-03 15:37:01 -04:00
void Reset ( ) {
// end child window if it was made
if ( ChildWindowMade )
ImGui : : EndChild ( ) ;
ChildWindowMade = false ;
// reset the next plot data
NextPlotData = ImPlotNextPlotData ( ) ;
// reset items count
VisibleItemCount = 0 ;
// reset legend items
LegendIndices . shrink ( 0 ) ;
LegendLabels . Buf . shrink ( 0 ) ;
// reset ticks/labels
XTicks . shrink ( 0 ) ;
XTickLabels . Buf . shrink ( 0 ) ;
for ( int i = 0 ; i < 3 ; + + i ) {
YTicks [ i ] . shrink ( 0 ) ;
YTickLabels [ i ] . Buf . shrink ( 0 ) ;
}
// reset extents
FitX = false ;
ExtentsX . Min = HUGE_VAL ;
ExtentsX . Max = - HUGE_VAL ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
ExtentsY [ i ] . Min = HUGE_VAL ;
ExtentsY [ i ] . Max = - HUGE_VAL ;
FitY [ i ] = false ;
}
// reset digital plot items count
DigitalPlotItemCnt = 0 ;
DigitalPlotOffset = 0 ;
// nullify plot
CurrentPlot = NULL ;
}
2020-06-04 10:56:50 -04:00
// ALl Plots
2020-05-12 05:19:04 -04:00
ImPool < ImPlotState > Plots ;
2020-06-04 10:56:50 -04:00
// Current Plot
2020-05-12 05:19:04 -04:00
ImPlotState * CurrentPlot ;
2020-04-27 11:27:59 -04:00
// Legend
2020-05-13 10:11:25 -04:00
ImVector < int > LegendIndices ;
2020-05-03 01:24:10 -04:00
ImGuiTextBuffer LegendLabels ;
2020-05-13 10:11:25 -04:00
// Bounding regions
2020-04-27 11:27:59 -04:00
ImRect BB_Frame ;
ImRect BB_Canvas ;
2020-06-04 10:56:50 -04:00
ImRect BB_Plot ;
2020-05-03 01:24:10 -04:00
// Cached Colors
2020-05-13 10:11:25 -04:00
ImU32 Col_Frame , Col_Bg , Col_Border ,
Col_Txt , Col_TxtDis ,
2020-04-27 11:27:59 -04:00
Col_SlctBg , Col_SlctBd ,
2020-05-11 09:57:36 -04:00
Col_QryBg , Col_QryBd ;
2020-06-04 01:11:43 -04:00
ImPlotAxisColor Col_X ;
ImPlotAxisColor Col_Y [ MAX_Y_AXES ] ;
ImPlotAxisState X ;
ImPlotAxisState Y [ MAX_Y_AXES ] ;
2020-05-11 07:12:22 -04:00
// Tick marks
2020-06-03 10:54:25 -04:00
ImVector < ImPlotTick > XTicks , YTicks [ MAX_Y_AXES ] ;
2020-05-11 07:12:22 -04:00
ImGuiTextBuffer XTickLabels , YTickLabels [ MAX_Y_AXES ] ;
float AxisLabelReference [ MAX_Y_AXES ] ;
2020-05-03 01:24:10 -04:00
// Transformation cache
2020-05-11 07:12:22 -04:00
ImRect PixelRange [ MAX_Y_AXES ] ;
// linear scale (slope)
2020-05-29 13:39:30 -04:00
double Mx ;
double My [ MAX_Y_AXES ] ;
2020-05-11 07:12:22 -04:00
// log scale denominator
2020-05-29 13:39:30 -04:00
double LogDenX ;
double LogDenY [ MAX_Y_AXES ] ;
2020-04-27 11:27:59 -04:00
// Data extents
2020-05-11 07:12:22 -04:00
ImPlotRange ExtentsX ;
ImPlotRange ExtentsY [ MAX_Y_AXES ] ;
2020-04-27 11:27:59 -04:00
int VisibleItemCount ;
2020-05-11 07:12:22 -04:00
bool FitThisFrame ; bool FitX ;
2020-06-03 15:37:01 -04:00
bool FitY [ MAX_Y_AXES ] ;
2020-05-12 21:45:37 -04:00
// Hover states
bool Hov_Frame ;
2020-06-04 10:56:50 -04:00
bool Hov_Plot ;
2020-04-27 11:27:59 -04:00
// Render flags
2020-05-11 07:12:22 -04:00
bool RenderX , RenderY [ MAX_Y_AXES ] ;
2020-06-03 15:37:01 -04:00
// Lock info
bool LockPlot ;
bool ChildWindowMade ;
2020-04-27 11:27:59 -04:00
// Mouse pos
2020-05-16 22:09:36 -04:00
ImPlotPoint LastMousePos [ MAX_Y_AXES ] ;
2020-04-27 11:27:59 -04:00
// Style
2020-06-02 13:34:14 -04:00
ImVec4 * Colormap ;
int ColormapSize ;
2020-04-27 11:27:59 -04:00
ImPlotStyle Style ;
ImVector < ImGuiColorMod > ColorModifiers ; // Stack for PushStyleColor()/PopStyleColor()
ImVector < ImGuiStyleMod > StyleModifiers ; // Stack for PushStyleVar()/PopStyleVar()
2020-06-03 10:50:06 -04:00
ImPlotNextPlotData NextPlotData ;
2020-04-29 10:32:35 -04:00
// Digital plot item count
int DigitalPlotItemCnt ;
2020-05-09 00:54:16 -04:00
int DigitalPlotOffset ;
2020-04-27 11:27:59 -04:00
} ;
2020-06-04 10:56:50 -04:00
// Global plot context
2020-04-27 11:27:59 -04:00
static ImPlotContext gp ;
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-06-03 15:37:01 -04:00
// Context Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-06-04 10:56:50 -04:00
// Returns the next unused default plot color
2020-05-03 01:24:10 -04:00
ImVec4 NextColor ( ) {
2020-06-02 13:34:14 -04:00
ImVec4 col = gp . Colormap [ gp . CurrentPlot - > ColorIdx % gp . ColormapSize ] ;
2020-05-03 01:24:10 -04:00
gp . CurrentPlot - > ColorIdx + + ;
return col ;
2020-04-28 01:38:52 -04:00
}
2020-04-27 11:27:59 -04:00
2020-05-16 22:53:59 -04:00
inline void FitPoint ( const ImPlotPoint & p ) {
2020-05-11 07:12:22 -04:00
ImPlotRange * extents_x = & gp . ExtentsX ;
ImPlotRange * extents_y = & gp . ExtentsY [ gp . CurrentPlot - > CurrentYAxis ] ;
2020-05-03 01:24:10 -04:00
if ( ! NanOrInf ( p . x ) ) {
2020-05-11 07:12:22 -04:00
extents_x - > Min = p . x < extents_x - > Min ? p . x : extents_x - > Min ;
extents_x - > Max = p . x > extents_x - > Max ? p . x : extents_x - > Max ;
2020-05-03 01:24:10 -04:00
}
if ( ! NanOrInf ( p . y ) ) {
2020-05-11 07:12:22 -04:00
extents_y - > Min = p . y < extents_y - > Min ? p . y : extents_y - > Min ;
extents_y - > Max = p . y > extents_y - > Max ? p . y : extents_y - > Max ;
2020-05-03 01:24:10 -04:00
}
}
//-----------------------------------------------------------------------------
// Coordinate Transforms
//-----------------------------------------------------------------------------
inline void UpdateTransformCache ( ) {
// get pixels for transforms
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
gp . PixelRange [ i ] = ImRect ( HasFlag ( gp . CurrentPlot - > XAxis . Flags , ImPlotAxisFlags_Invert ) ? gp . BB_Plot . Max . x : gp . BB_Plot . Min . x ,
HasFlag ( gp . CurrentPlot - > YAxis [ i ] . Flags , ImPlotAxisFlags_Invert ) ? gp . BB_Plot . Min . y : gp . BB_Plot . Max . y ,
HasFlag ( gp . CurrentPlot - > XAxis . Flags , ImPlotAxisFlags_Invert ) ? gp . BB_Plot . Min . x : gp . BB_Plot . Max . x ,
HasFlag ( gp . CurrentPlot - > YAxis [ i ] . Flags , ImPlotAxisFlags_Invert ) ? gp . BB_Plot . Max . y : gp . BB_Plot . Min . y ) ;
2020-05-11 07:12:22 -04:00
gp . My [ i ] = ( gp . PixelRange [ i ] . Max . y - gp . PixelRange [ i ] . Min . y ) / gp . CurrentPlot - > YAxis [ i ] . Range . Size ( ) ;
}
2020-05-29 13:39:30 -04:00
gp . LogDenX = ImLog10 ( gp . CurrentPlot - > XAxis . Range . Max / gp . CurrentPlot - > XAxis . Range . Min ) ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-05-29 13:39:30 -04:00
gp . LogDenY [ i ] = ImLog10 ( gp . CurrentPlot - > YAxis [ i ] . Range . Max / gp . CurrentPlot - > YAxis [ i ] . Range . Min ) ;
2020-05-11 07:12:22 -04:00
}
gp . Mx = ( gp . PixelRange [ 0 ] . Max . x - gp . PixelRange [ 0 ] . Min . x ) / gp . CurrentPlot - > XAxis . Range . Size ( ) ;
2020-04-28 01:38:52 -04:00
}
2020-04-27 11:27:59 -04:00
2020-05-16 22:09:36 -04:00
inline ImPlotPoint PixelsToPlot ( float x , float y , int y_axis_in = - 1 ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PixelsToPlot() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in > = 0 ? y_axis_in : gp . CurrentPlot - > CurrentYAxis ;
2020-05-16 22:09:36 -04:00
ImPlotPoint plt ;
2020-05-11 07:12:22 -04:00
plt . x = ( x - gp . PixelRange [ y_axis ] . Min . x ) / gp . Mx + gp . CurrentPlot - > XAxis . Range . Min ;
plt . y = ( y - gp . PixelRange [ y_axis ] . Min . y ) / gp . My [ y_axis ] + gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . CurrentPlot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) ) {
2020-05-29 13:39:30 -04:00
double t = ( plt . x - gp . CurrentPlot - > XAxis . Range . Min ) / gp . CurrentPlot - > XAxis . Range . Size ( ) ;
plt . x = ImPow ( 10 , t * gp . LogDenX ) * gp . CurrentPlot - > XAxis . Range . Min ;
2020-05-03 01:24:10 -04:00
}
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . CurrentPlot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) ) {
2020-05-29 13:39:30 -04:00
double t = ( plt . y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) / gp . CurrentPlot - > YAxis [ y_axis ] . Range . Size ( ) ;
plt . y = ImPow ( 10 , t * gp . LogDenY [ y_axis ] ) * gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ;
2020-05-03 01:24:10 -04:00
}
return plt ;
}
2020-05-16 22:09:36 -04:00
ImPlotPoint PixelsToPlot ( const ImVec2 & pix , int y_axis ) {
2020-05-15 09:05:02 -04:00
return PixelsToPlot ( pix . x , pix . y , y_axis ) ;
}
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
2020-05-29 13:39:30 -04:00
inline ImVec2 PlotToPixels ( double x , double y , int y_axis_in = - 1 ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotToPixels() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in > = 0 ? y_axis_in : gp . CurrentPlot - > CurrentYAxis ;
2020-05-03 01:24:10 -04:00
ImVec2 pix ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . CurrentPlot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) ) {
2020-05-29 13:39:30 -04:00
double t = ImLog10 ( x / gp . CurrentPlot - > XAxis . Range . Min ) / gp . LogDenX ;
2020-05-16 22:09:36 -04:00
x = ImLerp ( gp . CurrentPlot - > XAxis . Range . Min , gp . CurrentPlot - > XAxis . Range . Max , ( float ) t ) ;
2020-05-13 10:11:25 -04:00
}
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . CurrentPlot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) ) {
2020-05-29 13:39:30 -04:00
double t = ImLog10 ( y / gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) / gp . LogDenY [ y_axis ] ;
2020-05-16 22:09:36 -04:00
y = ImLerp ( gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min , gp . CurrentPlot - > YAxis [ y_axis ] . Range . Max , ( float ) t ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-16 22:09:36 -04:00
pix . x = ( float ) ( gp . PixelRange [ y_axis ] . Min . x + gp . Mx * ( x - gp . CurrentPlot - > XAxis . Range . Min ) ) ;
pix . y = ( float ) ( gp . PixelRange [ y_axis ] . Min . y + gp . My [ y_axis ] * ( y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) ) ;
2020-05-03 01:24:10 -04:00
return pix ;
}
2020-05-15 09:05:02 -04:00
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
2020-05-16 22:09:36 -04:00
ImVec2 PlotToPixels ( const ImPlotPoint & plt , int y_axis ) {
2020-05-11 07:12:22 -04:00
return PlotToPixels ( plt . x , plt . y , y_axis ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-29 13:39:30 -04:00
// Transformer functors
2020-05-15 09:05:02 -04:00
2020-05-29 09:40:04 -04:00
struct TransformerLinLin {
TransformerLinLin ( int y_axis_in ) : y_axis ( y_axis_in ) { }
2020-05-03 01:24:10 -04:00
2020-05-29 09:40:04 -04:00
inline ImVec2 operator ( ) ( const ImPlotPoint & plt ) { return ( * this ) ( plt . x , plt . y ) ; }
2020-05-29 13:39:30 -04:00
inline ImVec2 operator ( ) ( double x , double y ) {
2020-05-16 22:53:59 -04:00
return ImVec2 ( ( float ) ( gp . PixelRange [ y_axis ] . Min . x + gp . Mx * ( x - gp . CurrentPlot - > XAxis . Range . Min ) ) ,
( float ) ( gp . PixelRange [ y_axis ] . Min . y + gp . My [ y_axis ] * ( y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) ) ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-11 07:12:22 -04:00
int y_axis ;
} ;
2020-05-03 01:24:10 -04:00
2020-05-29 09:40:04 -04:00
struct TransformerLogLin {
TransformerLogLin ( int y_axis_in ) : y_axis ( y_axis_in ) { }
2020-05-11 07:12:22 -04:00
2020-05-29 09:40:04 -04:00
inline ImVec2 operator ( ) ( const ImPlotPoint & plt ) { return ( * this ) ( plt . x , plt . y ) ; }
2020-05-29 13:39:30 -04:00
inline ImVec2 operator ( ) ( double x , double y ) {
double t = ImLog10 ( x / gp . CurrentPlot - > XAxis . Range . Min ) / gp . LogDenX ;
2020-05-16 22:53:59 -04:00
x = ImLerp ( gp . CurrentPlot - > XAxis . Range . Min , gp . CurrentPlot - > XAxis . Range . Max , ( float ) t ) ;
return ImVec2 ( ( float ) ( gp . PixelRange [ y_axis ] . Min . x + gp . Mx * ( x - gp . CurrentPlot - > XAxis . Range . Min ) ) ,
( float ) ( gp . PixelRange [ y_axis ] . Min . y + gp . My [ y_axis ] * ( y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) ) ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-11 07:12:22 -04:00
int y_axis ;
2020-05-03 01:24:10 -04:00
} ;
2020-05-29 09:40:04 -04:00
struct TransformerLinLog {
TransformerLinLog ( int y_axis_in ) : y_axis ( y_axis_in ) { }
2020-05-11 07:12:22 -04:00
2020-05-29 09:40:04 -04:00
inline ImVec2 operator ( ) ( const ImPlotPoint & plt ) { return ( * this ) ( plt . x , plt . y ) ; }
2020-05-29 13:39:30 -04:00
inline ImVec2 operator ( ) ( double x , double y ) {
double t = ImLog10 ( y / gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) / gp . LogDenY [ y_axis ] ;
y = ImLerp ( gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min , gp . CurrentPlot - > YAxis [ y_axis ] . Range . Max , ( float ) t ) ;
2020-05-16 22:53:59 -04:00
return ImVec2 ( ( float ) ( gp . PixelRange [ y_axis ] . Min . x + gp . Mx * ( x - gp . CurrentPlot - > XAxis . Range . Min ) ) ,
( float ) ( gp . PixelRange [ y_axis ] . Min . y + gp . My [ y_axis ] * ( y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) ) ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-11 07:12:22 -04:00
int y_axis ;
2020-05-03 01:24:10 -04:00
} ;
2020-05-29 09:40:04 -04:00
struct TransformerLogLog {
TransformerLogLog ( int y_axis_in ) : y_axis ( y_axis_in ) {
2020-05-11 07:12:22 -04:00
2020-05-29 09:40:04 -04:00
}
inline ImVec2 operator ( ) ( const ImPlotPoint & plt ) { return ( * this ) ( plt . x , plt . y ) ; }
2020-05-29 13:39:30 -04:00
inline ImVec2 operator ( ) ( double x , double y ) {
double t = ImLog10 ( x / gp . CurrentPlot - > XAxis . Range . Min ) / gp . LogDenX ;
x = ImLerp ( gp . CurrentPlot - > XAxis . Range . Min , gp . CurrentPlot - > XAxis . Range . Max , ( float ) t ) ;
t = ImLog10 ( y / gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) / gp . LogDenY [ y_axis ] ;
y = ImLerp ( gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min , gp . CurrentPlot - > YAxis [ y_axis ] . Range . Max , ( float ) t ) ;
2020-05-16 22:53:59 -04:00
return ImVec2 ( ( float ) ( gp . PixelRange [ y_axis ] . Min . x + gp . Mx * ( x - gp . CurrentPlot - > XAxis . Range . Min ) ) ,
( float ) ( gp . PixelRange [ y_axis ] . Min . y + gp . My [ y_axis ] * ( y - gp . CurrentPlot - > YAxis [ y_axis ] . Range . Min ) ) ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-11 07:12:22 -04:00
int y_axis ;
2020-05-03 01:24:10 -04:00
} ;
//-----------------------------------------------------------------------------
// Legend Utils
//-----------------------------------------------------------------------------
ImPlotItem * RegisterItem ( const char * label_id ) {
ImGuiID id = ImGui : : GetID ( label_id ) ;
ImPlotItem * item = gp . CurrentPlot - > Items . GetOrAddByKey ( id ) ;
int idx = gp . CurrentPlot - > Items . GetIndex ( item ) ;
item - > ID = id ;
gp . LegendIndices . push_back ( idx ) ;
item - > NameOffset = gp . LegendLabels . size ( ) ;
gp . LegendLabels . append ( label_id , label_id + strlen ( label_id ) + 1 ) ;
if ( item - > Show )
gp . VisibleItemCount + + ;
return item ;
}
int GetLegendCount ( ) {
return gp . LegendIndices . size ( ) ;
}
ImPlotItem * GetLegendItem ( int i ) {
return gp . CurrentPlot - > Items . GetByIndex ( gp . LegendIndices [ i ] ) ;
}
const char * GetLegendLabel ( int i ) {
ImPlotItem * item = gp . CurrentPlot - > Items . GetByIndex ( gp . LegendIndices [ i ] ) ;
IM_ASSERT ( item - > NameOffset ! = - 1 & & item - > NameOffset < gp . LegendLabels . Buf . Size ) ;
return gp . LegendLabels . Buf . Data + item - > NameOffset ;
}
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// Tick Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-06-04 10:56:50 -04:00
// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels
// Taken from Graphics Gems 1 Chapter 11.2, "Nice Numbers for Graph Labels"
2020-06-02 23:07:27 -04:00
inline double NiceNum ( double x , bool round ) {
double f ; /* fractional part of x */
double nf ; /* nice, rounded fraction */
int expv = ( int ) floor ( ImLog10 ( x ) ) ;
f = x / ImPow ( 10.0 , ( double ) expv ) ; /* between 1 and 10 */
if ( round )
if ( f < 1.5 )
nf = 1 ;
else if ( f < 3 )
nf = 2 ;
else if ( f < 7 )
nf = 5 ;
else
nf = 10 ;
else if ( f < = 1 )
nf = 1 ;
else if ( f < = 2 )
nf = 2 ;
else if ( f < = 5 )
nf = 5 ;
else
nf = 10 ;
return nf * ImPow ( 10.0 , expv ) ;
}
2020-06-03 15:37:01 -04:00
inline void AddDefaultTicks ( const ImPlotRange & range , int nMajor , int nMinor , bool logscale , ImVector < ImPlotTick > & out ) {
2020-04-27 11:27:59 -04:00
if ( logscale ) {
2020-05-17 00:25:15 -04:00
if ( range . Min < = 0 | | range . Max < = 0 )
2020-04-27 11:27:59 -04:00
return ;
2020-05-29 13:39:30 -04:00
int exp_min = ( int ) ImLog10 ( range . Min ) ;
int exp_max = ( int ) ( ceil ( ImLog10 ( range . Max ) ) ) ;
2020-04-27 11:27:59 -04:00
for ( int e = exp_min - 1 ; e < exp_max + 1 ; + + e ) {
double major1 = ImPow ( 10 , ( double ) ( e ) ) ;
double major2 = ImPow ( 10 , ( double ) ( e + 1 ) ) ;
double interval = ( major2 - major1 ) / 9 ;
2020-05-29 13:39:30 -04:00
if ( major1 > = ( range . Min - DBL_EPSILON ) & & major1 < = ( range . Max + DBL_EPSILON ) )
2020-06-03 10:54:25 -04:00
out . push_back ( ImPlotTick ( major1 , true ) ) ;
2020-04-27 11:27:59 -04:00
for ( int i = 1 ; i < 9 ; + + i ) {
double minor = major1 + i * interval ;
2020-05-29 13:39:30 -04:00
if ( minor > = ( range . Min - DBL_EPSILON ) & & minor < = ( range . Max + DBL_EPSILON ) )
2020-06-03 10:54:25 -04:00
out . push_back ( ImPlotTick ( minor , false , false ) ) ;
2020-04-27 11:27:59 -04:00
}
}
}
else {
2020-05-17 00:25:15 -04:00
const double nice_range = NiceNum ( range . Size ( ) * 0.99 , 0 ) ;
const double interval = NiceNum ( nice_range / ( nMajor - 1 ) , 1 ) ;
const double graphmin = floor ( range . Min / interval ) * interval ;
const double graphmax = ceil ( range . Max / interval ) * interval ;
2020-04-27 11:27:59 -04:00
for ( double major = graphmin ; major < graphmax + 0.5 * interval ; major + = interval ) {
2020-05-17 00:25:15 -04:00
if ( major > = range . Min & & major < = range . Max )
2020-06-03 10:54:25 -04:00
out . push_back ( ImPlotTick ( major , true ) ) ;
2020-04-27 11:27:59 -04:00
for ( int i = 1 ; i < nMinor ; + + i ) {
double minor = major + i * interval / nMinor ;
2020-05-17 00:25:15 -04:00
if ( minor > = range . Min & & minor < = range . Max )
2020-06-03 10:54:25 -04:00
out . push_back ( ImPlotTick ( minor , false ) ) ;
2020-04-27 11:27:59 -04:00
}
}
}
}
2020-06-03 10:54:25 -04:00
inline void LabelTicks ( ImVector < ImPlotTick > & ticks , bool scientific , ImGuiTextBuffer & buffer ) {
2020-04-27 11:27:59 -04:00
char temp [ 32 ] ;
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < ticks . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * tk = & ticks [ t ] ;
2020-06-03 15:37:01 -04:00
if ( tk - > RenderLabel & & ! tk - > Labeled ) {
2020-05-13 00:45:34 -04:00
tk - > TextOffset = buffer . size ( ) ;
2020-04-27 11:27:59 -04:00
if ( scientific )
2020-05-13 00:45:34 -04:00
sprintf ( temp , " %.0e " , tk - > PlotPos ) ;
2020-04-27 11:27:59 -04:00
else
2020-06-04 10:56:50 -04:00
sprintf ( temp , " %.10g " , tk - > PlotPos ) ;
2020-04-27 11:27:59 -04:00
buffer . append ( temp , temp + strlen ( temp ) + 1 ) ;
2020-05-13 00:45:34 -04:00
tk - > Size = ImGui : : CalcTextSize ( buffer . Buf . Data + tk - > TextOffset ) ;
2020-06-03 15:37:01 -04:00
tk - > Labeled = true ;
}
}
}
inline void AddCustomTicks ( const double * values , const char * * labels , int n , ImVector < ImPlotTick > & ticks , ImGuiTextBuffer & buffer ) {
for ( int i = 0 ; i < n ; + + i ) {
ImPlotTick tick ( values [ i ] , false ) ;
tick . TextOffset = buffer . size ( ) ;
if ( labels ! = NULL ) {
buffer . append ( labels [ i ] , labels [ i ] + strlen ( labels [ i ] ) + 1 ) ;
tick . Size = ImGui : : CalcTextSize ( labels [ i ] ) ;
tick . Labeled = true ;
2020-04-27 11:27:59 -04:00
}
2020-06-03 15:37:01 -04:00
ticks . push_back ( tick ) ;
2020-04-27 11:27:59 -04:00
}
}
2020-06-04 10:56:50 -04:00
inline float MaxTickLabelWidth ( ImVector < ImPlotTick > & ticks ) {
float w = 0 ;
for ( int i = 0 ; i < ticks . Size ; + + i )
w = ticks [ i ] . Size . x > w ? ticks [ i ] . Size . x : w ;
return w ;
2020-05-11 07:12:22 -04:00
}
class YPadCalculator {
public :
2020-06-04 01:11:43 -04:00
YPadCalculator ( const ImPlotAxisState * axis_states , const float * max_label_widths , float txt_off )
: ImPlotAxisStates ( axis_states ) , MaxLabelWidths ( max_label_widths ) , TxtOff ( txt_off ) { }
2020-05-11 07:12:22 -04:00
float operator ( ) ( int y_axis ) {
2020-05-12 05:19:04 -04:00
ImPlotState & plot = * gp . CurrentPlot ;
2020-06-04 10:56:50 -04:00
if ( ! ImPlotAxisStates [ y_axis ] . Present ) { return 0 ; }
2020-05-11 07:12:22 -04:00
// If we have more than 1 axis present before us, then we need
// extra space to account for our tick bar.
float pad_result = 0 ;
2020-06-04 10:56:50 -04:00
if ( ImPlotAxisStates [ y_axis ] . PresentSoFar > = 3 ) {
2020-05-11 07:12:22 -04:00
pad_result + = 6.0f ;
}
2020-05-13 10:08:12 -04:00
if ( ! HasFlag ( plot . YAxis [ y_axis ] . Flags , ImPlotAxisFlags_TickLabels ) ) {
2020-05-11 07:12:22 -04:00
return pad_result ;
}
pad_result + = MaxLabelWidths [ y_axis ] + TxtOff ;
return pad_result ;
}
private :
2020-06-04 01:11:43 -04:00
const ImPlotAxisState * const ImPlotAxisStates ;
2020-05-11 07:12:22 -04:00
const float * const MaxLabelWidths ;
const float TxtOff ;
} ;
2020-06-04 10:56:50 -04:00
//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------
void UpdateAxisColor ( int axis_flag , ImPlotAxisColor * col ) {
const ImVec4 col_Axis = gp . Style . Colors [ axis_flag ] . w = = - 1 ? ImGui : : GetStyle ( ) . Colors [ ImGuiCol_Text ] * ImVec4 ( 1 , 1 , 1 , 0.25f ) : gp . Style . Colors [ axis_flag ] ;
col - > Major = ImGui : : GetColorU32 ( col_Axis ) ;
col - > Minor = ImGui : : GetColorU32 ( col_Axis * ImVec4 ( 1 , 1 , 1 , 0.25f ) ) ;
col - > Txt = ImGui : : GetColorU32 ( ImVec4 ( col_Axis . x , col_Axis . y , col_Axis . z , 1 ) ) ;
}
struct ImPlotAxisScale {
ImPlotAxisScale ( int y_axis , float tx , float ty , float zoom_rate ) {
Min = PixelsToPlot ( gp . BB_Plot . Min - gp . BB_Plot . GetSize ( ) * ImVec2 ( tx * zoom_rate , ty * zoom_rate ) , y_axis ) ;
Max = PixelsToPlot ( gp . BB_Plot . Max + gp . BB_Plot . GetSize ( ) * ImVec2 ( ( 1 - tx ) * zoom_rate , ( 1 - ty ) * zoom_rate ) , y_axis ) ;
}
ImPlotPoint Min , Max ;
} ;
2020-05-11 07:12:22 -04:00
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// BeginPlot()
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-13 10:08:12 -04:00
bool BeginPlot ( const char * title , const char * x_label , const char * y_label , const ImVec2 & size , ImPlotFlags flags , ImPlotAxisFlags x_flags , ImPlotAxisFlags y_flags , ImPlotAxisFlags y2_flags , ImPlotAxisFlags y3_flags ) {
2020-04-27 11:27:59 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " Mismatched BeginPlot()/EndPlot()! " ) ;
// FRONT MATTER -----------------------------------------------------------
ImGuiContext & G = * GImGui ;
ImGuiWindow * Window = G . CurrentWindow ;
if ( Window - > SkipItems ) {
2020-06-03 15:37:01 -04:00
gp . Reset ( ) ;
2020-04-27 11:27:59 -04:00
return false ;
}
const ImGuiID ID = Window - > GetID ( title ) ;
const ImGuiStyle & Style = G . Style ;
2020-05-13 10:11:25 -04:00
const ImGuiIO & IO = ImGui : : GetIO ( ) ;
2020-04-27 11:27:59 -04:00
2020-05-13 10:11:25 -04:00
bool just_created = gp . Plots . GetByKey ( ID ) = = NULL ;
2020-04-27 11:27:59 -04:00
gp . CurrentPlot = gp . Plots . GetOrAddByKey ( ID ) ;
2020-05-12 05:19:04 -04:00
ImPlotState & plot = * gp . CurrentPlot ;
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
plot . CurrentYAxis = 0 ;
2020-04-27 11:27:59 -04:00
if ( just_created ) {
2020-05-11 07:12:22 -04:00
plot . Flags = flags ;
plot . XAxis . Flags = x_flags ;
plot . YAxis [ 0 ] . Flags = y_flags ;
plot . YAxis [ 1 ] . Flags = y2_flags ;
plot . YAxis [ 2 ] . Flags = y3_flags ;
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
else {
2020-05-13 10:11:25 -04:00
// TODO: Check which individual flags changed, and only reset those!
2020-05-11 07:12:22 -04:00
// There's probably an easy bit mask trick I'm not aware of.
2020-05-13 10:11:25 -04:00
if ( flags ! = plot . PreviousFlags )
plot . Flags = flags ;
2020-05-11 07:12:22 -04:00
if ( y_flags ! = plot . YAxis [ 0 ] . PreviousFlags )
plot . YAxis [ 0 ] . PreviousFlags = y_flags ;
if ( y2_flags ! = plot . YAxis [ 1 ] . PreviousFlags )
plot . YAxis [ 1 ] . PreviousFlags = y2_flags ;
if ( y3_flags ! = plot . YAxis [ 2 ] . PreviousFlags )
plot . YAxis [ 2 ] . PreviousFlags = y3_flags ;
}
plot . PreviousFlags = flags ;
plot . XAxis . PreviousFlags = x_flags ;
plot . YAxis [ 0 ] . PreviousFlags = y_flags ;
plot . YAxis [ 1 ] . PreviousFlags = y2_flags ;
plot . YAxis [ 2 ] . PreviousFlags = y3_flags ;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
// capture scroll with a child region
2020-05-16 10:11:29 -04:00
const float default_w = 400 ;
const float default_h = 300 ;
2020-05-03 01:24:10 -04:00
if ( ! HasFlag ( plot . Flags , ImPlotFlags_NoChild ) ) {
2020-05-16 10:11:29 -04:00
ImGui : : BeginChild ( title , ImVec2 ( size . x = = 0 ? default_w : size . x , size . y = = 0 ? default_h : size . y ) ) ;
2020-05-03 01:24:10 -04:00
Window = ImGui : : GetCurrentWindow ( ) ;
Window - > ScrollMax . y = 1.0f ;
2020-06-03 15:37:01 -04:00
gp . ChildWindowMade = true ;
}
else {
gp . ChildWindowMade = false ;
2020-05-03 01:24:10 -04:00
}
ImDrawList & DrawList = * Window - > DrawList ;
2020-04-27 11:27:59 -04:00
// NextPlotData -----------------------------------------------------------
if ( gp . NextPlotData . HasXRange ) {
if ( just_created | | gp . NextPlotData . XRangeCond = = ImGuiCond_Always )
{
2020-05-11 07:12:22 -04:00
plot . XAxis . Range = gp . NextPlotData . X ;
2020-04-27 11:27:59 -04:00
}
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( gp . NextPlotData . HasYRange [ i ] ) {
if ( just_created | | gp . NextPlotData . YRangeCond [ i ] = = ImGuiCond_Always )
{
plot . YAxis [ i ] . Range = gp . NextPlotData . Y [ i ] ;
}
2020-04-27 11:27:59 -04:00
}
}
// AXIS STATES ------------------------------------------------------------
2020-06-04 01:11:43 -04:00
gp . X = ImPlotAxisState ( plot . XAxis , gp . NextPlotData . HasXRange , gp . NextPlotData . XRangeCond , true , 0 ) ;
gp . Y [ 0 ] = ImPlotAxisState ( plot . YAxis [ 0 ] , gp . NextPlotData . HasYRange [ 0 ] , gp . NextPlotData . YRangeCond [ 0 ] , true , 0 ) ;
gp . Y [ 1 ] = ImPlotAxisState ( plot . YAxis [ 1 ] , gp . NextPlotData . HasYRange [ 1 ] , gp . NextPlotData . YRangeCond [ 1 ] ,
2020-06-04 10:56:50 -04:00
HasFlag ( plot . Flags , ImPlotFlags_YAxis2 ) , gp . Y [ 0 ] . PresentSoFar ) ;
2020-06-04 01:11:43 -04:00
gp . Y [ 2 ] = ImPlotAxisState ( plot . YAxis [ 2 ] , gp . NextPlotData . HasYRange [ 2 ] , gp . NextPlotData . YRangeCond [ 2 ] ,
2020-06-04 10:56:50 -04:00
HasFlag ( plot . Flags , ImPlotFlags_YAxis3 ) , gp . Y [ 1 ] . PresentSoFar ) ;
2020-06-04 01:11:43 -04:00
2020-06-04 10:56:50 -04:00
gp . LockPlot = gp . X . Lock & & gp . Y [ 0 ] . Lock & & gp . Y [ 1 ] . Lock & & gp . Y [ 2 ] . Lock ;
2020-04-27 11:27:59 -04:00
// CONSTRAINTS ------------------------------------------------------------
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Min = ConstrainNan ( ConstrainInf ( plot . XAxis . Range . Min ) ) ;
plot . XAxis . Range . Max = ConstrainNan ( ConstrainInf ( plot . XAxis . Range . Max ) ) ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
plot . YAxis [ i ] . Range . Min = ConstrainNan ( ConstrainInf ( plot . YAxis [ i ] . Range . Min ) ) ;
plot . YAxis [ i ] . Range . Max = ConstrainNan ( ConstrainInf ( plot . YAxis [ i ] . Range . Max ) ) ;
}
2020-04-27 11:27:59 -04:00
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Min = ConstrainLog ( plot . XAxis . Range . Min ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Max = ConstrainLog ( plot . XAxis . Range . Max ) ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Min = ConstrainLog ( plot . YAxis [ i ] . Range . Min ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Max = ConstrainLog ( plot . YAxis [ i ] . Range . Max ) ;
}
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
if ( plot . XAxis . Range . Max < = plot . XAxis . Range . Min )
2020-05-29 13:39:30 -04:00
plot . XAxis . Range . Max = plot . XAxis . Range . Min + DBL_EPSILON ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( plot . YAxis [ i ] . Range . Max < = plot . YAxis [ i ] . Range . Min )
2020-05-29 13:39:30 -04:00
plot . YAxis [ i ] . Range . Max = plot . YAxis [ i ] . Range . Min + DBL_EPSILON ;
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
// adaptive divisions
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_Adaptive ) ) {
2020-04-27 11:27:59 -04:00
plot . XAxis . Divisions = ( int ) IM_ROUND ( 0.003 * gp . BB_Canvas . GetWidth ( ) ) ;
if ( plot . XAxis . Divisions < 2 )
2020-05-13 10:11:25 -04:00
plot . XAxis . Divisions = 2 ;
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_Adaptive ) ) {
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Divisions = ( int ) IM_ROUND ( 0.003 * gp . BB_Canvas . GetHeight ( ) ) ;
if ( plot . YAxis [ i ] . Divisions < 2 )
plot . YAxis [ i ] . Divisions = 2 ;
}
2020-04-27 11:27:59 -04:00
}
// COLORS -----------------------------------------------------------------
2020-05-12 05:19:04 -04:00
gp . Col_Frame = gp . Style . Colors [ ImPlotCol_FrameBg ] . w = = - 1 ? ImGui : : GetColorU32 ( ImGuiCol_FrameBg ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_FrameBg ] ) ;
gp . Col_Bg = gp . Style . Colors [ ImPlotCol_PlotBg ] . w = = - 1 ? ImGui : : GetColorU32 ( ImGuiCol_WindowBg ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_PlotBg ] ) ;
gp . Col_Border = gp . Style . Colors [ ImPlotCol_PlotBorder ] . w = = - 1 ? ImGui : : GetColorU32 ( ImGuiCol_Text , 0.5f ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_PlotBorder ] ) ;
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
UpdateAxisColor ( ImPlotCol_XAxis , & gp . Col_X ) ;
UpdateAxisColor ( ImPlotCol_YAxis , & gp . Col_Y [ 0 ] ) ;
UpdateAxisColor ( ImPlotCol_YAxis2 , & gp . Col_Y [ 1 ] ) ;
UpdateAxisColor ( ImPlotCol_YAxis3 , & gp . Col_Y [ 2 ] ) ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
gp . Col_Txt = ImGui : : GetColorU32 ( ImGuiCol_Text ) ;
gp . Col_TxtDis = ImGui : : GetColorU32 ( ImGuiCol_TextDisabled ) ;
gp . Col_SlctBg = ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Selection ] * ImVec4 ( 1 , 1 , 1 , 0.25f ) ) ;
gp . Col_SlctBd = ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Selection ] ) ;
gp . Col_QryBg = ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Query ] * ImVec4 ( 1 , 1 , 1 , 0.25f ) ) ;
gp . Col_QryBd = ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Query ] ) ;
2020-04-27 11:27:59 -04:00
// BB AND HOVER -----------------------------------------------------------
// frame
2020-05-16 10:11:29 -04:00
const ImVec2 frame_size = ImGui : : CalcItemSize ( size , default_w , default_h ) ;
2020-04-27 11:27:59 -04:00
gp . BB_Frame = ImRect ( Window - > DC . CursorPos , Window - > DC . CursorPos + frame_size ) ;
2020-05-12 05:19:04 -04:00
ImGui : : ItemSize ( gp . BB_Frame ) ;
if ( ! ImGui : : ItemAdd ( gp . BB_Frame , 0 , & gp . BB_Frame ) ) {
2020-06-03 15:37:01 -04:00
gp . Reset ( ) ;
2020-04-27 11:27:59 -04:00
return false ;
}
2020-05-12 05:19:04 -04:00
gp . Hov_Frame = ImGui : : ItemHoverable ( gp . BB_Frame , ID ) ;
ImGui : : RenderFrame ( gp . BB_Frame . Min , gp . BB_Frame . Max , gp . Col_Frame , true , Style . FrameRounding ) ;
2020-04-27 11:27:59 -04:00
// canvas bb
2020-05-13 10:11:25 -04:00
gp . BB_Canvas = ImRect ( gp . BB_Frame . Min + Style . WindowPadding , gp . BB_Frame . Max - Style . WindowPadding ) ;
2020-04-27 11:27:59 -04:00
2020-05-13 10:08:12 -04:00
gp . RenderX = ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_GridLines ) | |
HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickMarks ) | |
HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickLabels ) ) & & plot . XAxis . Divisions > 1 ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
gp . RenderY [ i ] =
2020-06-04 10:56:50 -04:00
gp . Y [ i ] . Present & &
2020-05-13 10:11:25 -04:00
( HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_GridLines ) | |
HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_TickMarks ) | |
2020-05-13 10:08:12 -04:00
HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_TickLabels ) ) & & plot . YAxis [ i ] . Divisions > 1 ;
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
// get ticks
2020-06-03 15:37:01 -04:00
if ( gp . RenderX & & gp . NextPlotData . ShowDefaultTicksX )
AddDefaultTicks ( plot . XAxis . Range , plot . XAxis . Divisions , plot . XAxis . Subdivisions , HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_LogScale ) , gp . XTicks ) ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-03 15:37:01 -04:00
if ( gp . RenderY [ i ] & & gp . NextPlotData . ShowDefaultTicksY [ i ] ) {
AddDefaultTicks ( plot . YAxis [ i ] . Range , plot . YAxis [ i ] . Divisions , plot . YAxis [ i ] . Subdivisions , HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_LogScale ) , gp . YTicks [ i ] ) ;
2020-05-11 07:12:22 -04:00
}
}
2020-04-27 11:27:59 -04:00
// label ticks
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickLabels ) )
LabelTicks ( gp . XTicks , HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_Scientific ) , gp . XTickLabels ) ;
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
float max_label_width [ MAX_Y_AXES ] = { } ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( gp . Y [ i ] . Present & & HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_TickLabels ) ) {
2020-05-13 10:08:12 -04:00
LabelTicks ( gp . YTicks [ i ] , HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_Scientific ) , gp . YTickLabels [ i ] ) ;
2020-06-04 10:56:50 -04:00
max_label_width [ i ] = MaxTickLabelWidth ( gp . YTicks [ i ] ) ;
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
// grid bb
2020-05-12 05:19:04 -04:00
const ImVec2 title_size = ImGui : : CalcTextSize ( title , NULL , true ) ;
2020-04-27 11:27:59 -04:00
const float txt_off = 5 ;
2020-05-12 05:19:04 -04:00
const float txt_height = ImGui : : GetTextLineHeight ( ) ;
2020-04-27 11:27:59 -04:00
const float pad_top = title_size . x > 0.0f ? txt_height + txt_off : 0 ;
2020-05-13 10:08:12 -04:00
const float pad_bot = ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickLabels ) ? txt_height + txt_off : 0 ) + ( x_label ? txt_height + txt_off : 0 ) ;
2020-06-04 01:11:43 -04:00
YPadCalculator y_axis_pad ( gp . Y , max_label_width , txt_off ) ;
2020-05-11 07:12:22 -04:00
const float pad_left = y_axis_pad ( 0 ) + ( y_label ? txt_height + txt_off : 0 ) ;
const float pad_right = y_axis_pad ( 1 ) + y_axis_pad ( 2 ) ;
2020-06-04 10:56:50 -04:00
gp . BB_Plot = ImRect ( gp . BB_Canvas . Min + ImVec2 ( pad_left , pad_top ) , gp . BB_Canvas . Max - ImVec2 ( pad_right , pad_bot ) ) ;
gp . Hov_Plot = gp . BB_Plot . Contains ( IO . MousePos ) ;
2020-04-27 11:27:59 -04:00
// axis region bbs
2020-06-04 10:56:50 -04:00
const ImRect xAxisRegion_bb ( gp . BB_Plot . Min + ImVec2 ( 10 , 0 ) , ImVec2 ( gp . BB_Plot . Max . x , gp . BB_Frame . Max . y ) - ImVec2 ( 10 , 0 ) ) ;
2020-04-27 11:27:59 -04:00
const bool hov_x_axis_region = xAxisRegion_bb . Contains ( IO . MousePos ) ;
2020-05-11 07:12:22 -04:00
// The left labels are referenced to the left of the bounding box.
2020-06-04 10:56:50 -04:00
gp . AxisLabelReference [ 0 ] = gp . BB_Plot . Min . x ;
2020-05-11 07:12:22 -04:00
// If Y axis 1 is present, its labels will be referenced to the
// right of the bounding box.
2020-06-04 10:56:50 -04:00
gp . AxisLabelReference [ 1 ] = gp . BB_Plot . Max . x ;
2020-05-11 07:12:22 -04:00
// The third axis may be either referenced to the right of the
// bounding box, or 6 pixels further past the end of the 2nd axis.
gp . AxisLabelReference [ 2 ] =
2020-06-04 10:56:50 -04:00
! gp . Y [ 1 ] . Present ?
gp . BB_Plot . Max . x :
2020-05-11 07:12:22 -04:00
( gp . AxisLabelReference [ 1 ] + y_axis_pad ( 1 ) + 6 ) ;
ImRect yAxisRegion_bb [ MAX_Y_AXES ] ;
2020-06-04 10:56:50 -04:00
yAxisRegion_bb [ 0 ] = ImRect ( ImVec2 ( gp . BB_Frame . Min . x , gp . BB_Plot . Min . y ) , ImVec2 ( gp . BB_Plot . Min . x + 6 , gp . BB_Plot . Max . y - 10 ) ) ;
2020-05-11 07:12:22 -04:00
// The auxiliary y axes are off to the right of the BB grid.
2020-06-04 10:56:50 -04:00
yAxisRegion_bb [ 1 ] = ImRect ( ImVec2 ( gp . BB_Plot . Max . x - 6 , gp . BB_Plot . Min . y ) ,
gp . BB_Plot . Max + ImVec2 ( y_axis_pad ( 1 ) , 0 ) ) ;
yAxisRegion_bb [ 2 ] = ImRect ( ImVec2 ( gp . AxisLabelReference [ 2 ] - 6 , gp . BB_Plot . Min . y ) ,
2020-05-11 07:12:22 -04:00
yAxisRegion_bb [ 1 ] . Max + ImVec2 ( y_axis_pad ( 2 ) , 0 ) ) ;
2020-06-04 10:56:50 -04:00
ImRect centralRegion ( ImVec2 ( gp . BB_Plot . Min . x + 6 , gp . BB_Plot . Min . y ) ,
ImVec2 ( gp . BB_Plot . Max . x - 6 , gp . BB_Plot . Max . y ) ) ;
2020-05-13 10:11:25 -04:00
2020-05-11 07:12:22 -04:00
const bool hov_y_axis_region [ MAX_Y_AXES ] = {
2020-06-04 10:56:50 -04:00
gp . Y [ 0 ] . Present & & ( yAxisRegion_bb [ 0 ] . Contains ( IO . MousePos ) | | centralRegion . Contains ( IO . MousePos ) ) ,
gp . Y [ 1 ] . Present & & ( yAxisRegion_bb [ 1 ] . Contains ( IO . MousePos ) | | centralRegion . Contains ( IO . MousePos ) ) ,
gp . Y [ 2 ] . Present & & ( yAxisRegion_bb [ 2 ] . Contains ( IO . MousePos ) | | centralRegion . Contains ( IO . MousePos ) ) ,
2020-05-11 07:12:22 -04:00
} ;
const bool any_hov_y_axis_region = hov_y_axis_region [ 0 ] | | hov_y_axis_region [ 1 ] | | hov_y_axis_region [ 2 ] ;
2020-04-27 11:27:59 -04:00
// legend hovered from last frame
2020-05-13 10:11:25 -04:00
const bool hov_legend = HasFlag ( plot . Flags , ImPlotFlags_Legend ) ? gp . Hov_Frame & & plot . BB_Legend . Contains ( IO . MousePos ) : false ;
2020-04-30 09:45:03 -04:00
bool hov_query = false ;
2020-06-04 10:56:50 -04:00
if ( gp . Hov_Frame & & gp . Hov_Plot & & plot . Queried & & ! plot . Querying ) {
2020-05-11 07:12:22 -04:00
ImRect bb_query = plot . QueryRect ;
2020-06-04 10:56:50 -04:00
bb_query . Min + = gp . BB_Plot . Min ;
bb_query . Max + = gp . BB_Plot . Min ;
2020-05-11 07:12:22 -04:00
2020-04-30 09:45:03 -04:00
hov_query = bb_query . Contains ( IO . MousePos ) ;
}
// QUERY DRAG -------------------------------------------------------------
if ( plot . DraggingQuery & & ( IO . MouseReleased [ 0 ] | | ! IO . MouseDown [ 0 ] ) ) {
plot . DraggingQuery = false ;
}
2020-05-13 10:11:25 -04:00
if ( plot . DraggingQuery ) {
2020-05-12 05:19:04 -04:00
ImGui : : SetMouseCursor ( ImGuiMouseCursor_ResizeAll ) ;
2020-05-11 07:12:22 -04:00
plot . QueryRect . Min + = IO . MouseDelta ;
plot . QueryRect . Max + = IO . MouseDelta ;
2020-04-30 09:45:03 -04:00
}
2020-06-04 10:56:50 -04:00
if ( gp . Hov_Frame & & gp . Hov_Plot & & hov_query & & ! plot . DraggingQuery & & ! plot . Selecting & & ! hov_legend ) {
2020-05-12 05:19:04 -04:00
ImGui : : SetMouseCursor ( ImGuiMouseCursor_ResizeAll ) ;
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot . YAxis [ 0 ] . Dragging | | plot . YAxis [ 1 ] . Dragging | | plot . YAxis [ 2 ] . Dragging ;
if ( IO . MouseDown [ 0 ] & & ! plot . XAxis . Dragging & & ! any_y_dragging ) {
2020-04-30 09:45:03 -04:00
plot . DraggingQuery = true ;
2020-05-13 10:11:25 -04:00
}
}
2020-04-27 11:27:59 -04:00
// DRAG INPUT -------------------------------------------------------------
// end drags
if ( plot . XAxis . Dragging & & ( IO . MouseReleased [ 0 ] | | ! IO . MouseDown [ 0 ] ) ) {
plot . XAxis . Dragging = false ;
2020-05-13 10:11:25 -04:00
G . IO . MouseDragMaxDistanceSqr [ 0 ] = 0 ;
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( plot . YAxis [ i ] . Dragging & & ( IO . MouseReleased [ 0 ] | | ! IO . MouseDown [ 0 ] ) ) {
plot . YAxis [ i ] . Dragging = false ;
G . IO . MouseDragMaxDistanceSqr [ 0 ] = 0 ;
}
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot . YAxis [ 0 ] . Dragging | | plot . YAxis [ 1 ] . Dragging | | plot . YAxis [ 2 ] . Dragging ;
2020-05-11 09:57:36 -04:00
bool drag_in_progress = plot . XAxis . Dragging | | any_y_dragging ;
2020-04-27 11:27:59 -04:00
// do drag
2020-05-11 07:12:22 -04:00
if ( drag_in_progress ) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache ( ) ;
2020-06-04 10:56:50 -04:00
if ( ! gp . X . Lock & & plot . XAxis . Dragging ) {
ImPlotPoint plot_tl = PixelsToPlot ( gp . BB_Plot . Min - IO . MouseDelta , 0 ) ;
ImPlotPoint plot_br = PixelsToPlot ( gp . BB_Plot . Max - IO . MouseDelta , 0 ) ;
if ( ! gp . X . LockMin )
plot . XAxis . Range . Min = gp . X . Invert ? plot_br . x : plot_tl . x ;
if ( ! gp . X . LockMax )
plot . XAxis . Range . Max = gp . X . Invert ? plot_tl . x : plot_br . x ;
2020-05-11 07:12:22 -04:00
}
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . Lock & & plot . YAxis [ i ] . Dragging ) {
ImPlotPoint plot_tl = PixelsToPlot ( gp . BB_Plot . Min - IO . MouseDelta , i ) ;
ImPlotPoint plot_br = PixelsToPlot ( gp . BB_Plot . Max - IO . MouseDelta , i ) ;
if ( ! gp . Y [ i ] . LockMin )
plot . YAxis [ i ] . Range . Min = gp . Y [ i ] . Invert ? plot_tl . y : plot_br . y ;
if ( ! gp . Y [ i ] . LockMax )
plot . YAxis [ i ] . Range . Max = gp . Y [ i ] . Invert ? plot_br . y : plot_tl . y ;
2020-05-11 07:12:22 -04:00
}
}
// Set the mouse cursor based on which axes are moving.
int direction = 0 ;
2020-06-04 10:56:50 -04:00
if ( ! gp . X . Lock & & plot . XAxis . Dragging ) {
2020-05-11 07:12:22 -04:00
direction | = ( 1 < < 1 ) ;
}
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . Present ) { continue ; }
if ( ! gp . Y [ i ] . Lock & & plot . YAxis [ i ] . Dragging ) {
2020-05-11 07:12:22 -04:00
direction | = ( 1 < < 2 ) ;
break ;
}
}
2020-06-06 18:54:46 -04:00
if ( IO . MouseDragMaxDistanceSqr [ 0 ] > 5 ) {
if ( direction = = 0 ) {
ImGui : : SetMouseCursor ( ImGuiMouseCursor_NotAllowed ) ;
}
else if ( direction = = ( 1 < < 1 ) ) {
ImGui : : SetMouseCursor ( ImGuiMouseCursor_ResizeEW ) ;
}
else if ( direction = = ( 1 < < 2 ) ) {
ImGui : : SetMouseCursor ( ImGuiMouseCursor_ResizeNS ) ;
}
else {
ImGui : : SetMouseCursor ( ImGuiMouseCursor_ResizeAll ) ;
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
// start drag
2020-06-06 18:54:46 -04:00
if ( ! drag_in_progress & & gp . Hov_Frame & & IO . MouseClicked [ 0 ] & & ! plot . Selecting & & ! hov_legend & & ! hov_query & & ! plot . DraggingQuery ) {
2020-05-11 07:12:22 -04:00
if ( hov_x_axis_region ) {
plot . XAxis . Dragging = true ;
}
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( hov_y_axis_region [ i ] ) {
plot . YAxis [ i ] . Dragging = true ;
}
}
}
2020-04-27 11:27:59 -04:00
// SCROLL INPUT -----------------------------------------------------------
2020-05-11 07:12:22 -04:00
if ( gp . Hov_Frame & & ( hov_x_axis_region | | any_hov_y_axis_region ) & & IO . MouseWheel ! = 0 ) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache ( ) ;
2020-04-27 11:27:59 -04:00
float zoom_rate = 0.1f ;
2020-05-13 10:11:25 -04:00
if ( IO . MouseWheel > 0 )
zoom_rate = ( - zoom_rate ) / ( 1.0f + ( 2.0f * zoom_rate ) ) ;
2020-06-04 10:56:50 -04:00
float tx = Remap ( IO . MousePos . x , gp . BB_Plot . Min . x , gp . BB_Plot . Max . x , 0.0f , 1.0f ) ;
float ty = Remap ( IO . MousePos . y , gp . BB_Plot . Min . y , gp . BB_Plot . Max . y , 0.0f , 1.0f ) ;
if ( hov_x_axis_region & & ! gp . X . Lock ) {
2020-05-16 22:09:36 -04:00
ImPlotAxisScale axis_scale ( 0 , tx , ty , zoom_rate ) ;
const ImPlotPoint & plot_tl = axis_scale . Min ;
const ImPlotPoint & plot_br = axis_scale . Max ;
2020-05-11 07:12:22 -04:00
2020-06-04 10:56:50 -04:00
if ( ! gp . X . LockMin )
plot . XAxis . Range . Min = gp . X . Invert ? plot_br . x : plot_tl . x ;
if ( ! gp . X . LockMax )
plot . XAxis . Range . Max = gp . X . Invert ? plot_tl . x : plot_br . x ;
2020-05-11 07:12:22 -04:00
}
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( hov_y_axis_region [ i ] & & ! gp . Y [ i ] . Lock ) {
2020-05-16 22:09:36 -04:00
ImPlotAxisScale axis_scale ( i , tx , ty , zoom_rate ) ;
const ImPlotPoint & plot_tl = axis_scale . Min ;
const ImPlotPoint & plot_br = axis_scale . Max ;
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . LockMin )
plot . YAxis [ i ] . Range . Min = gp . Y [ i ] . Invert ? plot_tl . y : plot_br . y ;
if ( ! gp . Y [ i ] . LockMax )
plot . YAxis [ i ] . Range . Max = gp . Y [ i ] . Invert ? plot_br . y : plot_tl . y ;
2020-05-11 07:12:22 -04:00
}
2020-05-13 10:11:25 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-04-28 21:17:26 -04:00
// BOX-SELECTION AND QUERY ------------------------------------------------
2020-04-27 11:27:59 -04:00
// confirm selection
2020-04-28 21:17:26 -04:00
if ( plot . Selecting & & ( IO . MouseReleased [ 1 ] | | ! IO . MouseDown [ 1 ] ) ) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache ( ) ;
2020-04-28 21:17:26 -04:00
ImVec2 select_size = plot . SelectStart - IO . MousePos ;
2020-05-12 05:19:04 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_BoxSelect ) & & ImFabs ( select_size . x ) > 2 & & ImFabs ( select_size . y ) > 2 ) {
2020-05-16 22:09:36 -04:00
ImPlotPoint p1 = PixelsToPlot ( plot . SelectStart ) ;
ImPlotPoint p2 = PixelsToPlot ( IO . MousePos ) ;
2020-06-04 10:56:50 -04:00
if ( ! gp . X . LockMin & & ! IO . KeyAlt )
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Min = ImMin ( p1 . x , p2 . x ) ;
2020-06-04 10:56:50 -04:00
if ( ! gp . X . LockMax & & ! IO . KeyAlt )
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Max = ImMax ( p1 . x , p2 . x ) ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
p1 = PixelsToPlot ( plot . SelectStart , i ) ;
p2 = PixelsToPlot ( IO . MousePos , i ) ;
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . LockMin & & ! IO . KeyShift )
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Min = ImMin ( p1 . y , p2 . y ) ;
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . LockMax & & ! IO . KeyShift )
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Max = ImMax ( p1 . y , p2 . y ) ;
}
2020-05-13 10:11:25 -04:00
}
2020-04-27 11:27:59 -04:00
plot . Selecting = false ;
}
// bad selection
2020-06-03 15:37:01 -04:00
if ( plot . Selecting & & ( ! HasFlag ( plot . Flags , ImPlotFlags_BoxSelect ) | | gp . LockPlot ) & & ImLengthSqr ( plot . SelectStart - IO . MousePos ) > 4 ) {
2020-04-27 11:27:59 -04:00
ImGui : : SetMouseCursor ( ImGuiMouseCursor_NotAllowed ) ;
}
// cancel selection
2020-04-28 21:17:26 -04:00
if ( plot . Selecting & & ( IO . MouseClicked [ 0 ] | | IO . MouseDown [ 0 ] ) ) {
2020-04-27 11:27:59 -04:00
plot . Selecting = false ;
}
2020-04-28 00:57:49 -04:00
// begin selection or query
2020-06-04 10:56:50 -04:00
if ( gp . Hov_Frame & & gp . Hov_Plot & & IO . MouseClicked [ 1 ] ) {
2020-04-27 11:27:59 -04:00
plot . SelectStart = IO . MousePos ;
2020-04-28 21:17:26 -04:00
plot . Selecting = true ;
}
// update query
if ( plot . Querying ) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache ( ) ;
2020-06-04 10:56:50 -04:00
plot . QueryRect . Min . x = IO . KeyAlt ? gp . BB_Plot . Min . x : ImMin ( plot . QueryStart . x , IO . MousePos . x ) ;
plot . QueryRect . Max . x = IO . KeyAlt ? gp . BB_Plot . Max . x : ImMax ( plot . QueryStart . x , IO . MousePos . x ) ;
plot . QueryRect . Min . y = IO . KeyShift ? gp . BB_Plot . Min . y : ImMin ( plot . QueryStart . y , IO . MousePos . y ) ;
plot . QueryRect . Max . y = IO . KeyShift ? gp . BB_Plot . Max . y : ImMax ( plot . QueryStart . y , IO . MousePos . y ) ;
2020-05-11 07:12:22 -04:00
2020-06-04 10:56:50 -04:00
plot . QueryRect . Min - = gp . BB_Plot . Min ;
plot . QueryRect . Max - = gp . BB_Plot . Min ;
2020-04-28 21:17:26 -04:00
}
// end query
if ( plot . Querying & & ( IO . MouseReleased [ 2 ] | | IO . MouseReleased [ 1 ] ) ) {
plot . Querying = false ;
if ( plot . QueryRect . GetWidth ( ) > 2 & & plot . QueryRect . GetHeight ( ) > 2 ) {
plot . Queried = true ;
}
else {
plot . Queried = false ;
}
2020-04-28 00:57:49 -04:00
}
// begin query
2020-06-04 10:56:50 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_Query ) & & ( gp . Hov_Frame & & gp . Hov_Plot & & IO . MouseClicked [ 2 ] ) ) {
2020-04-28 21:17:26 -04:00
plot . QueryRect = ImRect ( 0 , 0 , 0 , 0 ) ;
plot . Querying = true ;
plot . Queried = true ;
plot . QueryStart = IO . MousePos ;
}
// toggle between select/query
2020-05-11 07:12:22 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_Query ) & & plot . Selecting & & IO . KeyCtrl ) {
2020-04-28 21:17:26 -04:00
plot . Selecting = false ;
plot . QueryRect = ImRect ( 0 , 0 , 0 , 0 ) ;
2020-04-28 00:57:49 -04:00
plot . Querying = true ;
2020-04-28 21:17:26 -04:00
plot . Queried = true ;
plot . QueryStart = plot . SelectStart ;
}
2020-05-12 05:19:04 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_BoxSelect ) & & plot . Querying & & ! IO . KeyCtrl & & ! IO . MouseDown [ 2 ] ) {
2020-04-28 21:17:26 -04:00
plot . Selecting = true ;
plot . Querying = false ;
plot . Queried = false ;
plot . QueryRect = ImRect ( 0 , 0 , 0 , 0 ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-13 10:11:25 -04:00
2020-04-27 11:27:59 -04:00
// DOUBLE CLICK -----------------------------------------------------------
2020-05-11 07:12:22 -04:00
if ( IO . MouseDoubleClicked [ 0 ] & & gp . Hov_Frame & & ( hov_x_axis_region | | any_hov_y_axis_region ) & & ! hov_legend & & ! hov_query ) {
2020-04-27 11:27:59 -04:00
gp . FitThisFrame = true ;
2020-04-30 09:13:44 -04:00
gp . FitX = hov_x_axis_region ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
gp . FitY [ i ] = hov_y_axis_region [ i ] ;
}
2020-04-30 09:13:44 -04:00
}
else {
2020-05-13 10:11:25 -04:00
gp . FitThisFrame = false ;
2020-04-30 09:13:44 -04:00
gp . FitX = false ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
gp . FitY [ i ] = false ;
}
2020-04-30 09:13:44 -04:00
}
2020-04-27 11:27:59 -04:00
// FOCUS ------------------------------------------------------------------
// focus window
if ( ( IO . MouseClicked [ 0 ] | | IO . MouseClicked [ 1 ] ) & & gp . Hov_Frame )
2020-05-13 10:11:25 -04:00
ImGui : : FocusWindow ( ImGui : : GetCurrentWindow ( ) ) ;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
UpdateTransformCache ( ) ;
2020-04-27 11:27:59 -04:00
// set mouse position
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
gp . LastMousePos [ i ] = PixelsToPlot ( IO . MousePos , i ) ;
}
2020-04-27 11:27:59 -04:00
// RENDER -----------------------------------------------------------------
// grid bg
2020-06-04 10:56:50 -04:00
DrawList . AddRectFilled ( gp . BB_Plot . Min , gp . BB_Plot . Max , gp . Col_Bg ) ;
2020-04-27 11:27:59 -04:00
// render axes
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
// transform ticks
if ( gp . RenderX ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . XTicks . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * xt = & gp . XTicks [ t ] ;
2020-05-29 13:39:30 -04:00
xt - > PixelPos = PlotToPixels ( xt - > PlotPos , 0 , 0 ) . x ;
2020-05-13 00:45:34 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( gp . RenderY [ i ] ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . YTicks [ i ] . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * yt = & gp . YTicks [ i ] [ t ] ;
2020-05-16 22:53:59 -04:00
yt - > PixelPos = PlotToPixels ( 0 , yt - > PlotPos , i ) . y ;
2020-05-13 00:45:34 -04:00
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
// render grid
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_GridLines ) ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . XTicks . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * xt = & gp . XTicks [ t ] ;
2020-06-04 10:56:50 -04:00
DrawList . AddLine ( ImVec2 ( xt - > PixelPos , gp . BB_Plot . Min . y ) , ImVec2 ( xt - > PixelPos , gp . BB_Plot . Max . y ) , xt - > Major ? gp . Col_X . Major : gp . Col_X . Minor , 1 ) ;
2020-05-13 00:45:34 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( gp . Y [ i ] . Present & & HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_GridLines ) ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . YTicks [ i ] . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * yt = & gp . YTicks [ i ] [ t ] ;
2020-06-04 10:56:50 -04:00
DrawList . AddLine ( ImVec2 ( gp . BB_Plot . Min . x , yt - > PixelPos ) , ImVec2 ( gp . BB_Plot . Max . x , yt - > PixelPos ) , yt - > Major ? gp . Col_Y [ i ] . Major : gp . Col_Y [ i ] . Minor , 1 ) ;
2020-05-13 00:45:34 -04:00
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
// render title
if ( title_size . x > 0.0f ) {
2020-05-12 05:19:04 -04:00
ImGui : : RenderText ( ImVec2 ( gp . BB_Canvas . GetCenter ( ) . x - title_size . x * 0.5f , gp . BB_Canvas . Min . y ) , title , NULL , true ) ;
2020-04-27 11:27:59 -04:00
}
// render labels
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickLabels ) ) {
2020-05-12 05:19:04 -04:00
ImGui : : PushClipRect ( gp . BB_Frame . Min , gp . BB_Frame . Max , true ) ;
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . XTicks . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * xt = & gp . XTicks [ t ] ;
2020-06-04 10:56:50 -04:00
if ( xt - > RenderLabel & & xt - > PixelPos > = gp . BB_Plot . Min . x - 1 & & xt - > PixelPos < = gp . BB_Plot . Max . x + 1 )
DrawList . AddText ( ImVec2 ( xt - > PixelPos - xt - > Size . x * 0.5f , gp . BB_Plot . Max . y + txt_off ) , gp . Col_X . Txt , gp . XTickLabels . Buf . Data + xt - > TextOffset ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
ImGui : : PopClipRect ( ) ;
2020-04-27 11:27:59 -04:00
}
if ( x_label ) {
2020-05-12 05:19:04 -04:00
const ImVec2 xLabel_size = ImGui : : CalcTextSize ( x_label ) ;
2020-06-04 10:56:50 -04:00
const ImVec2 xLabel_pos ( gp . BB_Plot . GetCenter ( ) . x - xLabel_size . x * 0.5f ,
2020-04-27 11:27:59 -04:00
gp . BB_Canvas . Max . y - txt_height ) ;
2020-05-11 07:12:22 -04:00
DrawList . AddText ( xLabel_pos , gp . Col_X . Txt , x_label ) ;
}
2020-05-12 05:19:04 -04:00
ImGui : : PushClipRect ( gp . BB_Frame . Min , gp . BB_Frame . Max , true ) ;
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( gp . Y [ i ] . Present & & HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_TickLabels ) ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . YTicks [ i ] . Size ; t + + ) {
2020-06-04 10:56:50 -04:00
const float x_start = gp . AxisLabelReference [ i ] + ( i = = 0 ? ( - txt_off - gp . YTicks [ i ] [ t ] . Size . x ) : txt_off ) ;
2020-06-03 10:54:25 -04:00
ImPlotTick * yt = & gp . YTicks [ i ] [ t ] ;
2020-06-04 10:56:50 -04:00
if ( yt - > RenderLabel & & yt - > PixelPos > = gp . BB_Plot . Min . y - 1 & & yt - > PixelPos < = gp . BB_Plot . Max . y + 1 ) {
2020-05-13 00:45:34 -04:00
ImVec2 start ( x_start , yt - > PixelPos - 0.5f * yt - > Size . y ) ;
DrawList . AddText ( start , gp . Col_Y [ i ] . Txt , gp . YTickLabels [ i ] . Buf . Data + yt - > TextOffset ) ;
2020-05-11 07:12:22 -04:00
}
}
2020-04-27 11:27:59 -04:00
}
}
2020-05-12 05:19:04 -04:00
ImGui : : PopClipRect ( ) ;
2020-04-27 11:27:59 -04:00
if ( y_label ) {
const ImVec2 yLabel_size = CalcTextSizeVertical ( y_label ) ;
2020-06-04 10:56:50 -04:00
const ImVec2 yLabel_pos ( gp . BB_Canvas . Min . x , gp . BB_Plot . GetCenter ( ) . y + yLabel_size . y * 0.5f ) ;
2020-05-11 07:12:22 -04:00
AddTextVertical ( & DrawList , y_label , yLabel_pos , gp . Col_Y [ 0 ] . Txt ) ;
2020-04-27 11:27:59 -04:00
}
// PREP -------------------------------------------------------------------
// push plot ID into stack
2020-05-12 05:19:04 -04:00
ImGui : : PushID ( ID ) ;
2020-04-27 11:27:59 -04:00
return true ;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// Context Menu
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-17 00:25:15 -04:00
template < typename F >
2020-06-02 23:07:27 -04:00
bool DragFloat ( const char * label , F * v , float v_speed , F v_min , F v_max ) {
2020-05-17 00:25:15 -04:00
return false ;
}
template < >
2020-06-02 23:07:27 -04:00
bool DragFloat < double > ( const char * label , double * v , float v_speed , double v_min , double v_max ) {
2020-05-17 00:25:15 -04:00
return ImGui : : DragScalar ( label , ImGuiDataType_Double , v , v_speed , & v_min , & v_max , " %.3f " , 1 ) ;
}
2020-05-16 22:09:36 -04:00
2020-05-17 00:25:15 -04:00
template < >
2020-06-02 23:07:27 -04:00
bool DragFloat < float > ( const char * label , float * v , float v_speed , float v_min , float v_max ) {
2020-05-17 00:25:15 -04:00
return ImGui : : DragScalar ( label , ImGuiDataType_Float , v , v_speed , & v_min , & v_max , " %.3f " , 1 ) ;
2020-05-16 22:09:36 -04:00
}
2020-06-04 01:11:43 -04:00
inline void BeginDisabledControls ( bool cond ) {
if ( cond ) {
ImGui : : PushItemFlag ( ImGuiItemFlags_Disabled , true ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , ImGui : : GetStyle ( ) . Alpha * 0.25f ) ;
}
}
inline void EndDisabledControls ( bool cond ) {
if ( cond ) {
ImGui : : PopItemFlag ( ) ;
ImGui : : PopStyleVar ( ) ;
}
}
2020-06-04 10:56:50 -04:00
inline void AxisMenu ( ImPlotAxisState & state ) {
2020-06-04 01:11:43 -04:00
ImGui : : PushItemWidth ( 75 ) ;
2020-06-04 10:56:50 -04:00
bool total_lock = state . HasRange & & state . RangeCond = = ImGuiCond_Always ;
bool logscale = HasFlag ( state . Axis - > Flags , ImPlotAxisFlags_LogScale ) ;
bool grid = HasFlag ( state . Axis - > Flags , ImPlotAxisFlags_GridLines ) ;
bool ticks = HasFlag ( state . Axis - > Flags , ImPlotAxisFlags_TickMarks ) ;
bool labels = HasFlag ( state . Axis - > Flags , ImPlotAxisFlags_TickLabels ) ;
2020-06-04 01:11:43 -04:00
BeginDisabledControls ( total_lock ) ;
2020-06-04 10:56:50 -04:00
if ( ImGui : : Checkbox ( " ##LockMin " , & state . LockMin ) )
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_LockMin ) ;
2020-06-04 01:11:43 -04:00
EndDisabledControls ( total_lock ) ;
2020-04-27 11:27:59 -04:00
ImGui : : SameLine ( ) ;
2020-06-04 10:56:50 -04:00
BeginDisabledControls ( state . LockMin ) ;
DragFloat ( " Min " , & state . Axis - > Range . Min , 0.01f * ( float ) state . Axis - > Range . Size ( ) , - HUGE_VAL , state . Axis - > Range . Max - DBL_EPSILON ) ;
EndDisabledControls ( state . LockMin ) ;
2020-04-27 11:27:59 -04:00
2020-06-04 01:11:43 -04:00
BeginDisabledControls ( total_lock ) ;
2020-06-04 10:56:50 -04:00
if ( ImGui : : Checkbox ( " ##LockMax " , & state . LockMax ) )
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_LockMax ) ;
2020-06-04 01:11:43 -04:00
EndDisabledControls ( total_lock ) ;
2020-04-27 11:27:59 -04:00
ImGui : : SameLine ( ) ;
2020-06-04 10:56:50 -04:00
BeginDisabledControls ( state . LockMax ) ;
DragFloat ( " Max " , & state . Axis - > Range . Max , 0.01f * ( float ) state . Axis - > Range . Size ( ) , state . Axis - > Range . Min + DBL_EPSILON , HUGE_VAL ) ;
EndDisabledControls ( state . LockMax ) ;
2020-06-04 01:11:43 -04:00
2020-04-27 11:27:59 -04:00
ImGui : : Separator ( ) ;
2020-06-04 01:11:43 -04:00
2020-06-04 10:56:50 -04:00
if ( ImGui : : Checkbox ( " Invert " , & state . Invert ) )
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_Invert ) ;
2020-04-27 11:27:59 -04:00
if ( ImGui : : Checkbox ( " Log Scale " , & logscale ) )
2020-06-04 10:56:50 -04:00
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_LogScale ) ;
2020-04-27 11:27:59 -04:00
ImGui : : Separator ( ) ;
if ( ImGui : : Checkbox ( " Grid Lines " , & grid ) )
2020-06-04 10:56:50 -04:00
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_GridLines ) ;
2020-04-27 11:27:59 -04:00
if ( ImGui : : Checkbox ( " Tick Marks " , & ticks ) )
2020-06-04 10:56:50 -04:00
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_TickMarks ) ;
2020-04-27 11:27:59 -04:00
if ( ImGui : : Checkbox ( " Labels " , & labels ) )
2020-06-04 10:56:50 -04:00
FlipFlag ( state . Axis - > Flags , ImPlotAxisFlags_TickLabels ) ;
2020-06-04 01:11:43 -04:00
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PlotContextMenu ( ImPlotState & plot ) {
2020-05-13 10:11:25 -04:00
if ( ImGui : : BeginMenu ( " X-Axis " ) ) {
ImGui : : PushID ( " X " ) ;
2020-06-04 10:56:50 -04:00
AxisMenu ( gp . X ) ;
2020-05-12 05:19:04 -04:00
ImGui : : PopID ( ) ;
2020-04-27 11:27:59 -04:00
ImGui : : EndMenu ( ) ;
}
2020-05-11 07:12:22 -04:00
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
if ( i = = 1 & & ! HasFlag ( plot . Flags , ImPlotFlags_YAxis2 ) ) {
continue ;
}
if ( i = = 2 & & ! HasFlag ( plot . Flags , ImPlotFlags_YAxis3 ) ) {
continue ;
}
char buf [ 10 ] = { } ;
if ( i = = 0 ) {
snprintf ( buf , sizeof ( buf ) - 1 , " Y-Axis " ) ;
} else {
snprintf ( buf , sizeof ( buf ) - 1 , " Y-Axis %d " , i + 1 ) ;
}
if ( ImGui : : BeginMenu ( buf ) ) {
2020-05-13 10:11:25 -04:00
ImGui : : PushID ( i ) ;
2020-06-04 10:56:50 -04:00
AxisMenu ( gp . Y [ i ] ) ;
2020-05-12 05:19:04 -04:00
ImGui : : PopID ( ) ;
2020-05-11 07:12:22 -04:00
ImGui : : EndMenu ( ) ;
}
2020-04-27 11:27:59 -04:00
}
2020-05-13 10:11:25 -04:00
2020-04-27 11:27:59 -04:00
ImGui : : Separator ( ) ;
if ( ( ImGui : : BeginMenu ( " Settings " ) ) ) {
2020-05-12 05:19:04 -04:00
if ( ImGui : : MenuItem ( " Box Select " , NULL , HasFlag ( plot . Flags , ImPlotFlags_BoxSelect ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_BoxSelect ) ;
}
if ( ImGui : : MenuItem ( " Query " , NULL , HasFlag ( plot . Flags , ImPlotFlags_Query ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_Query ) ;
2020-04-27 11:27:59 -04:00
}
2020-04-28 21:17:26 -04:00
if ( ImGui : : MenuItem ( " Crosshairs " , NULL , HasFlag ( plot . Flags , ImPlotFlags_Crosshairs ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_Crosshairs ) ;
2020-04-27 11:27:59 -04:00
}
if ( ImGui : : MenuItem ( " Mouse Position " , NULL , HasFlag ( plot . Flags , ImPlotFlags_MousePos ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_MousePos ) ;
}
2020-04-28 21:17:26 -04:00
if ( ImGui : : MenuItem ( " Cull Data " , NULL , HasFlag ( plot . Flags , ImPlotFlags_CullData ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_CullData ) ;
}
if ( ImGui : : MenuItem ( " Anti-Aliased Lines " , NULL , HasFlag ( plot . Flags , ImPlotFlags_AntiAliased ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_AntiAliased ) ;
2020-04-27 11:27:59 -04:00
}
ImGui : : EndMenu ( ) ;
}
if ( ImGui : : MenuItem ( " Legend " , NULL , HasFlag ( plot . Flags , ImPlotFlags_Legend ) ) ) {
FlipFlag ( plot . Flags , ImPlotFlags_Legend ) ;
}
#if 0
if ( ImGui : : BeginMenu ( " Metrics " ) ) {
ImGui : : PushItemWidth ( 75 ) ;
ImGui : : LabelText ( " Plots " , " %d " , gp . Plots . GetSize ( ) ) ;
ImGui : : LabelText ( " Color Modifiers " , " %d " , gp . ColorModifiers . size ( ) ) ;
ImGui : : LabelText ( " Style Modifiers " , " %d " , gp . StyleModifiers . size ( ) ) ;
ImGui : : PopItemWidth ( ) ;
ImGui : : EndMenu ( ) ;
}
# endif
}
2020-05-11 07:12:22 -04:00
namespace {
class BufferWriter {
public :
BufferWriter ( char * buffer , size_t size ) : Buffer ( buffer ) , Pos ( 0 ) , Size ( size ) { }
void Write ( const char * fmt , . . . ) IM_FMTARGS ( 2 ) {
va_list argp ;
va_start ( argp , fmt ) ;
VWrite ( fmt , argp ) ;
va_end ( argp ) ;
}
private :
void VWrite ( const char * fmt , va_list argp ) {
const int written = : : vsnprintf ( & Buffer [ Pos ] , Size - Pos - 1 , fmt , argp ) ;
2020-05-12 12:49:21 -04:00
if ( written > 0 )
Pos + = ImMin ( size_t ( written ) , Size - Pos - 1 ) ;
2020-05-11 07:12:22 -04:00
}
char * const Buffer ;
size_t Pos ;
const size_t Size ;
} ;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// EndPlot()
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
void EndPlot ( ) {
2020-05-13 10:11:25 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " Mismatched BeginPlot()/EndPlot()! " ) ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
ImPlotState & plot = * gp . CurrentPlot ;
2020-04-27 11:27:59 -04:00
ImGuiContext & G = * GImGui ;
ImGuiWindow * Window = G . CurrentWindow ;
ImDrawList & DrawList = * Window - > DrawList ;
2020-05-12 05:19:04 -04:00
const ImGuiIO & IO = ImGui : : GetIO ( ) ;
2020-04-27 11:27:59 -04:00
// AXIS STATES ------------------------------------------------------------
2020-06-04 10:56:50 -04:00
const bool any_y_locked = gp . Y [ 0 ] . Lock | | gp . Y [ 1 ] . Present ? gp . Y [ 1 ] . Lock : false | | gp . Y [ 2 ] . Present ? gp . Y [ 2 ] . Lock : false ;
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot . YAxis [ 0 ] . Dragging | | plot . YAxis [ 1 ] . Dragging | | plot . YAxis [ 2 ] . Dragging ;
2020-04-27 11:27:59 -04:00
2020-06-03 15:37:01 -04:00
2020-04-27 11:27:59 -04:00
// FINAL RENDER -----------------------------------------------------------
2020-04-28 21:17:26 -04:00
// render ticks
2020-05-11 07:12:22 -04:00
PushPlotClipRect ( ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_TickMarks ) ) {
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . XTicks . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * xt = & gp . XTicks [ t ] ;
2020-06-04 10:56:50 -04:00
DrawList . AddLine ( ImVec2 ( xt - > PixelPos , gp . BB_Plot . Max . y ) , ImVec2 ( xt - > PixelPos , gp . BB_Plot . Max . y - ( xt - > Major ? 10.0f : 5.0f ) ) , gp . Col_Border , 1 ) ;
2020-05-13 00:45:34 -04:00
}
2020-04-28 21:17:26 -04:00
}
2020-05-11 07:12:22 -04:00
PopPlotClipRect ( ) ;
2020-06-04 10:56:50 -04:00
ImGui : : PushClipRect ( gp . BB_Plot . Min , ImVec2 ( gp . BB_Frame . Max . x , gp . BB_Plot . Max . y ) , true ) ;
2020-05-11 07:12:22 -04:00
int axis_count = 0 ;
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-06-04 10:56:50 -04:00
if ( ! gp . Y [ i ] . Present ) { continue ; }
2020-05-11 07:12:22 -04:00
axis_count + + ;
2020-05-13 10:08:12 -04:00
if ( ! HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_TickMarks ) ) { continue ; }
2020-05-11 07:12:22 -04:00
float x_start = gp . AxisLabelReference [ i ] ;
float direction = ( i = = 0 ) ? 1.0f : - 1.0f ;
bool no_major = axis_count > = 3 ;
2020-05-13 00:45:34 -04:00
for ( int t = 0 ; t < gp . YTicks [ i ] . Size ; t + + ) {
2020-06-03 10:54:25 -04:00
ImPlotTick * yt = & gp . YTicks [ i ] [ t ] ;
2020-05-13 00:45:34 -04:00
ImVec2 start = ImVec2 ( x_start , yt - > PixelPos ) ;
2020-05-11 07:12:22 -04:00
DrawList . AddLine (
start ,
2020-05-13 00:45:34 -04:00
start + ImVec2 ( direction * ( ( ! no_major & & yt - > Major ) ? 10.0f : 5.0f ) , 0 ) ,
2020-05-11 07:12:22 -04:00
gp . Col_Border , 1 ) ;
}
if ( axis_count > = 3 ) {
// Draw a bar next to the ticks to act as a visual separator.
DrawList . AddLine (
2020-06-04 10:56:50 -04:00
ImVec2 ( x_start , gp . BB_Plot . Min . y ) ,
ImVec2 ( x_start , gp . BB_Plot . Max . y ) ,
2020-05-11 07:12:22 -04:00
gp . Col_Border , 1 ) ;
}
2020-04-28 21:17:26 -04:00
}
2020-05-12 05:19:04 -04:00
ImGui : : PopClipRect ( ) ;
2020-05-11 07:12:22 -04:00
PushPlotClipRect ( ) ;
2020-04-28 21:17:26 -04:00
// render selection/query
if ( plot . Selecting ) {
ImRect select_bb ( ImMin ( IO . MousePos , plot . SelectStart ) , ImMax ( IO . MousePos , plot . SelectStart ) ) ;
2020-06-03 15:37:01 -04:00
bool select_big_enough = ImLengthSqr ( select_bb . GetSize ( ) ) > 4 ;
if ( plot . Selecting & & ! gp . LockPlot & & HasFlag ( plot . Flags , ImPlotFlags_BoxSelect ) & & select_big_enough ) {
if ( IO . KeyAlt & & IO . KeyShift ) {
2020-06-04 10:56:50 -04:00
DrawList . AddRectFilled ( gp . BB_Plot . Min , gp . BB_Plot . Max , gp . Col_SlctBg ) ;
DrawList . AddRect ( gp . BB_Plot . Min , gp . BB_Plot . Max , gp . Col_SlctBd ) ;
2020-04-28 21:17:26 -04:00
}
2020-06-04 10:56:50 -04:00
else if ( ( gp . X . Lock | | IO . KeyAlt ) ) {
DrawList . AddRectFilled ( ImVec2 ( gp . BB_Plot . Min . x , select_bb . Min . y ) , ImVec2 ( gp . BB_Plot . Max . x , select_bb . Max . y ) , gp . Col_SlctBg ) ;
DrawList . AddRect ( ImVec2 ( gp . BB_Plot . Min . x , select_bb . Min . y ) , ImVec2 ( gp . BB_Plot . Max . x , select_bb . Max . y ) , gp . Col_SlctBd ) ;
2020-04-28 21:17:26 -04:00
}
2020-06-03 15:37:01 -04:00
else if ( ( any_y_locked | | IO . KeyShift ) ) {
2020-06-04 10:56:50 -04:00
DrawList . AddRectFilled ( ImVec2 ( select_bb . Min . x , gp . BB_Plot . Min . y ) , ImVec2 ( select_bb . Max . x , gp . BB_Plot . Max . y ) , gp . Col_SlctBg ) ;
DrawList . AddRect ( ImVec2 ( select_bb . Min . x , gp . BB_Plot . Min . y ) , ImVec2 ( select_bb . Max . x , gp . BB_Plot . Max . y ) , gp . Col_SlctBd ) ;
2020-04-28 21:17:26 -04:00
}
2020-06-03 15:37:01 -04:00
else {
2020-04-28 21:17:26 -04:00
DrawList . AddRectFilled ( select_bb . Min , select_bb . Max , gp . Col_SlctBg ) ;
DrawList . AddRect ( select_bb . Min , select_bb . Max , gp . Col_SlctBd ) ;
}
}
}
2020-05-11 07:12:22 -04:00
if ( plot . Querying | | plot . Queried ) {
2020-04-28 21:17:26 -04:00
if ( plot . QueryRect . GetWidth ( ) > 2 & & plot . QueryRect . GetHeight ( ) > 2 ) {
2020-06-04 10:56:50 -04:00
DrawList . AddRectFilled ( plot . QueryRect . Min + gp . BB_Plot . Min , plot . QueryRect . Max + gp . BB_Plot . Min , gp . Col_QryBg ) ;
DrawList . AddRect ( plot . QueryRect . Min + gp . BB_Plot . Min , plot . QueryRect . Max + gp . BB_Plot . Min , gp . Col_QryBd ) ;
2020-05-13 10:11:25 -04:00
}
2020-04-28 21:17:26 -04:00
}
else if ( plot . Queried ) {
2020-05-11 07:12:22 -04:00
ImRect bb_query = plot . QueryRect ;
2020-06-04 10:56:50 -04:00
bb_query . Min + = gp . BB_Plot . Min ;
bb_query . Max + = gp . BB_Plot . Min ;
2020-05-11 07:12:22 -04:00
DrawList . AddRectFilled ( bb_query . Min , bb_query . Max , gp . Col_QryBg ) ;
DrawList . AddRect ( bb_query . Min , bb_query . Max , gp . Col_QryBd ) ;
}
2020-04-27 11:27:59 -04:00
// render legend
2020-05-12 05:19:04 -04:00
const float txt_ht = ImGui : : GetTextLineHeight ( ) ;
2020-04-27 11:27:59 -04:00
const ImVec2 legend_offset ( 10 , 10 ) ;
const ImVec2 legend_padding ( 5 , 5 ) ;
const float legend_icon_size = txt_ht ;
ImRect legend_content_bb ;
2020-05-03 01:24:10 -04:00
int nItems = GetLegendCount ( ) ;
2020-04-27 11:27:59 -04:00
bool hov_legend = false ;
if ( HasFlag ( plot . Flags , ImPlotFlags_Legend ) & & nItems > 0 ) {
// get max width
float max_label_width = 0 ;
for ( int i = 0 ; i < nItems ; + + i ) {
2020-05-03 01:24:10 -04:00
const char * label = GetLegendLabel ( i ) ;
2020-05-12 05:19:04 -04:00
ImVec2 labelWidth = ImGui : : CalcTextSize ( label , NULL , true ) ;
2020-04-27 11:27:59 -04:00
max_label_width = labelWidth . x > max_label_width ? labelWidth . x : max_label_width ;
}
2020-06-04 10:56:50 -04:00
legend_content_bb = ImRect ( gp . BB_Plot . Min + legend_offset , gp . BB_Plot . Min + legend_offset + ImVec2 ( max_label_width , nItems * txt_ht ) ) ;
2020-04-27 11:27:59 -04:00
plot . BB_Legend = ImRect ( legend_content_bb . Min , legend_content_bb . Max + legend_padding * 2 + ImVec2 ( legend_icon_size , 0 ) ) ;
hov_legend = HasFlag ( plot . Flags , ImPlotFlags_Legend ) ? gp . Hov_Frame & & plot . BB_Legend . Contains ( IO . MousePos ) : false ;
// render legend box
2020-05-12 05:19:04 -04:00
DrawList . AddRectFilled ( plot . BB_Legend . Min , plot . BB_Legend . Max , ImGui : : GetColorU32 ( ImGuiCol_PopupBg ) ) ;
2020-04-27 11:27:59 -04:00
DrawList . AddRect ( plot . BB_Legend . Min , plot . BB_Legend . Max , gp . Col_Border ) ;
// render each legend item
for ( int i = 0 ; i < nItems ; + + i ) {
2020-05-03 01:24:10 -04:00
ImPlotItem * item = GetLegendItem ( i ) ;
2020-04-27 11:27:59 -04:00
ImRect icon_bb ;
icon_bb . Min = legend_content_bb . Min + legend_padding + ImVec2 ( 0 , i * txt_ht ) + ImVec2 ( 2 , 2 ) ;
icon_bb . Max = legend_content_bb . Min + legend_padding + ImVec2 ( 0 , i * txt_ht ) + ImVec2 ( legend_icon_size - 2 , legend_icon_size - 2 ) ;
2020-04-28 01:38:52 -04:00
ImRect label_bb ;
label_bb . Min = legend_content_bb . Min + legend_padding + ImVec2 ( 0 , i * txt_ht ) + ImVec2 ( 2 , 2 ) ;
label_bb . Max = legend_content_bb . Min + legend_padding + ImVec2 ( 0 , i * txt_ht ) + ImVec2 ( legend_content_bb . Max . x , legend_icon_size - 2 ) ;
ImU32 col_hl_txt ;
if ( HasFlag ( plot . Flags , ImPlotFlags_Highlight ) & & hov_legend & & ( icon_bb . Contains ( IO . MousePos ) | | label_bb . Contains ( IO . MousePos ) ) ) {
item - > Highlight = true ;
2020-05-12 05:19:04 -04:00
col_hl_txt = ImGui : : GetColorU32 ( ImLerp ( G . Style . Colors [ ImGuiCol_Text ] , item - > Color , 0.25f ) ) ;
2020-04-28 01:38:52 -04:00
}
else
2020-05-10 22:43:12 -04:00
{
item - > Highlight = false ;
col_hl_txt = gp . Col_Txt ;
}
2020-04-27 11:27:59 -04:00
ImU32 iconColor ;
if ( hov_legend & & icon_bb . Contains ( IO . MousePos ) ) {
2020-05-11 07:12:22 -04:00
ImVec4 colAlpha = item - > Color ;
2020-04-27 11:27:59 -04:00
colAlpha . w = 0.5f ;
2020-05-12 05:19:04 -04:00
iconColor = item - > Show ? ImGui : : GetColorU32 ( colAlpha )
: ImGui : : GetColorU32 ( ImGuiCol_TextDisabled , 0.5f ) ;
2020-04-27 11:27:59 -04:00
if ( IO . MouseClicked [ 0 ] )
item - > Show = ! item - > Show ;
} else {
2020-05-12 05:19:04 -04:00
iconColor = item - > Show ? ImGui : : GetColorU32 ( item - > Color ) : gp . Col_TxtDis ;
2020-04-27 11:27:59 -04:00
}
DrawList . AddRectFilled ( icon_bb . Min , icon_bb . Max , iconColor , 1 ) ;
2020-05-03 01:24:10 -04:00
const char * label = GetLegendLabel ( i ) ;
2020-05-12 05:19:04 -04:00
const char * text_display_end = ImGui : : FindRenderedTextEnd ( label , NULL ) ;
2020-04-27 11:27:59 -04:00
if ( label ! = text_display_end )
2020-05-10 22:43:12 -04:00
DrawList . AddText ( legend_content_bb . Min + legend_padding + ImVec2 ( legend_icon_size , i * txt_ht ) , item - > Show ? col_hl_txt : gp . Col_TxtDis , label , text_display_end ) ;
2020-04-27 11:27:59 -04:00
}
}
// render crosshairs
2020-06-04 10:56:50 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_Crosshairs ) & & gp . Hov_Plot & & gp . Hov_Frame & &
2020-05-11 07:12:22 -04:00
! ( plot . XAxis . Dragging | | any_y_dragging ) & & ! plot . Selecting & & ! plot . Querying & & ! hov_legend ) {
2020-04-27 11:27:59 -04:00
ImGui : : SetMouseCursor ( ImGuiMouseCursor_None ) ;
ImVec2 xy = IO . MousePos ;
2020-06-04 10:56:50 -04:00
ImVec2 h1 ( gp . BB_Plot . Min . x , xy . y ) ;
2020-04-27 11:27:59 -04:00
ImVec2 h2 ( xy . x - 5 , xy . y ) ;
ImVec2 h3 ( xy . x + 5 , xy . y ) ;
2020-06-04 10:56:50 -04:00
ImVec2 h4 ( gp . BB_Plot . Max . x , xy . y ) ;
ImVec2 v1 ( xy . x , gp . BB_Plot . Min . y ) ;
2020-04-27 11:27:59 -04:00
ImVec2 v2 ( xy . x , xy . y - 5 ) ;
ImVec2 v3 ( xy . x , xy . y + 5 ) ;
2020-06-04 10:56:50 -04:00
ImVec2 v4 ( xy . x , gp . BB_Plot . Max . y ) ;
2020-04-27 11:27:59 -04:00
DrawList . AddLine ( h1 , h2 , gp . Col_Border ) ;
DrawList . AddLine ( h3 , h4 , gp . Col_Border ) ;
DrawList . AddLine ( v1 , v2 , gp . Col_Border ) ;
DrawList . AddLine ( v3 , v4 , gp . Col_Border ) ;
}
// render mouse pos
2020-06-04 10:56:50 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_MousePos ) & & gp . Hov_Plot ) {
2020-05-10 22:43:12 -04:00
char buffer [ 128 ] = { } ;
2020-05-11 07:12:22 -04:00
BufferWriter writer ( buffer , sizeof ( buffer ) ) ;
writer . Write ( " %.2f,%.2f " , gp . LastMousePos [ 0 ] . x , gp . LastMousePos [ 0 ] . y ) ;
if ( HasFlag ( plot . Flags , ImPlotFlags_YAxis2 ) ) {
writer . Write ( " ,(%.2f) " , gp . LastMousePos [ 1 ] . y ) ;
}
if ( HasFlag ( plot . Flags , ImPlotFlags_YAxis3 ) ) {
writer . Write ( " ,(%.2f) " , gp . LastMousePos [ 2 ] . y ) ;
}
2020-05-12 05:19:04 -04:00
ImVec2 size = ImGui : : CalcTextSize ( buffer ) ;
2020-06-04 10:56:50 -04:00
ImVec2 pos = gp . BB_Plot . Max - size - ImVec2 ( 5 , 5 ) ;
2020-04-27 11:27:59 -04:00
DrawList . AddText ( pos , gp . Col_Txt , buffer ) ;
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
// render border
2020-06-04 10:56:50 -04:00
DrawList . AddRect ( gp . BB_Plot . Min , gp . BB_Plot . Max , gp . Col_Border ) ;
2020-04-27 11:27:59 -04:00
// FIT DATA --------------------------------------------------------------
2020-04-28 21:17:26 -04:00
if ( gp . FitThisFrame & & ( gp . VisibleItemCount > 0 | | plot . Queried ) ) {
2020-05-13 10:08:12 -04:00
if ( gp . FitX & & ! HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_LockMin ) & & ! NanOrInf ( gp . ExtentsX . Min ) ) {
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Min = gp . ExtentsX . Min ;
}
2020-05-13 10:08:12 -04:00
if ( gp . FitX & & ! HasFlag ( plot . XAxis . Flags , ImPlotAxisFlags_LockMax ) & & ! NanOrInf ( gp . ExtentsX . Max ) ) {
2020-05-11 07:12:22 -04:00
plot . XAxis . Range . Max = gp . ExtentsX . Max ;
}
for ( int i = 0 ; i < MAX_Y_AXES ; i + + ) {
2020-05-13 10:08:12 -04:00
if ( gp . FitY [ i ] & & ! HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_LockMin ) & & ! NanOrInf ( gp . ExtentsY [ i ] . Min ) ) {
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Min = gp . ExtentsY [ i ] . Min ;
}
2020-05-13 10:08:12 -04:00
if ( gp . FitY [ i ] & & ! HasFlag ( plot . YAxis [ i ] . Flags , ImPlotAxisFlags_LockMax ) & & ! NanOrInf ( gp . ExtentsY [ i ] . Max ) ) {
2020-05-11 07:12:22 -04:00
plot . YAxis [ i ] . Range . Max = gp . ExtentsY [ i ] . Max ;
}
}
2020-04-27 11:27:59 -04:00
}
// CONTEXT MENU -----------------------------------------------------------
2020-06-04 10:56:50 -04:00
if ( HasFlag ( plot . Flags , ImPlotFlags_ContextMenu ) & & gp . Hov_Frame & & gp . Hov_Plot & & IO . MouseDoubleClicked [ 1 ] & & ! hov_legend )
2020-04-27 11:27:59 -04:00
ImGui : : OpenPopup ( " ##Context " ) ;
if ( ImGui : : BeginPopup ( " ##Context " ) ) {
PlotContextMenu ( plot ) ;
ImGui : : EndPopup ( ) ;
}
// CLEANUP ----------------------------------------------------------------
2020-05-12 05:19:04 -04:00
// Pop ImGui::PushID at the end of BeginPlot
2020-05-13 10:11:25 -04:00
ImGui : : PopID ( ) ;
2020-06-03 15:37:01 -04:00
// Reset context for next plot
gp . Reset ( ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// MISC API
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
void SetNextPlotLimits ( double x_min , double x_max , double y_min , double y_max , ImGuiCond cond ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " SetNextPlotLimits() needs to be called before BeginPlot()! " ) ;
2020-05-11 07:12:22 -04:00
SetNextPlotLimitsX ( x_min , x_max , cond ) ;
SetNextPlotLimitsY ( y_min , y_max , cond ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
void SetNextPlotLimitsX ( double x_min , double x_max , ImGuiCond cond ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " SetNextPlotLSetNextPlotLimitsXimitsY() needs to be called before BeginPlot()! " ) ;
2020-04-27 11:27:59 -04:00
IM_ASSERT ( cond = = 0 | | ImIsPowerOfTwo ( cond ) ) ; // Make sure the user doesn't attempt to combine multiple condition flags.
gp . NextPlotData . HasXRange = true ;
gp . NextPlotData . XRangeCond = cond ;
2020-05-11 07:12:22 -04:00
gp . NextPlotData . X . Min = x_min ;
gp . NextPlotData . X . Max = x_max ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
void SetNextPlotLimitsY ( double y_min , double y_max , ImGuiCond cond , int y_axis ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " SetNextPlotLimitsY() needs to be called before BeginPlot()! " ) ;
IM_ASSERT_USER_ERROR ( y_axis > = 0 & & y_axis < MAX_Y_AXES , " y_axis needs to be between 0 and MAX_Y_AXES " ) ;
2020-04-27 11:27:59 -04:00
IM_ASSERT ( cond = = 0 | | ImIsPowerOfTwo ( cond ) ) ; // Make sure the user doesn't attempt to combine multiple condition flags.
2020-05-11 07:12:22 -04:00
gp . NextPlotData . HasYRange [ y_axis ] = true ;
gp . NextPlotData . YRangeCond [ y_axis ] = cond ;
gp . NextPlotData . Y [ y_axis ] . Min = y_min ;
gp . NextPlotData . Y [ y_axis ] . Max = y_max ;
}
2020-06-03 15:37:01 -04:00
void SetNextPlotTicksX ( const double * values , int n_ticks , const char * * labels , bool show_default ) {
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " SetNextPlotTicksX() needs to be called before BeginPlot()! " ) ;
gp . NextPlotData . ShowDefaultTicksX = show_default ;
AddCustomTicks ( values , labels , n_ticks , gp . XTicks , gp . XTickLabels ) ;
}
void SetNextPlotTicksX ( double x_min , double x_max , int n_ticks , const char * * labels , bool show_default ) {
IM_ASSERT_USER_ERROR ( n_ticks > 1 , " The number of ticks must be greater than 1 " ) ;
static ImVector < double > buffer ;
FillRange ( buffer , n_ticks , x_min , x_max ) ;
SetNextPlotTicksX ( & buffer [ 0 ] , n_ticks , labels , show_default ) ;
}
void SetNextPlotTicksY ( const double * values , int n_ticks , const char * * labels , bool show_default , int y_axis ) {
IM_ASSERT_USER_ERROR ( gp . CurrentPlot = = NULL , " SetNextPlotTicksY() needs to be called before BeginPlot()! " ) ;
IM_ASSERT_USER_ERROR ( y_axis > = 0 & & y_axis < MAX_Y_AXES , " y_axis needs to be between 0 and MAX_Y_AXES " ) ;
gp . NextPlotData . ShowDefaultTicksY [ y_axis ] = show_default ;
AddCustomTicks ( values , labels , n_ticks , gp . YTicks [ y_axis ] , gp . YTickLabels [ y_axis ] ) ;
}
void SetNextPlotTicksY ( double y_min , double y_max , int n_ticks , const char * * labels , bool show_default , int y_axis ) {
IM_ASSERT_USER_ERROR ( n_ticks > 1 , " The number of ticks must be greater than 1 " ) ;
static ImVector < double > buffer ;
FillRange ( buffer , n_ticks , y_min , y_max ) ;
SetNextPlotTicksY ( & buffer [ 0 ] , n_ticks , labels , show_default , y_axis ) ;
}
2020-05-11 07:12:22 -04:00
void SetPlotYAxis ( int y_axis ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " SetPlotYAxis() needs to be called between BeginPlot() and EndPlot()! " ) ;
IM_ASSERT_USER_ERROR ( y_axis > = 0 & & y_axis < MAX_Y_AXES , " y_axis needs to be between 0 and MAX_Y_AXES " ) ;
2020-05-11 07:12:22 -04:00
gp . CurrentPlot - > CurrentYAxis = y_axis ;
2020-04-27 11:27:59 -04:00
}
2020-04-30 09:45:03 -04:00
ImVec2 GetPlotPos ( ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " GetPlotPos() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-06-04 10:56:50 -04:00
return gp . BB_Plot . Min ;
2020-04-30 09:45:03 -04:00
}
ImVec2 GetPlotSize ( ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " GetPlotSize() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-06-04 10:56:50 -04:00
return gp . BB_Plot . GetSize ( ) ;
2020-04-30 09:45:03 -04:00
}
void PushPlotClipRect ( ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-06-04 10:56:50 -04:00
ImGui : : PushClipRect ( gp . BB_Plot . Min , gp . BB_Plot . Max , true ) ;
2020-04-30 09:45:03 -04:00
}
void PopPlotClipRect ( ) {
2020-05-12 05:19:04 -04:00
ImGui : : PopClipRect ( ) ;
2020-04-30 09:45:03 -04:00
}
2020-05-13 10:11:25 -04:00
bool IsPlotHovered ( ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " IsPlotHovered() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-06-04 10:56:50 -04:00
return gp . Hov_Plot ;
2020-04-28 21:17:26 -04:00
}
2020-05-16 22:09:36 -04:00
ImPlotPoint GetPlotMousePos ( int y_axis_in ) {
2020-05-11 07:12:22 -04:00
IM_ASSERT_USER_ERROR ( y_axis_in > = - 1 & & y_axis_in < MAX_Y_AXES , " y_axis needs to between -1 and MAX_Y_AXES " ) ;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in > = 0 ? y_axis_in : gp . CurrentPlot - > CurrentYAxis ;
2020-05-13 10:11:25 -04:00
return gp . LastMousePos [ y_axis ] ;
2020-04-28 21:17:26 -04:00
}
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
ImPlotLimits GetPlotLimits ( int y_axis_in ) {
IM_ASSERT_USER_ERROR ( y_axis_in > = - 1 & & y_axis_in < MAX_Y_AXES , " y_axis needs to between -1 and MAX_Y_AXES " ) ;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " GetPlotLimits() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in > = 0 ? y_axis_in : gp . CurrentPlot - > CurrentYAxis ;
2020-05-12 05:19:04 -04:00
ImPlotState & plot = * gp . CurrentPlot ;
2020-05-11 07:12:22 -04:00
ImPlotLimits limits ;
limits . X = plot . XAxis . Range ;
limits . Y = plot . YAxis [ y_axis ] . Range ;
return limits ;
2020-04-28 00:57:49 -04:00
}
bool IsPlotQueried ( ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " IsPlotQueried() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-04-28 21:17:26 -04:00
return gp . CurrentPlot - > Queried ;
2020-04-28 00:57:49 -04:00
}
2020-05-11 07:12:22 -04:00
ImPlotLimits GetPlotQuery ( int y_axis_in ) {
IM_ASSERT_USER_ERROR ( y_axis_in > = - 1 & & y_axis_in < MAX_Y_AXES , " y_axis needs to between -1 and MAX_Y_AXES " ) ;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " GetPlotQuery() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-12 05:19:04 -04:00
ImPlotState & plot = * gp . CurrentPlot ;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in > = 0 ? y_axis_in : gp . CurrentPlot - > CurrentYAxis ;
UpdateTransformCache ( ) ;
2020-06-04 10:56:50 -04:00
ImPlotPoint p1 = PixelsToPlot ( plot . QueryRect . Min + gp . BB_Plot . Min , y_axis ) ;
ImPlotPoint p2 = PixelsToPlot ( plot . QueryRect . Max + gp . BB_Plot . Min , y_axis ) ;
2020-05-11 07:12:22 -04:00
ImPlotLimits result ;
result . X . Min = ImMin ( p1 . x , p2 . x ) ;
result . X . Max = ImMax ( p1 . x , p2 . x ) ;
result . Y . Min = ImMin ( p1 . y , p2 . y ) ;
result . Y . Max = ImMax ( p1 . y , p2 . y ) ;
return result ;
2020-04-28 00:57:49 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// STYLING
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
struct ImPlotStyleVarInfo {
ImGuiDataType Type ;
ImU32 Count ;
ImU32 Offset ;
void * GetVarPtr ( ImPlotStyle * style ) const { return ( void * ) ( ( unsigned char * ) style + Offset ) ; }
} ;
2020-05-13 10:11:25 -04:00
static const ImPlotStyleVarInfo GPlotStyleVarInfo [ ] =
2020-04-27 11:27:59 -04:00
{
2020-04-29 10:32:35 -04:00
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , LineWeight ) } , // ImPlotStyleVar_LineWeight
{ ImGuiDataType_S32 , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , Marker ) } , // ImPlotStyleVar_Marker
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , MarkerSize ) } , // ImPlotStyleVar_MarkerSize
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , MarkerWeight ) } , // ImPlotStyleVar_MarkerWeight
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , ErrorBarSize ) } , // ImPlotStyleVar_ErrorBarSize
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , ErrorBarWeight ) } , // ImPlotStyleVar_ErrorBarWeight
2020-05-09 00:54:16 -04:00
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , DigitalBitHeight ) } , // ImPlotStyleVar_DigitalBitHeight
{ ImGuiDataType_Float , 1 , ( ImU32 ) IM_OFFSETOF ( ImPlotStyle , DigitalBitGap ) } // ImPlotStyleVar_DigitalBitGap
2020-04-27 11:27:59 -04:00
} ;
static const ImPlotStyleVarInfo * GetPlotStyleVarInfo ( ImPlotStyleVar idx )
{
IM_ASSERT ( idx > = 0 & & idx < ImPlotStyleVar_COUNT ) ;
IM_ASSERT ( IM_ARRAYSIZE ( GPlotStyleVarInfo ) = = ImPlotStyleVar_COUNT ) ;
return & GPlotStyleVarInfo [ idx ] ;
}
2020-05-12 05:19:04 -04:00
ImPlotStyle & GetStyle ( ) {
2020-04-27 11:27:59 -04:00
return gp . Style ;
}
2020-05-12 05:19:04 -04:00
void PushStyleColor ( ImPlotCol idx , ImU32 col ) {
2020-04-27 11:27:59 -04:00
ImGuiColorMod backup ;
backup . Col = idx ;
backup . BackupValue = gp . Style . Colors [ idx ] ;
gp . ColorModifiers . push_back ( backup ) ;
2020-05-12 05:19:04 -04:00
gp . Style . Colors [ idx ] = ImGui : : ColorConvertU32ToFloat4 ( col ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PushStyleColor ( ImPlotCol idx , const ImVec4 & col ) {
2020-04-27 11:27:59 -04:00
ImGuiColorMod backup ;
backup . Col = idx ;
backup . BackupValue = gp . Style . Colors [ idx ] ;
gp . ColorModifiers . push_back ( backup ) ;
gp . Style . Colors [ idx ] = col ;
}
2020-05-12 05:19:04 -04:00
void PopStyleColor ( int count ) {
2020-04-27 11:27:59 -04:00
while ( count > 0 )
{
ImGuiColorMod & backup = gp . ColorModifiers . back ( ) ;
gp . Style . Colors [ backup . Col ] = backup . BackupValue ;
gp . ColorModifiers . pop_back ( ) ;
count - - ;
}
}
2020-05-12 05:19:04 -04:00
void PushStyleVar ( ImPlotStyleVar idx , float val ) {
2020-04-27 11:27:59 -04:00
const ImPlotStyleVarInfo * var_info = GetPlotStyleVarInfo ( idx ) ;
if ( var_info - > Type = = ImGuiDataType_Float & & var_info - > Count = = 1 ) {
float * pvar = ( float * ) var_info - > GetVarPtr ( & gp . Style ) ;
gp . StyleModifiers . push_back ( ImGuiStyleMod ( idx , * pvar ) ) ;
* pvar = val ;
return ;
}
2020-05-12 05:19:04 -04:00
IM_ASSERT ( 0 & & " Called PushStyleVar() float variant but variable is not a float! " ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PushStyleVar ( ImPlotStyleVar idx , int val ) {
2020-04-27 11:27:59 -04:00
const ImPlotStyleVarInfo * var_info = GetPlotStyleVarInfo ( idx ) ;
if ( var_info - > Type = = ImGuiDataType_S32 & & var_info - > Count = = 1 ) {
int * pvar = ( int * ) var_info - > GetVarPtr ( & gp . Style ) ;
gp . StyleModifiers . push_back ( ImGuiStyleMod ( idx , * pvar ) ) ;
* pvar = val ;
return ;
}
else if ( var_info - > Type = = ImGuiDataType_Float & & var_info - > Count = = 1 ) {
float * pvar = ( float * ) var_info - > GetVarPtr ( & gp . Style ) ;
gp . StyleModifiers . push_back ( ImGuiStyleMod ( idx , * pvar ) ) ;
* pvar = ( float ) val ;
return ;
}
2020-05-12 05:19:04 -04:00
IM_ASSERT ( 0 & & " Called PushStyleVar() int variant but variable is not a int! " ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PopStyleVar ( int count ) {
2020-04-27 11:27:59 -04:00
while ( count > 0 ) {
ImGuiStyleMod & backup = gp . StyleModifiers . back ( ) ;
const ImPlotStyleVarInfo * info = GetPlotStyleVarInfo ( backup . VarIdx ) ;
void * data = info - > GetVarPtr ( & gp . Style ) ;
if ( info - > Type = = ImGuiDataType_Float & & info - > Count = = 1 ) {
( ( float * ) data ) [ 0 ] = backup . BackupFloat [ 0 ] ;
}
else if ( info - > Type = = ImGuiDataType_Float & & info - > Count = = 2 ) {
2020-05-13 10:11:25 -04:00
( ( float * ) data ) [ 0 ] = backup . BackupFloat [ 0 ] ;
( ( float * ) data ) [ 1 ] = backup . BackupFloat [ 1 ] ;
2020-04-27 11:27:59 -04:00
}
else if ( info - > Type = = ImGuiDataType_S32 & & info - > Count = = 1 ) {
( ( int * ) data ) [ 0 ] = backup . BackupInt [ 0 ] ;
}
gp . StyleModifiers . pop_back ( ) ;
count - - ;
}
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
// RENDERING FUNCTIONS
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
# define SQRT_1_2 0.70710678118f
# define SQRT_3_2 0.86602540378f
inline void TransformMarker ( ImVec2 * points , int n , const ImVec2 & c , float s ) {
for ( int i = 0 ; i < n ; + + i ) {
points [ i ] . x = c . x + points [ i ] . x * s ;
points [ i ] . y = c . y + points [ i ] . y * s ;
}
}
inline void MarkerGeneral ( ImDrawList & DrawList , ImVec2 * points , int n , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
TransformMarker ( points , n , c , s ) ;
if ( fill )
DrawList . AddConvexPolyFilled ( points , n , col_fill ) ;
if ( outline & & ! ( fill & & col_outline = = col_fill ) ) {
for ( int i = 0 ; i < n ; + + i )
DrawList . AddLine ( points [ i ] , points [ ( i + 1 ) % n ] , col_outline , weight ) ;
}
}
2020-05-11 07:12:22 -04:00
inline void MarkerCircle ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 10 ] = { ImVec2 ( 1.0f , 0.0f ) ,
ImVec2 ( 0.809017f , 0.58778524f ) ,
ImVec2 ( 0.30901697f , 0.95105654f ) ,
ImVec2 ( - 0.30901703f , 0.9510565f ) ,
ImVec2 ( - 0.80901706f , 0.5877852f ) ,
ImVec2 ( - 1.0f , 0.0f ) ,
ImVec2 ( - 0.80901694f , - 0.58778536f ) ,
ImVec2 ( - 0.3090171f , - 0.9510565f ) ,
ImVec2 ( 0.30901712f , - 0.9510565f ) ,
ImVec2 ( 0.80901694f , - 0.5877853f ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 10 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerDiamond ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 4 ] = { ImVec2 ( 1 , 0 ) , ImVec2 ( 0 , - 1 ) , ImVec2 ( - 1 , 0 ) , ImVec2 ( 0 , 1 ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 4 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerSquare ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 4 ] = { ImVec2 ( SQRT_1_2 , SQRT_1_2 ) , ImVec2 ( SQRT_1_2 , - SQRT_1_2 ) , ImVec2 ( - SQRT_1_2 , - SQRT_1_2 ) , ImVec2 ( - SQRT_1_2 , SQRT_1_2 ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 4 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerUp ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 3 ] = { ImVec2 ( SQRT_3_2 , 0.5f ) , ImVec2 ( 0 , - 1 ) , ImVec2 ( - SQRT_3_2 , 0.5f ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 3 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerDown ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 3 ] = { ImVec2 ( SQRT_3_2 , - 0.5f ) , ImVec2 ( 0 , 1 ) , ImVec2 ( - SQRT_3_2 , - 0.5f ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 3 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerLeft ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 3 ] = { ImVec2 ( - 1 , 0 ) , ImVec2 ( 0.5 , SQRT_3_2 ) , ImVec2 ( 0.5 , - SQRT_3_2 ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 3 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
inline void MarkerRight ( ImDrawList & DrawList , const ImVec2 & c , float s , bool outline , ImU32 col_outline , bool fill , ImU32 col_fill , float weight ) {
2020-05-13 00:45:34 -04:00
ImVec2 marker [ 3 ] = { ImVec2 ( 1 , 0 ) , ImVec2 ( - 0.5 , SQRT_3_2 ) , ImVec2 ( - 0.5 , - SQRT_3_2 ) } ;
2020-04-27 11:27:59 -04:00
MarkerGeneral ( DrawList , marker , 3 , c , s , outline , col_outline , fill , col_fill , weight ) ;
}
2020-05-10 22:43:12 -04:00
inline void MarkerAsterisk ( ImDrawList & DrawList , const ImVec2 & c , float s , bool /*outline*/ , ImU32 col_outline , bool /*fill*/ , ImU32 /*col_fill*/ , float weight ) {
2020-05-29 17:31:50 -04:00
ImVec2 marker [ 6 ] = { ImVec2 ( SQRT_3_2 , 0.5f ) , ImVec2 ( 0 , - 1 ) , ImVec2 ( - SQRT_3_2 , 0.5f ) , ImVec2 ( SQRT_3_2 , - 0.5f ) , ImVec2 ( 0 , 1 ) , ImVec2 ( - SQRT_3_2 , - 0.5f ) } ;
2020-04-27 11:27:59 -04:00
TransformMarker ( marker , 6 , c , s ) ;
DrawList . AddLine ( marker [ 0 ] , marker [ 5 ] , col_outline , weight ) ;
DrawList . AddLine ( marker [ 1 ] , marker [ 4 ] , col_outline , weight ) ;
DrawList . AddLine ( marker [ 2 ] , marker [ 3 ] , col_outline , weight ) ;
}
2020-05-10 22:43:12 -04:00
inline void MarkerPlus ( ImDrawList & DrawList , const ImVec2 & c , float s , bool /*outline*/ , ImU32 col_outline , bool /*fill*/ , ImU32 /*col_fill*/ , float weight ) {
2020-05-29 17:31:50 -04:00
ImVec2 marker [ 4 ] = { ImVec2 ( 1 , 0 ) , ImVec2 ( 0 , - 1 ) , ImVec2 ( - 1 , 0 ) , ImVec2 ( 0 , 1 ) } ;
2020-04-27 11:27:59 -04:00
TransformMarker ( marker , 4 , c , s ) ;
DrawList . AddLine ( marker [ 0 ] , marker [ 2 ] , col_outline , weight ) ;
DrawList . AddLine ( marker [ 1 ] , marker [ 3 ] , col_outline , weight ) ;
}
2020-05-10 22:43:12 -04:00
inline void MarkerCross ( ImDrawList & DrawList , const ImVec2 & c , float s , bool /*outline*/ , ImU32 col_outline , bool /*fill*/ , ImU32 /*col_fill*/ , float weight ) {
2020-05-29 17:31:50 -04:00
ImVec2 marker [ 4 ] = { ImVec2 ( SQRT_1_2 , SQRT_1_2 ) , ImVec2 ( SQRT_1_2 , - SQRT_1_2 ) , ImVec2 ( - SQRT_1_2 , - SQRT_1_2 ) , ImVec2 ( - SQRT_1_2 , SQRT_1_2 ) } ;
2020-04-27 11:27:59 -04:00
TransformMarker ( marker , 4 , c , s ) ;
DrawList . AddLine ( marker [ 0 ] , marker [ 2 ] , col_outline , weight ) ;
DrawList . AddLine ( marker [ 1 ] , marker [ 3 ] , col_outline , weight ) ;
}
2020-05-03 01:24:10 -04:00
template < typename Transformer , typename Getter >
2020-05-29 13:39:30 -04:00
inline void RenderMarkers ( Getter getter , Transformer transformer , ImDrawList & DrawList , int count , int offset , bool rend_mk_line , ImU32 col_mk_line , bool rend_mk_fill , ImU32 col_mk_fill , bool cull ) {
2020-05-03 01:24:10 -04:00
int idx = offset ;
2020-05-13 10:11:25 -04:00
for ( int i = 0 ; i < count ; + + i ) {
2020-05-03 01:24:10 -04:00
ImVec2 c ;
2020-05-11 07:12:22 -04:00
c = transformer ( getter ( idx ) ) ;
2020-05-03 01:24:10 -04:00
idx = ( idx + 1 ) % count ;
2020-06-04 10:56:50 -04:00
if ( ! cull | | gp . BB_Plot . Contains ( c ) ) {
2020-05-03 01:24:10 -04:00
// TODO: Optimize the loop and if statements, this is atrocious
2020-05-13 10:11:25 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Circle ) )
2020-05-11 07:12:22 -04:00
MarkerCircle ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Square ) )
2020-05-13 10:11:25 -04:00
MarkerSquare ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Diamond ) )
2020-05-03 01:24:10 -04:00
MarkerDiamond ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Up ) )
2020-05-13 10:11:25 -04:00
MarkerUp ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Down ) )
MarkerDown ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Left ) )
2020-05-13 10:11:25 -04:00
MarkerLeft ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Right ) )
MarkerRight ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Cross ) )
2020-05-13 10:11:25 -04:00
MarkerCross ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Plus ) )
2020-05-13 10:11:25 -04:00
MarkerPlus ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( gp . Style . Marker , ImPlotMarker_Asterisk ) )
2020-05-13 10:11:25 -04:00
MarkerAsterisk ( DrawList , c , gp . Style . MarkerSize , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , gp . Style . MarkerWeight ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-13 10:11:25 -04:00
}
2020-05-03 01:24:10 -04:00
}
inline void RenderLine ( ImDrawList & DrawList , const ImVec2 & p1 , const ImVec2 & p2 , float line_weight , ImU32 col_line , ImVec2 uv ) {
// http://assemblyrequired.crashworks.org/timing-square-root/
float dx = p2 . x - p1 . x ;
float dy = p2 . y - p1 . y ;
IM_NORMALIZE2F_OVER_ZERO ( dx , dy ) ;
dx * = ( line_weight * 0.5f ) ;
2020-05-13 10:11:25 -04:00
dy * = ( line_weight * 0.5f ) ;
2020-05-03 01:24:10 -04:00
DrawList . _VtxWritePtr [ 0 ] . pos . x = p1 . x + dy ;
DrawList . _VtxWritePtr [ 0 ] . pos . y = p1 . y - dx ;
DrawList . _VtxWritePtr [ 0 ] . uv = uv ;
DrawList . _VtxWritePtr [ 0 ] . col = col_line ;
DrawList . _VtxWritePtr [ 1 ] . pos . x = p2 . x + dy ;
DrawList . _VtxWritePtr [ 1 ] . pos . y = p2 . y - dx ;
DrawList . _VtxWritePtr [ 1 ] . uv = uv ;
DrawList . _VtxWritePtr [ 1 ] . col = col_line ;
DrawList . _VtxWritePtr [ 2 ] . pos . x = p2 . x - dy ;
DrawList . _VtxWritePtr [ 2 ] . pos . y = p2 . y + dx ;
DrawList . _VtxWritePtr [ 2 ] . uv = uv ;
DrawList . _VtxWritePtr [ 2 ] . col = col_line ;
DrawList . _VtxWritePtr [ 3 ] . pos . x = p1 . x - dy ;
DrawList . _VtxWritePtr [ 3 ] . pos . y = p1 . y + dx ;
DrawList . _VtxWritePtr [ 3 ] . uv = uv ;
DrawList . _VtxWritePtr [ 3 ] . col = col_line ;
DrawList . _VtxWritePtr + = 4 ;
DrawList . _IdxWritePtr [ 0 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx ) ;
DrawList . _IdxWritePtr [ 1 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 1 ) ;
DrawList . _IdxWritePtr [ 2 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 2 ) ;
DrawList . _IdxWritePtr [ 3 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx ) ;
DrawList . _IdxWritePtr [ 4 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 2 ) ;
DrawList . _IdxWritePtr [ 5 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 3 ) ;
DrawList . _IdxWritePtr + = 6 ;
DrawList . _VtxCurrentIdx + = 4 ;
}
2020-06-02 23:07:27 -04:00
inline void RenderRect ( ImDrawList & DrawList , const ImVec2 & p1 , const ImVec2 & p2 , ImU32 col_ul , ImU32 col_ur , ImU32 col_bl , ImU32 col_br , ImVec2 uv ) {
2020-06-02 13:34:14 -04:00
DrawList . _VtxWritePtr [ 0 ] . pos . x = p1 . x ;
DrawList . _VtxWritePtr [ 0 ] . pos . y = p1 . y ;
DrawList . _VtxWritePtr [ 0 ] . uv = uv ;
2020-06-02 23:07:27 -04:00
DrawList . _VtxWritePtr [ 0 ] . col = col_ul ;
2020-06-02 13:34:14 -04:00
DrawList . _VtxWritePtr [ 1 ] . pos . x = p2 . x ;
DrawList . _VtxWritePtr [ 1 ] . pos . y = p1 . y ;
DrawList . _VtxWritePtr [ 1 ] . uv = uv ;
2020-06-02 23:07:27 -04:00
DrawList . _VtxWritePtr [ 1 ] . col = col_ur ;
2020-06-02 13:34:14 -04:00
DrawList . _VtxWritePtr [ 2 ] . pos . x = p2 . x ;
DrawList . _VtxWritePtr [ 2 ] . pos . y = p2 . y ;
DrawList . _VtxWritePtr [ 2 ] . uv = uv ;
2020-06-02 23:07:27 -04:00
DrawList . _VtxWritePtr [ 2 ] . col = col_br ;
2020-06-02 13:34:14 -04:00
DrawList . _VtxWritePtr [ 3 ] . pos . x = p1 . x ;
DrawList . _VtxWritePtr [ 3 ] . pos . y = p2 . y ;
DrawList . _VtxWritePtr [ 3 ] . uv = uv ;
2020-06-02 23:07:27 -04:00
DrawList . _VtxWritePtr [ 3 ] . col = col_bl ;
2020-06-02 13:34:14 -04:00
DrawList . _VtxWritePtr + = 4 ;
DrawList . _IdxWritePtr [ 0 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx ) ;
DrawList . _IdxWritePtr [ 1 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 1 ) ;
DrawList . _IdxWritePtr [ 2 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 3 ) ;
DrawList . _IdxWritePtr [ 3 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 1 ) ;
DrawList . _IdxWritePtr [ 4 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 2 ) ;
DrawList . _IdxWritePtr [ 5 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 3 ) ;
DrawList . _IdxWritePtr + = 6 ;
DrawList . _VtxCurrentIdx + = 4 ;
}
2020-05-31 17:32:32 -04:00
inline void RenderFill ( ImDrawList & DrawList , const ImVec2 & p1 , const ImVec2 & p2 , float zero , ImU32 col_fill , ImVec2 uv ) {
const int crosses_zero = ( p1 . y > zero & & p2 . y < zero ) | | ( p1 . y < zero & & p2 . y > zero ) ; // could do y*y < 0 earlier on
const float xmid = p1 . x + ( p2 . x - p1 . x ) / ( p2 . y - p1 . y ) * ( zero - p1 . y ) ;
DrawList . _VtxWritePtr [ 0 ] . pos = p1 ;
DrawList . _VtxWritePtr [ 0 ] . uv = uv ;
DrawList . _VtxWritePtr [ 0 ] . col = col_fill ;
DrawList . _VtxWritePtr [ 1 ] . pos = p2 ;
DrawList . _VtxWritePtr [ 1 ] . uv = uv ;
DrawList . _VtxWritePtr [ 1 ] . col = col_fill ;
DrawList . _VtxWritePtr [ 2 ] . pos = ImVec2 ( xmid , zero ) ;
DrawList . _VtxWritePtr [ 2 ] . uv = uv ;
DrawList . _VtxWritePtr [ 2 ] . col = col_fill ;
DrawList . _VtxWritePtr [ 3 ] . pos = ImVec2 ( p1 . x , zero ) ;
DrawList . _VtxWritePtr [ 3 ] . uv = uv ;
DrawList . _VtxWritePtr [ 3 ] . col = col_fill ;
DrawList . _VtxWritePtr [ 4 ] . pos = ImVec2 ( p2 . x , zero ) ; ;
DrawList . _VtxWritePtr [ 4 ] . uv = uv ;
DrawList . _VtxWritePtr [ 4 ] . col = col_fill ;
DrawList . _VtxWritePtr + = 5 ;
DrawList . _IdxWritePtr [ 0 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx ) ;
DrawList . _IdxWritePtr [ 1 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 1 + crosses_zero ) ;
DrawList . _IdxWritePtr [ 2 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 3 ) ;
DrawList . _IdxWritePtr [ 3 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 1 ) ;
DrawList . _IdxWritePtr [ 4 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 3 - crosses_zero ) ;
DrawList . _IdxWritePtr [ 5 ] = ( ImDrawIdx ) ( DrawList . _VtxCurrentIdx + 4 ) ;
DrawList . _IdxWritePtr + = 6 ;
DrawList . _VtxCurrentIdx + = 5 ;
}
2020-05-03 01:24:10 -04:00
inline void RenderLineAA ( ImDrawList & DrawList , const ImVec2 & p1 , const ImVec2 & p2 , float line_weight , ImU32 col_line ) {
DrawList . AddLine ( p1 , p2 , col_line , line_weight ) ;
}
2020-05-29 13:39:30 -04:00
template < typename Getter , typename Transformer >
inline void RenderLineStrip ( Getter getter , Transformer transformer , ImDrawList & DrawList , int count , int offset , float line_weight , ImU32 col_line , bool cull ) {
2020-05-31 17:32:32 -04:00
offset % = count ;
if ( offset < 0 )
offset + = count ; // shift negative offset to positive range
int i_start = offset + 1 ;
if ( i_start > = count )
i_start - = count ;
int i_end = offset + count ;
if ( i_end > = count )
2020-06-01 18:26:32 -04:00
i_end - = count ;
2020-05-31 17:32:32 -04:00
ImVec2 p1 = transformer ( getter ( offset ) ) ;
if ( HasFlag ( gp . CurrentPlot - > Flags , ImPlotFlags_AntiAliased ) ) {
for ( int i1 = i_start ; i1 ! = i_end ; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count ) {
ImVec2 p2 = transformer ( getter ( i1 ) ) ;
2020-06-04 10:56:50 -04:00
if ( ! cull | | gp . BB_Plot . Overlaps ( ImRect ( ImMin ( p1 , p2 ) , ImMax ( p1 , p2 ) ) ) )
2020-05-31 17:32:32 -04:00
RenderLineAA ( DrawList , p1 , p2 , line_weight , col_line ) ;
p1 = p2 ;
}
}
else {
2020-06-01 18:26:32 -04:00
int segments = count - 1 , i1 = 1 , segments_culled = 0 ;
2020-05-31 17:32:32 -04:00
const ImVec2 uv = DrawList . _Data - > TexUvWhitePixel ;
2020-06-01 18:26:32 -04:00
while ( segments )
{
int cnt = ( int /*todo - remove this cast*/ ) std : : min ( size_t ( segments ) , ( ( ( size_t ( 1 ) < < sizeof ( ImDrawIdx ) * 8 ) - 1 - DrawList . _VtxCurrentIdx ) / 4 ) ) ; // find how many can be reserved up to end of current draw command's limit
if ( cnt > = std : : min ( 64 , segments ) ) // make sure at least this many elements can be rendered to avoid situations where at the end of buffer this slow path is not taken all the time
{
if ( segments_culled > = cnt )
segments_culled - = cnt ; // reuse previous reservation
else
{
DrawList . PrimReserve ( ( cnt - segments_culled ) * 6 , ( cnt - segments_culled ) * 4 ) ; // add more elements to previous reservation
segments_culled = 0 ;
}
}
else
{
if ( segments_culled > 0 )
{
DrawList . PrimUnreserve ( segments_culled * 6 , segments_culled * 4 ) ;
segments_culled = 0 ;
}
cnt = ( int /*todo - remove this cast*/ ) std : : min ( size_t ( segments ) , ( ( ( size_t ( 1 ) < < sizeof ( ImDrawIdx ) * 8 ) - 1 - 0 /*DrawList._VtxCurrentIdx*/ ) / 4 ) ) ;
DrawList . PrimReserve ( cnt * 6 , cnt * 4 ) ; // reserve new draw command
}
segments - = cnt ;
for ( size_t ie = i1 + cnt ; i1 ! = ie ; + + i1 )
{
int idx = i1 ;
if ( offset )
{
idx + = offset ;
if ( idx > = count )
idx - = count ;
}
ImVec2 p2 = transformer ( getter ( idx ) ) ;
if ( ! cull | | gp . BB_Plot . Overlaps ( ImRect ( ImMin ( p1 , p2 ) , ImMax ( p1 , p2 ) ) ) )
2020-05-31 17:32:32 -04:00
RenderLine ( DrawList , p1 , p2 , line_weight , col_line , uv ) ;
2020-06-01 18:26:32 -04:00
else
2020-05-31 17:32:32 -04:00
segments_culled + + ;
2020-06-01 18:26:32 -04:00
p1 = p2 ;
}
2020-05-31 17:32:32 -04:00
}
if ( segments_culled > 0 )
2020-06-01 18:26:32 -04:00
DrawList . PrimUnreserve ( segments_culled * 6 , segments_culled * 4 ) ;
2020-05-31 17:32:32 -04:00
}
}
template < typename Getter , typename Transformer >
inline void RenderLineFill ( Getter getter , Transformer transformer , ImDrawList & DrawList , int count , int offset , ImU32 col_fill , bool cull ) {
( void ) cull ;
offset % = count ;
if ( offset < 0 )
offset + = count ; // shift negative offset to positive range
int i_start = offset + 1 ;
if ( i_start > = count )
i_start - = count ;
int i_end = offset + count ;
if ( i_end > = count )
i_end - = count ;
const int segments = count - 1 ;
ImVec2 p1 = transformer ( getter ( offset ) ) ;
float zero = transformer ( 0 , 0 ) . y ;
const ImVec2 uv = DrawList . _Data - > TexUvWhitePixel ;
DrawList . PrimReserve ( segments * 6 , segments * 5 ) ;
int segments_culled = 0 ;
for ( int i1 = i_start ; i1 ! = i_end ; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count ) {
ImVec2 p2 = transformer ( getter ( i1 ) ) ;
// TODO: Culling (not as simple as RenderLineStrip)
RenderFill ( DrawList , p1 , p2 , zero , col_fill , uv ) ;
p1 = p2 ;
}
if ( segments_culled > 0 )
DrawList . PrimUnreserve ( segments_culled * 6 , segments_culled * 5 ) ;
2020-05-03 01:24:10 -04:00
}
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
// DATA GETTERS
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-16 22:53:59 -04:00
template < typename T >
inline T StrideIndex ( const T * data , int idx , int stride ) {
return * ( const T * ) ( const void * ) ( ( const unsigned char * ) data + ( size_t ) idx * stride ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-16 22:53:59 -04:00
template < typename T >
2020-05-03 01:24:10 -04:00
struct GetterYs {
2020-05-16 22:53:59 -04:00
GetterYs ( const T * ys , int stride ) { Ys = ys ; Stride = stride ; }
const T * Ys ;
2020-04-27 11:27:59 -04:00
int Stride ;
2020-05-16 22:53:59 -04:00
inline ImPlotPoint operator ( ) ( int idx ) {
return ImPlotPoint ( ( T ) idx , StrideIndex ( Ys , idx , Stride ) ) ;
2020-04-27 11:27:59 -04:00
}
} ;
2020-05-16 22:53:59 -04:00
template < typename T >
2020-05-29 13:39:30 -04:00
struct GetterXsYs {
GetterXsYs ( const T * xs , const T * ys , int stride ) { Xs = xs ; Ys = ys ; Stride = stride ; }
2020-05-16 22:53:59 -04:00
const T * Xs ;
const T * Ys ;
2020-05-03 01:24:10 -04:00
int Stride ;
2020-05-16 22:53:59 -04:00
inline ImPlotPoint operator ( ) ( int idx ) {
return ImPlotPoint ( StrideIndex ( Xs , idx , Stride ) , StrideIndex ( Ys , idx , Stride ) ) ;
2020-05-03 01:24:10 -04:00
}
} ;
2020-04-27 11:27:59 -04:00
2020-05-31 10:17:07 -04:00
struct GetterImVec2 {
GetterImVec2 ( const ImVec2 * data ) { Data = data ; }
inline ImPlotPoint operator ( ) ( int idx ) { return ImPlotPoint ( Data [ idx ] . x , Data [ idx ] . y ) ; }
const ImVec2 * Data ;
} ;
2020-05-29 13:39:30 -04:00
struct GetterImPlotPoint {
GetterImPlotPoint ( const ImPlotPoint * data ) { Data = data ; }
inline ImPlotPoint operator ( ) ( int idx ) { return Data [ idx ] ; }
const ImPlotPoint * Data ;
} ;
struct GetterFuncPtrImPlotPoint {
GetterFuncPtrImPlotPoint ( ImPlotPoint ( * g ) ( void * data , int idx ) , void * d ) { getter = g ; data = d ; }
inline ImPlotPoint operator ( ) ( int idx ) { return getter ( data , idx ) ; }
ImPlotPoint ( * getter ) ( void * data , int idx ) ;
void * data ;
} ;
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
// PLOT
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
template < typename Getter >
inline void PlotEx ( const char * label_id , Getter getter , int count , int offset )
2020-04-27 11:27:59 -04:00
{
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " Plot() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
ImPlotState * plot = gp . CurrentPlot ;
2020-05-11 07:12:22 -04:00
const int y_axis = plot - > CurrentYAxis ;
2020-05-03 01:24:10 -04:00
ImPlotItem * item = RegisterItem ( label_id ) ;
2020-04-27 11:27:59 -04:00
if ( ! item - > Show )
return ;
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-05-31 17:32:32 -04:00
const bool rend_line = gp . Style . Colors [ ImPlotCol_Line ] . w ! = 0 & & gp . Style . LineWeight > 0 ;
const bool rend_fill = gp . Style . Colors [ ImPlotCol_Fill ] . w > 0 ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
ImU32 col_line = gp . Style . Colors [ ImPlotCol_Line ] . w = = - 1 ? ImGui : : GetColorU32 ( item - > Color ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Line ] ) ;
2020-05-03 01:24:10 -04:00
2020-04-27 11:27:59 -04:00
if ( gp . Style . Colors [ ImPlotCol_Line ] . w ! = - 1 )
item - > Color = gp . Style . Colors [ ImPlotCol_Line ] ;
2020-05-11 07:12:22 -04:00
bool cull = HasFlag ( plot - > Flags , ImPlotFlags_CullData ) ;
2020-05-03 01:24:10 -04:00
2020-04-27 11:27:59 -04:00
// find data extents
if ( gp . FitThisFrame ) {
for ( int i = 0 ; i < count ; + + i ) {
2020-05-16 22:53:59 -04:00
ImPlotPoint p = getter ( i ) ;
2020-05-03 01:24:10 -04:00
FitPoint ( p ) ;
2020-04-27 11:27:59 -04:00
}
2020-06-04 01:11:43 -04:00
if ( rend_fill ) {
ImPlotPoint p1 = getter ( 0 ) ;
ImPlotPoint p2 = getter ( count - 1 ) ;
p1 . y = 0 ; p2 . y = 0 ;
FitPoint ( p1 ) ; FitPoint ( p2 ) ;
}
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-05-31 17:32:32 -04:00
// render fill
if ( count > 1 & & rend_fill ) {
const ImU32 col_fill = ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Fill ] ) ;
if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) & & HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
RenderLineFill ( getter , TransformerLogLog ( y_axis ) , DrawList , count , offset , col_fill , cull ) ;
else if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) )
RenderLineFill ( getter , TransformerLogLin ( y_axis ) , DrawList , count , offset , col_fill , cull ) ;
else if ( HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
RenderLineFill ( getter , TransformerLinLog ( y_axis ) , DrawList , count , offset , col_fill , cull ) ;
else
RenderLineFill ( getter , TransformerLinLin ( y_axis ) , DrawList , count , offset , col_fill , cull ) ;
}
// render line
2020-04-27 11:27:59 -04:00
if ( count > 1 & & rend_line ) {
2020-05-31 17:32:32 -04:00
const float line_weight = item - > Highlight ? gp . Style . LineWeight * 2 : gp . Style . LineWeight ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) & & HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderLineStrip ( getter , TransformerLogLog ( y_axis ) , DrawList , count , offset , line_weight , col_line , cull ) ;
2020-05-13 10:08:12 -04:00
else if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderLineStrip ( getter , TransformerLogLin ( y_axis ) , DrawList , count , offset , line_weight , col_line , cull ) ;
2020-05-13 10:08:12 -04:00
else if ( HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderLineStrip ( getter , TransformerLinLog ( y_axis ) , DrawList , count , offset , line_weight , col_line , cull ) ;
2020-05-03 01:24:10 -04:00
else
2020-05-29 13:39:30 -04:00
RenderLineStrip ( getter , TransformerLinLin ( y_axis ) , DrawList , count , offset , line_weight , col_line , cull ) ;
2020-05-03 01:24:10 -04:00
}
2020-05-04 03:09:33 -04:00
// render markers
2020-05-13 10:08:12 -04:00
if ( gp . Style . Marker ! = ImPlotMarker_None ) {
2020-05-31 17:32:32 -04:00
const bool rend_mk_line = gp . Style . Colors [ ImPlotCol_MarkerOutline ] . w ! = 0 & & gp . Style . MarkerWeight > 0 ;
const bool rend_mk_fill = gp . Style . Colors [ ImPlotCol_MarkerFill ] . w ! = 0 ;
const ImU32 col_mk_line = gp . Style . Colors [ ImPlotCol_MarkerOutline ] . w = = - 1 ? col_line : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_MarkerOutline ] ) ;
const ImU32 col_mk_fill = gp . Style . Colors [ ImPlotCol_MarkerFill ] . w = = - 1 ? col_line : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_MarkerFill ] ) ;
2020-05-13 10:08:12 -04:00
if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) & & HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderMarkers ( getter , TransformerLogLog ( y_axis ) , DrawList , count , offset , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , cull ) ;
2020-05-13 10:08:12 -04:00
else if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderMarkers ( getter , TransformerLogLin ( y_axis ) , DrawList , count , offset , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , cull ) ;
2020-05-13 10:08:12 -04:00
else if ( HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-05-29 13:39:30 -04:00
RenderMarkers ( getter , TransformerLinLog ( y_axis ) , DrawList , count , offset , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , cull ) ;
2020-05-03 01:24:10 -04:00
else
2020-05-29 13:39:30 -04:00
RenderMarkers ( getter , TransformerLinLin ( y_axis ) , DrawList , count , offset , rend_mk_line , col_mk_line , rend_mk_fill , col_mk_fill , cull ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-05-16 09:39:43 -04:00
void PlotLine ( const char * label_id , const float * values , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterYs < float > getter ( values , stride ) ;
2020-05-03 01:24:10 -04:00
PlotEx ( label_id , getter , count , offset ) ;
2020-04-29 10:32:35 -04:00
}
2020-05-16 09:39:43 -04:00
void PlotLine ( const char * label_id , const float * xs , const float * ys , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterXsYs < float > getter ( xs , ys , stride ) ;
2020-05-03 01:24:10 -04:00
return PlotEx ( label_id , getter , count , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-04-30 09:45:03 -04:00
2020-05-16 09:39:43 -04:00
void PlotLine ( const char * label_id , const ImVec2 * data , int count , int offset ) {
2020-05-03 01:24:10 -04:00
GetterImVec2 getter ( data ) ;
return PlotEx ( label_id , getter , count , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-04-30 09:45:03 -04:00
2020-04-29 10:32:35 -04:00
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// double
void PlotLine ( const char * label_id , const double * values , int count , int offset , int stride ) {
GetterYs < double > getter ( values , stride ) ;
PlotEx ( label_id , getter , count , offset ) ;
}
void PlotLine ( const char * label_id , const double * xs , const double * ys , int count , int offset , int stride ) {
GetterXsYs < double > getter ( xs , ys , stride ) ;
return PlotEx ( label_id , getter , count , offset ) ;
}
void PlotLine ( const char * label_id , const ImPlotPoint * data , int count , int offset ) {
GetterImPlotPoint getter ( data ) ;
return PlotEx ( label_id , getter , count , offset ) ;
}
2020-05-31 10:07:24 -04:00
//-----------------------------------------------------------------------------
// custom
2020-05-29 13:39:30 -04:00
void PlotLine ( const char * label_id , ImPlotPoint ( * getter_func ) ( void * data , int idx ) , void * data , int count , int offset ) {
GetterFuncPtrImPlotPoint getter ( getter_func , data ) ;
return PlotEx ( label_id , getter , count , offset ) ;
}
2020-05-16 09:39:43 -04:00
//-----------------------------------------------------------------------------
// PLOT SCATTER
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
inline int PushScatterStyle ( ) {
int vars = 1 ;
2020-05-16 09:39:43 -04:00
PushStyleVar ( ImPlotStyleVar_LineWeight , 0 ) ;
if ( GetStyle ( ) . Marker = = ImPlotMarker_None ) {
PushStyleVar ( ImPlotStyleVar_Marker , ImPlotMarker_Circle ) ;
2020-05-29 13:39:30 -04:00
vars + + ;
2020-05-16 09:39:43 -04:00
}
2020-05-29 13:39:30 -04:00
return vars ;
}
//-----------------------------------------------------------------------------
// float
void PlotScatter ( const char * label_id , const float * values , int count , int offset , int stride ) {
int vars = PushScatterStyle ( ) ;
2020-05-16 09:39:43 -04:00
PlotLine ( label_id , values , count , offset , stride ) ;
2020-05-29 13:39:30 -04:00
PopStyleVar ( vars ) ;
2020-05-16 09:39:43 -04:00
}
void PlotScatter ( const char * label_id , const float * xs , const float * ys , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
int vars = PushScatterStyle ( ) ;
2020-05-16 09:39:43 -04:00
PlotLine ( label_id , xs , ys , count , offset , stride ) ;
2020-05-29 13:39:30 -04:00
PopStyleVar ( vars ) ;
2020-05-16 09:39:43 -04:00
}
void PlotScatter ( const char * label_id , const ImVec2 * data , int count , int offset ) {
2020-05-29 13:39:30 -04:00
int vars = PushScatterStyle ( ) ;
2020-05-16 09:39:43 -04:00
PlotLine ( label_id , data , count , offset ) ;
2020-05-29 13:39:30 -04:00
PopStyleVar ( vars ) ;
2020-05-16 09:39:43 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
// double
void PlotScatter ( const char * label_id , const double * values , int count , int offset , int stride ) {
int vars = PushScatterStyle ( ) ;
PlotLine ( label_id , values , count , offset , stride ) ;
PopStyleVar ( vars ) ;
}
void PlotScatter ( const char * label_id , const double * xs , const double * ys , int count , int offset , int stride ) {
int vars = PushScatterStyle ( ) ;
PlotLine ( label_id , xs , ys , count , offset , stride ) ;
PopStyleVar ( vars ) ;
}
void PlotScatter ( const char * label_id , const ImPlotPoint * data , int count , int offset ) {
int vars = PushScatterStyle ( ) ;
PlotLine ( label_id , data , count , offset ) ;
PopStyleVar ( vars ) ;
}
2020-05-31 10:07:24 -04:00
//-----------------------------------------------------------------------------
// custom
2020-05-29 13:39:30 -04:00
void PlotScatter ( const char * label_id , ImPlotPoint ( * getter ) ( void * data , int idx ) , void * data , int count , int offset ) {
int vars = PushScatterStyle ( ) ;
PlotLine ( label_id , getter , data , count , offset ) ;
PopStyleVar ( vars ) ;
}
//-----------------------------------------------------------------------------
// PLOT BAR V
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-29 10:32:35 -04:00
2020-05-16 22:53:59 -04:00
template < typename T >
2020-05-03 01:24:10 -04:00
struct GetterBarV {
2020-05-16 22:53:59 -04:00
const T * Ys ; T XShift ; int Stride ;
GetterBarV ( const T * ys , T xshift , int stride ) { Ys = ys ; XShift = xshift ; Stride = stride ; }
inline ImPlotPoint operator ( ) ( int idx ) { return ImPlotPoint ( ( T ) idx + XShift , StrideIndex ( Ys , idx , Stride ) ) ; }
2020-05-03 01:24:10 -04:00
} ;
2020-04-27 11:27:59 -04:00
2020-05-16 22:53:59 -04:00
template < typename T >
2020-05-03 01:24:10 -04:00
struct GetterBarH {
2020-05-16 22:53:59 -04:00
const T * Xs ; T YShift ; int Stride ;
GetterBarH ( const T * xs , T yshift , int stride ) { Xs = xs ; YShift = yshift ; Stride = stride ; }
inline ImPlotPoint operator ( ) ( int idx ) { return ImPlotPoint ( StrideIndex ( Xs , idx , Stride ) , ( T ) idx + YShift ) ; }
2020-05-03 01:24:10 -04:00
} ;
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
template < typename Getter , typename TWidth >
void PlotBarsEx ( const char * label_id , Getter getter , int count , TWidth width , int offset ) {
2020-04-27 11:27:59 -04:00
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotBars() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
ImPlotItem * item = RegisterItem ( label_id ) ;
2020-04-27 11:27:59 -04:00
if ( ! item - > Show )
return ;
2020-05-12 05:19:04 -04:00
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-04-27 11:27:59 -04:00
bool rend_line = gp . Style . Colors [ ImPlotCol_Line ] . w ! = 0 & & gp . Style . LineWeight > 0 ;
bool rend_fill = gp . Style . Colors [ ImPlotCol_Fill ] . w ! = 0 ;
2020-05-12 05:19:04 -04:00
ImU32 col_line = gp . Style . Colors [ ImPlotCol_Line ] . w = = - 1 ? ImGui : : GetColorU32 ( item - > Color ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Line ] ) ;
ImU32 col_fill = gp . Style . Colors [ ImPlotCol_Fill ] . w = = - 1 ? col_line : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Fill ] ) ;
2020-04-27 11:27:59 -04:00
if ( rend_fill & & col_line = = col_fill )
rend_line = false ;
if ( gp . Style . Colors [ ImPlotCol_Line ] . w ! = - 1 )
item - > Color = gp . Style . Colors [ ImPlotCol_Line ] ;
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
TWidth half_width = width / 2 ;
2020-04-27 11:27:59 -04:00
// find data extents
if ( gp . FitThisFrame ) {
for ( int i = 0 ; i < count ; + + i ) {
2020-05-16 22:53:59 -04:00
ImPlotPoint p = getter ( i ) ;
FitPoint ( ImPlotPoint ( p . x - half_width , p . y ) ) ;
FitPoint ( ImPlotPoint ( p . x + half_width , 0 ) ) ;
2020-04-27 11:27:59 -04:00
}
}
int idx = offset ;
2020-05-13 10:11:25 -04:00
for ( int i = 0 ; i < count ; + + i ) {
2020-06-01 23:14:22 -04:00
ImPlotPoint p = getter ( idx ) ;
2020-04-27 11:27:59 -04:00
idx = ( idx + 1 ) % count ;
if ( p . y = = 0 )
continue ;
2020-05-03 01:24:10 -04:00
ImVec2 a = PlotToPixels ( p . x - half_width , p . y ) ;
ImVec2 b = PlotToPixels ( p . x + half_width , 0 ) ;
2020-04-27 11:27:59 -04:00
if ( rend_fill )
DrawList . AddRectFilled ( a , b , col_fill ) ;
if ( rend_line )
DrawList . AddRect ( a , b , col_line ) ;
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-05-16 10:14:48 -04:00
void PlotBars ( const char * label_id , const float * values , int count , float width , float shift , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterBarV < float > getter ( values , shift , stride ) ;
2020-05-16 10:14:48 -04:00
PlotBarsEx ( label_id , getter , count , width , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-16 10:14:48 -04:00
void PlotBars ( const char * label_id , const float * xs , const float * ys , int count , float width , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterXsYs < float > getter ( xs , ys , stride ) ;
2020-05-16 10:14:48 -04:00
PlotBarsEx ( label_id , getter , count , width , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
// double
2020-05-03 01:24:10 -04:00
2020-05-29 13:39:30 -04:00
void PlotBars ( const char * label_id , const double * values , int count , double width , double shift , int offset , int stride ) {
GetterBarV < double > getter ( values , shift , stride ) ;
PlotBarsEx ( label_id , getter , count , width , offset ) ;
}
void PlotBars ( const char * label_id , const double * xs , const double * ys , int count , double width , int offset , int stride ) {
GetterXsYs < double > getter ( xs , ys , stride ) ;
PlotBarsEx ( label_id , getter , count , width , offset ) ;
}
2020-05-31 10:07:24 -04:00
//-----------------------------------------------------------------------------
// custom
2020-05-29 13:39:30 -04:00
void PlotBars ( const char * label_id , ImPlotPoint ( * getter_func ) ( void * data , int idx ) , void * data , int count , double width , int offset ) {
GetterFuncPtrImPlotPoint getter ( getter_func , data ) ;
PlotBarsEx ( label_id , getter , count , width , offset ) ;
}
//-----------------------------------------------------------------------------
// PLOT BAR H
//-----------------------------------------------------------------------------
template < typename Getter , typename THeight >
void PlotBarsHEx ( const char * label_id , Getter getter , int count , THeight height , int offset ) {
2020-04-27 11:27:59 -04:00
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotBarsH() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
ImPlotItem * item = RegisterItem ( label_id ) ;
2020-04-27 11:27:59 -04:00
if ( ! item - > Show )
return ;
2020-05-12 05:19:04 -04:00
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-04-27 11:27:59 -04:00
bool rend_line = gp . Style . Colors [ ImPlotCol_Line ] . w ! = 0 & & gp . Style . LineWeight > 0 ;
bool rend_fill = gp . Style . Colors [ ImPlotCol_Fill ] . w ! = 0 ;
2020-05-12 05:19:04 -04:00
ImU32 col_line = gp . Style . Colors [ ImPlotCol_Line ] . w = = - 1 ? ImGui : : GetColorU32 ( item - > Color ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Line ] ) ;
ImU32 col_fill = gp . Style . Colors [ ImPlotCol_Fill ] . w = = - 1 ? col_line : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_Fill ] ) ;
2020-04-27 11:27:59 -04:00
if ( rend_fill & & col_line = = col_fill )
rend_line = false ;
if ( gp . Style . Colors [ ImPlotCol_Line ] . w ! = - 1 )
item - > Color = gp . Style . Colors [ ImPlotCol_Line ] ;
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
THeight half_height = height / 2 ;
2020-04-27 11:27:59 -04:00
// find data extents
if ( gp . FitThisFrame ) {
for ( int i = 0 ; i < count ; + + i ) {
2020-05-16 22:53:59 -04:00
ImPlotPoint p = getter ( i ) ;
FitPoint ( ImPlotPoint ( 0 , p . y - half_height ) ) ;
FitPoint ( ImPlotPoint ( p . x , p . y + half_height ) ) ;
2020-04-27 11:27:59 -04:00
}
}
int idx = offset ;
2020-05-13 10:11:25 -04:00
for ( int i = 0 ; i < count ; + + i ) {
2020-06-01 23:14:22 -04:00
ImPlotPoint p = getter ( idx ) ;
2020-04-27 11:27:59 -04:00
idx = ( idx + 1 ) % count ;
if ( p . x = = 0 )
continue ;
2020-05-03 01:24:10 -04:00
ImVec2 a = PlotToPixels ( 0 , p . y - half_height ) ;
ImVec2 b = PlotToPixels ( p . x , p . y + half_height ) ;
2020-04-27 11:27:59 -04:00
if ( rend_fill )
DrawList . AddRectFilled ( a , b , col_fill ) ;
if ( rend_line )
DrawList . AddRect ( a , b , col_line ) ;
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-05-16 10:14:48 -04:00
void PlotBarsH ( const char * label_id , const float * values , int count , float height , float shift , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterBarH < float > getter ( values , shift , stride ) ;
2020-05-16 10:14:48 -04:00
PlotBarsHEx ( label_id , getter , count , height , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-16 10:14:48 -04:00
void PlotBarsH ( const char * label_id , const float * xs , const float * ys , int count , float height , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterXsYs < float > getter ( xs , ys , stride ) ;
2020-05-16 10:14:48 -04:00
PlotBarsHEx ( label_id , getter , count , height , offset ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// double
void PlotBarsH ( const char * label_id , const double * values , int count , double height , double shift , int offset , int stride ) {
GetterBarH < double > getter ( values , shift , stride ) ;
PlotBarsHEx ( label_id , getter , count , height , offset ) ;
}
void PlotBarsH ( const char * label_id , const double * xs , const double * ys , int count , double height , int offset , int stride ) {
GetterXsYs < double > getter ( xs , ys , stride ) ;
PlotBarsHEx ( label_id , getter , count , height , offset ) ;
}
2020-05-31 10:07:24 -04:00
//-----------------------------------------------------------------------------
// custom
2020-05-29 13:39:30 -04:00
void PlotBarsH ( const char * label_id , ImPlotPoint ( * getter_func ) ( void * data , int idx ) , void * data , int count , double height , int offset ) {
GetterFuncPtrImPlotPoint getter ( getter_func , data ) ;
PlotBarsHEx ( label_id , getter , count , height , offset ) ;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
// PLOT ERROR BARS
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
struct ImPlotPointError {
ImPlotPointError ( double _x , double _y , double _neg , double _pos ) {
x = _x ; y = _y ; neg = _neg ; pos = _pos ;
}
double x , y , neg , pos ;
} ;
template < typename T >
2020-05-03 01:24:10 -04:00
struct GetterError {
2020-05-29 13:39:30 -04:00
const T * Xs ; const T * Ys ; const T * Neg ; const T * Pos ; int Stride ;
GetterError ( const T * xs , const T * ys , const T * neg , const T * pos , int stride ) {
2020-05-03 01:24:10 -04:00
Xs = xs ; Ys = ys ; Neg = neg ; Pos = pos ; Stride = stride ;
}
2020-05-29 13:39:30 -04:00
ImPlotPointError operator ( ) ( int idx ) {
return ImPlotPointError ( StrideIndex ( Xs , idx , Stride ) ,
StrideIndex ( Ys , idx , Stride ) ,
StrideIndex ( Neg , idx , Stride ) ,
StrideIndex ( Pos , idx , Stride ) ) ;
2020-05-03 01:24:10 -04:00
}
} ;
template < typename Getter >
void PlotErrorBarsEx ( const char * label_id , Getter getter , int count , int offset ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotErrorBars() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
ImGuiID id = ImGui : : GetID ( label_id ) ;
2020-04-27 11:27:59 -04:00
ImPlotItem * item = gp . CurrentPlot - > Items . GetByKey ( id ) ;
if ( item ! = NULL & & item - > Show = = false )
return ;
2020-05-12 05:19:04 -04:00
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
const ImU32 col = gp . Style . Colors [ ImPlotCol_ErrorBar ] . w = = - 1 ? ImGui : : GetColorU32 ( ImGuiCol_Text ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_ErrorBar ] ) ;
2020-04-27 11:27:59 -04:00
const bool rend_whisker = gp . Style . ErrorBarSize > 0 ;
const float half_whisker = gp . Style . ErrorBarSize * 0.5f ;
// find data extents
if ( gp . FitThisFrame ) {
for ( int i = 0 ; i < count ; + + i ) {
2020-05-29 13:39:30 -04:00
ImPlotPointError e = getter ( i ) ;
FitPoint ( ImPlotPoint ( e . x , e . y - e . neg ) ) ;
FitPoint ( ImPlotPoint ( e . x , e . y + e . pos ) ) ;
2020-04-27 11:27:59 -04:00
}
}
int idx = offset ;
for ( int i = 0 ; i < count ; + + i ) {
2020-05-29 13:39:30 -04:00
ImPlotPointError e = getter ( idx ) ;
2020-04-27 11:27:59 -04:00
idx = ( idx + 1 ) % count ;
2020-05-29 13:39:30 -04:00
ImVec2 p1 = PlotToPixels ( e . x , e . y - e . neg ) ;
ImVec2 p2 = PlotToPixels ( e . x , e . y + e . pos ) ;
2020-04-27 11:27:59 -04:00
DrawList . AddLine ( p1 , p2 , col , gp . Style . ErrorBarWeight ) ;
if ( rend_whisker ) {
DrawList . AddLine ( p1 - ImVec2 ( half_whisker , 0 ) , p1 + ImVec2 ( half_whisker , 0 ) , col , gp . Style . ErrorBarWeight ) ;
DrawList . AddLine ( p2 - ImVec2 ( half_whisker , 0 ) , p2 + ImVec2 ( half_whisker , 0 ) , col , gp . Style . ErrorBarWeight ) ;
}
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
}
2020-04-27 11:27:59 -04:00
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-05-16 09:39:43 -04:00
void PlotErrorBars ( const char * label_id , const float * xs , const float * ys , const float * err , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterError < float > getter ( xs , ys , err , err , stride ) ;
2020-05-03 01:24:10 -04:00
PlotErrorBarsEx ( label_id , getter , count , offset ) ;
}
2020-05-16 09:39:43 -04:00
void PlotErrorBars ( const char * label_id , const float * xs , const float * ys , const float * neg , const float * pos , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterError < float > getter ( xs , ys , neg , pos , stride ) ;
PlotErrorBarsEx ( label_id , getter , count , offset ) ;
}
//-----------------------------------------------------------------------------
// double
void PlotErrorBars ( const char * label_id , const double * xs , const double * ys , const double * err , int count , int offset , int stride ) {
GetterError < double > getter ( xs , ys , err , err , stride ) ;
2020-05-03 01:24:10 -04:00
PlotErrorBarsEx ( label_id , getter , count , offset ) ;
}
2020-05-29 13:39:30 -04:00
void PlotErrorBars ( const char * label_id , const double * xs , const double * ys , const double * neg , const double * pos , int count , int offset , int stride ) {
GetterError < double > getter ( xs , ys , neg , pos , stride ) ;
2020-05-03 01:24:10 -04:00
PlotErrorBarsEx ( label_id , getter , count , offset ) ;
}
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
// PLOT PIE CHART
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-05-29 13:39:30 -04:00
inline void DrawPieSlice ( ImDrawList & DrawList , const ImPlotPoint & center , double radius , double a0 , double a1 , ImU32 col ) {
2020-05-03 01:24:10 -04:00
static const float resolution = 50 / ( 2 * IM_PI ) ;
static ImVec2 buffer [ 50 ] ;
buffer [ 0 ] = PlotToPixels ( center ) ;
int n = ImMax ( 3 , ( int ) ( ( a1 - a0 ) * resolution ) ) ;
2020-05-29 13:39:30 -04:00
double da = ( a1 - a0 ) / ( n - 1 ) ;
2020-05-03 01:24:10 -04:00
for ( int i = 0 ; i < n ; + + i ) {
2020-05-29 13:39:30 -04:00
double a = a0 + i * da ;
2020-05-03 01:24:10 -04:00
buffer [ i + 1 ] = PlotToPixels ( center . x + radius * cos ( a ) , center . y + radius * sin ( a ) ) ;
}
DrawList . AddConvexPolyFilled ( buffer , n + 1 , col ) ;
}
2020-05-29 13:39:30 -04:00
template < typename T >
2020-06-04 10:56:50 -04:00
void PlotPieChartEx ( const char * * label_ids , const T * values , int count , T x , T y , T radius , bool normalize , const char * fmt , T angle0 ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotPieChart() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-12 05:19:04 -04:00
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-05-03 01:24:10 -04:00
2020-05-29 13:39:30 -04:00
T sum = 0 ;
2020-05-03 01:24:10 -04:00
for ( int i = 0 ; i < count ; + + i )
sum + = values [ i ] ;
2020-05-13 10:11:25 -04:00
2020-06-04 10:56:50 -04:00
normalize = normalize | | sum > 1.0f ;
2020-05-03 01:24:10 -04:00
2020-05-16 22:09:36 -04:00
ImPlotPoint center ( x , y ) ;
2020-05-03 01:24:10 -04:00
PushPlotClipRect ( ) ;
2020-05-29 13:39:30 -04:00
T a0 = angle0 * 2 * IM_PI / 360.0f ;
T a1 = angle0 * 2 * IM_PI / 360.0f ;
2020-05-03 01:24:10 -04:00
for ( int i = 0 ; i < count ; + + i ) {
ImPlotItem * item = RegisterItem ( label_ids [ i ] ) ;
2020-05-12 05:19:04 -04:00
ImU32 col = ImGui : : GetColorU32 ( item - > Color ) ;
2020-05-29 13:39:30 -04:00
T percent = normalize ? values [ i ] / sum : values [ i ] ;
2020-05-03 01:24:10 -04:00
a1 = a0 + 2 * IM_PI * percent ;
if ( item - > Show ) {
if ( percent < 0.5 ) {
DrawPieSlice ( DrawList , center , radius , a0 , a1 , col ) ;
}
else {
DrawPieSlice ( DrawList , center , radius , a0 , a0 + ( a1 - a0 ) * 0.5f , col ) ;
DrawPieSlice ( DrawList , center , radius , a0 + ( a1 - a0 ) * 0.5f , a1 , col ) ;
}
}
a0 = a1 ;
2020-05-13 10:11:25 -04:00
}
2020-06-04 10:56:50 -04:00
if ( fmt ! = NULL ) {
a0 = angle0 * 2 * IM_PI / 360.0f ;
a1 = angle0 * 2 * IM_PI / 360.0f ;
char buffer [ 32 ] ;
for ( int i = 0 ; i < count ; + + i ) {
T percent = normalize ? values [ i ] / sum : values [ i ] ;
a1 = a0 + 2 * IM_PI * percent ;
sprintf ( buffer , fmt , values [ i ] ) ;
ImVec2 size = ImGui : : CalcTextSize ( buffer ) ;
T angle = a0 + ( a1 - a0 ) * 0.5f ;
ImVec2 pos = PlotToPixels ( center . x + 0.5f * radius * cos ( angle ) , center . y + 0.5f * radius * sin ( angle ) ) ;
DrawList . AddText ( pos - size * 0.5f + ImVec2 ( 1 , 1 ) , IM_COL32 ( 0 , 0 , 0 , 255 ) , buffer ) ;
DrawList . AddText ( pos - size * 0.5f , IM_COL32 ( 255 , 255 , 255 , 255 ) , buffer ) ;
a0 = a1 ;
}
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect ( ) ;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-06-04 10:56:50 -04:00
void PlotPieChart ( const char * * label_ids , const float * values , int count , float x , float y , float radius , bool normalize , const char * fmt , float angle0 ) {
return PlotPieChartEx ( label_ids , values , count , x , y , radius , normalize , fmt , angle0 ) ;
2020-05-29 13:39:30 -04:00
}
//-----------------------------------------------------------------------------
// double
2020-06-04 10:56:50 -04:00
void PlotPieChart ( const char * * label_ids , const double * values , int count , double x , double y , double radius , bool normalize , const char * fmt , double angle0 ) {
return PlotPieChartEx ( label_ids , values , count , x , y , radius , normalize , fmt , angle0 ) ;
2020-04-27 11:27:59 -04:00
}
2020-06-01 18:33:01 -04:00
//-----------------------------------------------------------------------------
// PLOT HEATMAP
//-----------------------------------------------------------------------------
2020-06-02 23:07:27 -04:00
template < typename T , typename Transformer >
2020-06-03 23:18:47 -04:00
void RenderHeatmap ( Transformer transformer , ImDrawList & DrawList , const T * values , int rows , int cols , T scale_min , T scale_max , const char * fmt , const ImPlotPoint & bounds_min , const ImPlotPoint & bounds_max ) {
2020-06-02 13:34:14 -04:00
const double w = ( bounds_max . x - bounds_min . x ) / cols ;
const double h = ( bounds_max . y - bounds_min . y ) / rows ;
2020-06-01 23:14:22 -04:00
const ImPlotPoint half_size ( w * 0.5 , h * 0.5 ) ;
2020-06-02 13:34:14 -04:00
const int n = rows * cols ;
2020-06-01 23:14:22 -04:00
int i = 0 ;
2020-06-02 13:34:14 -04:00
DrawList . PrimReserve ( 6 * n , 4 * n ) ;
const ImVec2 uv = DrawList . _Data - > TexUvWhitePixel ;
2020-06-01 23:14:22 -04:00
for ( int r = 0 ; r < rows ; + + r ) {
for ( int c = 0 ; c < cols ; + + c ) {
ImPlotPoint p ;
2020-06-02 13:34:14 -04:00
p . x = bounds_min . x + 0.5 * w + c * w ;
p . y = bounds_min . y + 1 - ( 0.5 * h + r * h ) ;
2020-06-02 23:07:27 -04:00
ImVec2 a = transformer ( p . x - half_size . x , p . y - half_size . y ) ;
ImVec2 b = transformer ( p . x + half_size . x , p . y + half_size . y ) ;
float t = ( float ) Remap ( values [ i ] , scale_min , scale_max , T ( 0 ) , T ( 1 ) ) ;
2020-06-02 13:34:14 -04:00
ImVec4 color = LerpColormap ( t ) ;
2020-06-02 23:07:27 -04:00
ImU32 col = ImGui : : GetColorU32 ( color ) ;
RenderRect ( DrawList , a , b , col , col , col , col , uv ) ;
2020-06-02 13:34:14 -04:00
i + + ;
}
}
2020-06-03 23:18:47 -04:00
if ( fmt ! = NULL ) {
2020-06-02 13:34:14 -04:00
// this has to go in its own loop due to PrimReserve above
i = 0 ;
for ( int r = 0 ; r < rows ; + + r ) {
for ( int c = 0 ; c < cols ; + + c ) {
ImPlotPoint p ;
p . x = bounds_min . x + 0.5 * w + c * w ;
p . y = bounds_min . y + 1 - ( 0.5 * h + r * h ) ;
2020-06-02 23:07:27 -04:00
ImVec2 px = transformer ( p ) ;
2020-06-01 23:14:22 -04:00
char buff [ 32 ] ;
2020-06-03 23:18:47 -04:00
sprintf ( buff , fmt , values [ i ] ) ;
2020-06-01 23:14:22 -04:00
ImVec2 size = ImGui : : CalcTextSize ( buff ) ;
DrawList . AddText ( px - size * 0.5f , ImGui : : GetColorU32 ( ImGuiCol_Text ) , buff ) ;
2020-06-02 13:34:14 -04:00
i + + ;
2020-06-01 23:14:22 -04:00
}
}
}
2020-06-02 23:07:27 -04:00
}
template < typename T >
2020-06-03 23:18:47 -04:00
void PlotHeatmapEx ( const char * label_id , const T * values , int rows , int cols , T scale_min , T scale_max , const char * fmt , const ImPlotPoint & bounds_min , const ImPlotPoint & bounds_max ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotHeatmap() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-06-02 23:07:27 -04:00
IM_ASSERT_USER_ERROR ( scale_min ! = scale_max , " Scale values must be different! " ) ;
ImPlotItem * item = RegisterItem ( label_id ) ;
if ( ! item - > Show )
return ;
if ( gp . FitThisFrame ) {
FitPoint ( bounds_min ) ;
FitPoint ( bounds_max ) ;
}
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
2020-06-04 10:56:50 -04:00
ImGui : : PushClipRect ( gp . BB_Plot . Min , gp . BB_Plot . Max , true ) ;
2020-06-02 23:07:27 -04:00
ImPlotState * plot = gp . CurrentPlot ;
int y_axis = plot - > CurrentYAxis ;
if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) & & HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-06-03 23:18:47 -04:00
RenderHeatmap ( TransformerLogLog ( y_axis ) , DrawList , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-02 23:07:27 -04:00
else if ( HasFlag ( plot - > XAxis . Flags , ImPlotAxisFlags_LogScale ) )
2020-06-03 23:18:47 -04:00
RenderHeatmap ( TransformerLogLin ( y_axis ) , DrawList , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-02 23:07:27 -04:00
else if ( HasFlag ( plot - > YAxis [ y_axis ] . Flags , ImPlotAxisFlags_LogScale ) )
2020-06-03 23:18:47 -04:00
RenderHeatmap ( TransformerLinLog ( y_axis ) , DrawList , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-02 23:07:27 -04:00
else
2020-06-03 23:18:47 -04:00
RenderHeatmap ( TransformerLinLin ( y_axis ) , DrawList , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-01 23:14:22 -04:00
ImGui : : PopClipRect ( ) ;
2020-06-01 18:33:01 -04:00
}
2020-06-02 23:07:27 -04:00
//-----------------------------------------------------------------------------
// float
2020-06-03 23:18:47 -04:00
void PlotHeatmap ( const char * label_id , const float * values , int rows , int cols , float scale_min , float scale_max , const char * fmt , const ImPlotPoint & bounds_min , const ImPlotPoint & bounds_max ) {
return PlotHeatmapEx ( label_id , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-02 23:07:27 -04:00
}
//-----------------------------------------------------------------------------
// double
2020-06-03 23:18:47 -04:00
void PlotHeatmap ( const char * label_id , const double * values , int rows , int cols , double scale_min , double scale_max , const char * fmt , const ImPlotPoint & bounds_min , const ImPlotPoint & bounds_max ) {
return PlotHeatmapEx ( label_id , values , rows , cols , scale_min , scale_max , fmt , bounds_min , bounds_max ) ;
2020-06-02 23:07:27 -04:00
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// PLOT DIGITAL
//-----------------------------------------------------------------------------
2020-05-04 05:14:44 -04:00
template < typename Getter >
inline void PlotDigitalEx ( const char * label_id , Getter getter , int count , int offset )
{
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotDigital() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-04 05:14:44 -04:00
ImPlotItem * item = RegisterItem ( label_id ) ;
if ( ! item - > Show )
return ;
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
const bool rend_line = gp . Style . Colors [ ImPlotCol_Line ] . w ! = 0 & & gp . Style . LineWeight > 0 ;
if ( gp . Style . Colors [ ImPlotCol_Line ] . w ! = - 1 )
item - > Color = gp . Style . Colors [ ImPlotCol_Line ] ;
2020-05-29 13:39:30 -04:00
2020-06-04 10:56:50 -04:00
ImGui : : PushClipRect ( gp . BB_Plot . Min , gp . BB_Plot . Max , true ) ;
2020-05-04 05:14:44 -04:00
bool cull = HasFlag ( gp . CurrentPlot - > Flags , ImPlotFlags_CullData ) ;
const float line_weight = item - > Highlight ? gp . Style . LineWeight * 2 : gp . Style . LineWeight ;
2020-05-11 07:12:22 -04:00
const int ax = gp . CurrentPlot - > CurrentYAxis ;
2020-05-04 05:14:44 -04:00
// render digital signals as "pixel bases" rectangles
if ( count > 1 & & rend_line ) {
2020-05-04 08:17:39 -04:00
//
2020-05-16 22:53:59 -04:00
const int segments = count - 1 ;
2020-05-04 05:14:44 -04:00
int i1 = offset ;
2020-05-09 00:54:16 -04:00
int pixYMax = 0 ;
2020-05-04 05:14:44 -04:00
for ( int s = 0 ; s < segments ; + + s ) {
const int i2 = ( i1 + 1 ) % count ;
2020-05-16 22:53:59 -04:00
ImPlotPoint itemData1 = getter ( i1 ) ;
ImPlotPoint itemData2 = getter ( i2 ) ;
2020-05-04 05:14:44 -04:00
i1 = i2 ;
2020-05-10 22:43:12 -04:00
int pixY_0 = ( int ) ( line_weight ) ;
2020-05-17 00:25:15 -04:00
itemData1 . y = itemData1 . y < 0 ? 0 : itemData1 . y ;
float pixY_1_float = gp . Style . DigitalBitHeight * ( float ) itemData1 . y ;
2020-05-10 22:43:12 -04:00
int pixY_1 = ( int ) ( pixY_1_float ) ; //allow only positive values
int pixY_chPosOffset = ( int ) ( ImMax ( gp . Style . DigitalBitHeight , pixY_1_float ) + gp . Style . DigitalBitGap ) ;
2020-05-09 00:54:16 -04:00
pixYMax = ImMax ( pixYMax , pixY_chPosOffset ) ;
2020-05-16 22:53:59 -04:00
ImVec2 pMin = PlotToPixels ( itemData1 ) ;
ImVec2 pMax = PlotToPixels ( itemData2 ) ;
int pixY_Offset = 20 ; //20 pixel from bottom due to mouse cursor label
2020-05-11 07:12:22 -04:00
pMin . y = ( gp . PixelRange [ ax ] . Min . y ) + ( ( - gp . DigitalPlotOffset ) - pixY_Offset ) ;
pMax . y = ( gp . PixelRange [ ax ] . Min . y ) + ( ( - gp . DigitalPlotOffset ) - pixY_0 - pixY_1 - pixY_Offset ) ;
2020-05-04 09:16:04 -04:00
//plot only one rectangle for same digital state
2020-05-09 00:54:16 -04:00
while ( ( ( s + 2 ) < segments ) & & ( itemData1 . y = = itemData2 . y ) ) {
2020-05-10 22:43:12 -04:00
const int i3 = ( i1 + 1 ) % count ;
itemData2 = getter ( i3 ) ;
2020-05-16 22:53:59 -04:00
pMax . x = PlotToPixels ( itemData2 ) . x ;
2020-05-10 22:43:12 -04:00
i1 = i3 ;
2020-05-04 08:17:39 -04:00
s + + ;
2020-05-13 10:11:25 -04:00
}
2020-05-04 09:16:04 -04:00
//do not extend plot outside plot range
2020-05-11 07:12:22 -04:00
if ( pMin . x < gp . PixelRange [ ax ] . Min . x ) pMin . x = gp . PixelRange [ ax ] . Min . x ;
if ( pMax . x < gp . PixelRange [ ax ] . Min . x ) pMax . x = gp . PixelRange [ ax ] . Min . x ;
if ( pMin . x > gp . PixelRange [ ax ] . Max . x ) pMin . x = gp . PixelRange [ ax ] . Max . x ;
if ( pMax . x > gp . PixelRange [ ax ] . Max . x ) pMax . x = gp . PixelRange [ ax ] . Max . x ;
2020-05-04 09:16:04 -04:00
//plot a rectangle that extends up to x2 with y1 height
2020-06-04 10:56:50 -04:00
if ( ( pMax . x > pMin . x ) & & ( ! cull | | gp . BB_Plot . Contains ( pMin ) | | gp . BB_Plot . Contains ( pMax ) ) ) {
2020-05-11 07:12:22 -04:00
ImVec4 colAlpha = item - > Color ;
colAlpha . w = item - > Highlight ? 1.0f : 0.9f ;
2020-05-12 05:19:04 -04:00
DrawList . AddRectFilled ( pMin , pMax , ImGui : : GetColorU32 ( colAlpha ) ) ;
2020-05-04 05:14:44 -04:00
}
}
gp . DigitalPlotItemCnt + + ;
2020-05-09 00:54:16 -04:00
gp . DigitalPlotOffset + = pixYMax ;
2020-05-13 10:11:25 -04:00
}
2020-05-04 05:14:44 -04:00
ImGui : : PopClipRect ( ) ;
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// float
2020-05-16 09:39:43 -04:00
void PlotDigital ( const char * label_id , const float * xs , const float * ys , int count , int offset , int stride ) {
2020-05-29 13:39:30 -04:00
GetterXsYs < float > getter ( xs , ys , stride ) ;
2020-05-04 05:14:44 -04:00
return PlotDigitalEx ( label_id , getter , count , offset ) ;
}
2020-05-29 13:39:30 -04:00
//-----------------------------------------------------------------------------
// double
void PlotDigital ( const char * label_id , const double * xs , const double * ys , int count , int offset , int stride ) {
GetterXsYs < double > getter ( xs , ys , stride ) ;
return PlotDigitalEx ( label_id , getter , count , offset ) ;
}
2020-05-31 10:07:24 -04:00
//-----------------------------------------------------------------------------
// custom
2020-05-29 13:39:30 -04:00
void PlotDigital ( const char * label_id , ImPlotPoint ( * getter_func ) ( void * data , int idx ) , void * data , int count , int offset ) {
GetterFuncPtrImPlotPoint getter ( getter_func , data ) ;
return PlotDigitalEx ( label_id , getter , count , offset ) ;
}
//-----------------------------------------------------------------------------
// PLOT TEXT
//-----------------------------------------------------------------------------
// float
void PlotText ( const char * text , float x , float y , bool vertical , const ImVec2 & pixel_offset ) {
return PlotText ( text , ( double ) x , ( double ) y , vertical , pixel_offset ) ;
}
//-----------------------------------------------------------------------------
// double
void PlotText ( const char * text , double x , double y , bool vertical , const ImVec2 & pixel_offset ) {
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR ( gp . CurrentPlot ! = NULL , " PlotText() needs to be called between BeginPlot() and EndPlot()! " ) ;
2020-05-29 13:39:30 -04:00
ImDrawList & DrawList = * ImGui : : GetWindowDrawList ( ) ;
PushPlotClipRect ( ) ;
ImVec2 pos = PlotToPixels ( ImPlotPoint ( x , y ) ) + pixel_offset ;
if ( vertical )
AddTextVertical ( & DrawList , text , pos , gp . Col_Txt ) ;
else
DrawList . AddText ( pos , gp . Col_Txt , text ) ;
PopPlotClipRect ( ) ;
}
2020-06-02 13:34:14 -04:00
//------------------------------------------------------------------------------
// COLORMAPS
//------------------------------------------------------------------------------
void SetColormap ( const ImVec4 * colors , int num_colors ) {
2020-06-02 23:07:27 -04:00
IM_ASSERT_USER_ERROR ( num_colors > 1 , " The number of colors must be greater than 1! " ) ;
2020-06-02 13:34:14 -04:00
static ImVector < ImVec4 > user_colormap ;
user_colormap . shrink ( 0 ) ;
user_colormap . reserve ( num_colors ) ;
2020-06-02 23:07:27 -04:00
for ( int i = 0 ; i < num_colors ; + + i )
user_colormap . push_back ( colors [ i ] ) ;
2020-06-02 13:34:14 -04:00
gp . Colormap = & user_colormap [ 0 ] ;
gp . ColormapSize = num_colors ;
}
// Returns the size of the current colormap
int GetColormapSize ( ) {
return gp . ColormapSize ;
}
2020-06-04 10:56:50 -04:00
// Returns a color from the Color map given an index > 0
2020-06-02 13:34:14 -04:00
ImVec4 GetColormapColor ( int index ) {
IM_ASSERT_USER_ERROR ( index > = 0 , " The Colormap index must be greater than zero! " ) ;
return gp . Colormap [ index % gp . ColormapSize ] ;
}
ImVec4 LerpColormap ( float t ) {
2020-06-02 23:07:27 -04:00
float tc = ImClamp ( t , 0.0f , 1.0f ) ;
int i1 = ( int ) ( ( gp . ColormapSize - 1 ) * tc ) ;
2020-06-02 13:34:14 -04:00
int i2 = i1 + 1 ;
if ( i2 = = gp . ColormapSize )
return gp . Colormap [ i1 ] ;
2020-06-02 23:07:27 -04:00
float t1 = ( float ) i1 / ( float ) ( gp . ColormapSize - 1 ) ;
float t2 = ( float ) i2 / ( float ) ( gp . ColormapSize - 1 ) ;
float tr = Remap ( t , t1 , t2 , 0.0f , 1.0f ) ;
return ImLerp ( gp . Colormap [ i1 ] , gp . Colormap [ i2 ] , tr ) ;
}
void ShowColormapScale ( double scale_min , double scale_max , float height ) {
2020-06-03 10:54:25 -04:00
static ImVector < ImPlotTick > ticks ;
2020-06-02 23:07:27 -04:00
static ImGuiTextBuffer txt_buff ;
ImPlotRange range ;
range . Min = scale_min ;
range . Max = scale_max ;
2020-06-03 15:37:01 -04:00
ticks . shrink ( 0 ) ;
txt_buff . Buf . shrink ( 0 ) ;
AddDefaultTicks ( range , 10 , 0 , false , ticks ) ;
2020-06-02 23:07:27 -04:00
LabelTicks ( ticks , false , txt_buff ) ;
float max_width = 0 ;
for ( int i = 0 ; i < ticks . Size ; + + i )
max_width = ticks [ i ] . Size . x > max_width ? ticks [ i ] . Size . x : max_width ;
ImGuiContext & G = * GImGui ;
ImGuiWindow * Window = G . CurrentWindow ;
if ( Window - > SkipItems )
return ;
const ImGuiStyle & Style = G . Style ;
const float txt_off = 5 ;
const float bar_w = 20 ;
ImDrawList & DrawList = * Window - > DrawList ;
ImVec2 size ( bar_w + txt_off + max_width + 2 * Style . WindowPadding . x , height ) ;
ImRect bb_frame = ImRect ( Window - > DC . CursorPos , Window - > DC . CursorPos + size ) ;
ImGui : : ItemSize ( bb_frame ) ;
if ( ! ImGui : : ItemAdd ( bb_frame , 0 , & bb_frame ) )
return ;
ImGui : : RenderFrame ( bb_frame . Min , bb_frame . Max , ImGui : : GetColorU32 ( ImGuiCol_FrameBg ) ) ;
ImRect bb_grad ( bb_frame . Min + Style . WindowPadding , bb_frame . Min + ImVec2 ( bar_w + Style . WindowPadding . x , height - Style . WindowPadding . y ) ) ;
int num_cols = GetColormapSize ( ) ;
float h_step = ( height - 2 * Style . WindowPadding . y ) / ( num_cols - 1 ) ;
for ( int i = 0 ; i < num_cols - 1 ; + + i ) {
ImRect rect ( bb_grad . Min . x , bb_grad . Min . y + h_step * i , bb_grad . Max . x , bb_grad . Min . y + h_step * ( i + 1 ) ) ;
ImU32 col1 = ImGui : : GetColorU32 ( GetColormapColor ( num_cols - 1 - i ) ) ;
ImU32 col2 = ImGui : : GetColorU32 ( GetColormapColor ( num_cols - 1 - ( i + 1 ) ) ) ;
DrawList . AddRectFilledMultiColor ( rect . Min , rect . Max , col1 , col1 , col2 , col2 ) ;
}
ImU32 col_border = gp . Style . Colors [ ImPlotCol_PlotBorder ] . w = = - 1 ? ImGui : : GetColorU32 ( ImGuiCol_Text , 0.5f ) : ImGui : : GetColorU32 ( gp . Style . Colors [ ImPlotCol_PlotBorder ] ) ;
ImGui : : PushClipRect ( bb_frame . Min , bb_frame . Max , true ) ;
for ( int i = 0 ; i < ticks . Size ; + + i ) {
float ypos = Remap ( ( float ) ticks [ i ] . PlotPos , ( float ) range . Max , ( float ) range . Min , bb_grad . Min . y , bb_grad . Max . y ) ;
if ( ypos < bb_grad . Max . y - 2 & & ypos > bb_grad . Min . y + 2 )
DrawList . AddLine ( ImVec2 ( bb_grad . Max . x - 1 , ypos ) , ImVec2 ( bb_grad . Max . x - ( ticks [ i ] . Major ? 10.0f : 5.0f ) , ypos ) , col_border , 1.0f ) ;
DrawList . AddText ( ImVec2 ( bb_grad . Max . x - 1 , ypos ) + ImVec2 ( txt_off , - ticks [ i ] . Size . y * 0.5f ) , ImGui : : GetColorU32 ( ImGuiCol_Text ) , txt_buff . Buf . Data + ticks [ i ] . TextOffset ) ;
}
ImGui : : PopClipRect ( ) ;
DrawList . AddRect ( bb_grad . Min , bb_grad . Max , col_border ) ;
2020-06-02 13:34:14 -04:00
}
2020-06-03 23:18:47 -04:00
void SetColormap ( ImPlotColormap colormap , int samples ) {
2020-06-02 13:34:14 -04:00
static int csizes [ ImPlotColormap_COUNT ] = { 10 , 9 , 9 , 12 , 11 , 11 , 11 , 11 , 11 , 11 } ;
static OffsetCalculator < ImPlotCol_COUNT > coffs ( csizes ) ;
static ImVec4 cdata [ ] {
// ImPlotColormap_Default // X11 Named Colors
ImVec4 ( 0.0f , 0.7490196228f , 1.0f , 1.0f ) , // Blues::DeepSkyBlue,
ImVec4 ( 1.0f , 0.0f , 0.0f , 1.0f ) , // Reds::Red,
ImVec4 ( 0.4980392158f , 1.0f , 0.0f , 1.0f ) , // Greens::Chartreuse,
ImVec4 ( 1.0f , 1.0f , 0.0f , 1.0f ) , // Yellows::Yellow,
ImVec4 ( 0.0f , 1.0f , 1.0f , 1.0f ) , // Cyans::Cyan,
ImVec4 ( 1.0f , 0.6470588446f , 0.0f , 1.0f ) , // Oranges::Orange,
ImVec4 ( 1.0f , 0.0f , 1.0f , 1.0f ) , // Purples::Magenta,
ImVec4 ( 0.5411764979f , 0.1686274558f , 0.8862745166f , 1.0f ) , // Purples::BlueViolet,
ImVec4 ( 0.5f , 0.5f , 0.5f , 1.0f ) , // Grays::Gray50,
ImVec4 ( 0.8235294223f , 0.7058823705f , 0.5490196347f , 1.0f ) , // Browns::Tan
// ImPlotColormap_Dark
ImVec4 ( 0.894118f , 0.101961f , 0.109804f , 1.0f ) ,
ImVec4 ( 0.215686f , 0.494118f , 0.721569f , 1.0f ) ,
ImVec4 ( 0.301961f , 0.686275f , 0.290196f , 1.0f ) ,
ImVec4 ( 0.596078f , 0.305882f , 0.639216f , 1.0f ) ,
ImVec4 ( 1.000000f , 0.498039f , 0.000000f , 1.0f ) ,
ImVec4 ( 1.000000f , 1.000000f , 0.200000f , 1.0f ) ,
ImVec4 ( 0.650980f , 0.337255f , 0.156863f , 1.0f ) ,
ImVec4 ( 0.968627f , 0.505882f , 0.749020f , 1.0f ) ,
ImVec4 ( 0.600000f , 0.600000f , 0.600000f , 1.0f ) ,
// ImPlotColormap_Pastel
ImVec4 ( 0.984314f , 0.705882f , 0.682353f , 1.0f ) ,
ImVec4 ( 0.701961f , 0.803922f , 0.890196f , 1.0f ) ,
ImVec4 ( 0.800000f , 0.921569f , 0.772549f , 1.0f ) ,
ImVec4 ( 0.870588f , 0.796078f , 0.894118f , 1.0f ) ,
ImVec4 ( 0.996078f , 0.850980f , 0.650980f , 1.0f ) ,
ImVec4 ( 1.000000f , 1.000000f , 0.800000f , 1.0f ) ,
ImVec4 ( 0.898039f , 0.847059f , 0.741176f , 1.0f ) ,
ImVec4 ( 0.992157f , 0.854902f , 0.925490f , 1.0f ) ,
ImVec4 ( 0.949020f , 0.949020f , 0.949020f , 1.0f ) ,
// ImPlotColormap_Paired
ImVec4 ( 0.258824f , 0.807843f , 0.890196f , 1.0f ) ,
ImVec4 ( 0.121569f , 0.470588f , 0.705882f , 1.0f ) ,
ImVec4 ( 0.698039f , 0.874510f , 0.541176f , 1.0f ) ,
ImVec4 ( 0.200000f , 0.627451f , 0.172549f , 1.0f ) ,
ImVec4 ( 0.984314f , 0.603922f , 0.600000f , 1.0f ) ,
ImVec4 ( 0.890196f , 0.101961f , 0.109804f , 1.0f ) ,
ImVec4 ( 0.992157f , 0.749020f , 0.435294f , 1.0f ) ,
ImVec4 ( 1.000000f , 0.498039f , 0.000000f , 1.0f ) ,
ImVec4 ( 0.792157f , 0.698039f , 0.839216f , 1.0f ) ,
ImVec4 ( 0.415686f , 0.239216f , 0.603922f , 1.0f ) ,
ImVec4 ( 1.000000f , 1.000000f , 0.600000f , 1.0f ) ,
ImVec4 ( 0.694118f , 0.349020f , 0.156863f , 1.0f ) ,
// ImPlotColormap_Viridis
ImVec4 ( 0.267004f , 0.004874f , 0.329415f , 1.0f ) ,
ImVec4 ( 0.282623f , 0.140926f , 0.457517f , 1.0f ) ,
ImVec4 ( 0.253935f , 0.265254f , 0.529983f , 1.0f ) ,
ImVec4 ( 0.206756f , 0.371758f , 0.553117f , 1.0f ) ,
ImVec4 ( 0.163625f , 0.471133f , 0.558148f , 1.0f ) ,
ImVec4 ( 0.127568f , 0.566949f , 0.550556f , 1.0f ) ,
ImVec4 ( 0.134692f , 0.658636f , 0.517649f , 1.0f ) ,
ImVec4 ( 0.266941f , 0.748751f , 0.440573f , 1.0f ) ,
ImVec4 ( 0.477504f , 0.821444f , 0.318195f , 1.0f ) ,
ImVec4 ( 0.741388f , 0.873449f , 0.149561f , 1.0f ) ,
ImVec4 ( 0.993248f , 0.906157f , 0.143936f , 1.0f ) ,
// ImPlotColormap_Plasma
ImVec4 ( 5.03830e-02 f , 2.98030e-02 f , 5.27975e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 2.54627e-01 f , 1.38820e-02 f , 6.15419e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 4.17642e-01 f , 5.64000e-04 f , 6.58390e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 5.62738e-01 f , 5.15450e-02 f , 6.41509e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 6.92840e-01 f , 1.65141e-01 f , 5.64522e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 7.98216e-01 f , 2.80197e-01 f , 4.69538e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 8.81443e-01 f , 3.92529e-01 f , 3.83229e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 9.49217e-01 f , 5.17763e-01 f , 2.95662e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 9.88260e-01 f , 6.52325e-01 f , 2.11364e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 9.88648e-01 f , 8.09579e-01 f , 1.45357e-01 f , 1.00000e+00 f ) ,
ImVec4 ( 9.40015e-01 f , 9.75158e-01 f , 1.31326e-01 f , 1.00000e+00 f ) ,
// ImPlotColormap_Hot
ImVec4 ( 0.2500f , 0.f , 0.f , 1.0f ) ,
ImVec4 ( 0.5000f , 0.f , 0.f , 1.0f ) ,
ImVec4 ( 0.7500f , 0.f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.2500f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.5000f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.7500f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 0.3333f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 0.6667f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 1.0000f , 1.0f ) ,
// ImPlotColormap_Cool
ImVec4 ( 0.f , 1.0000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.1000f , 0.9000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.2000f , 0.8000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.3000f , 0.7000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.4000f , 0.6000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.5000f , 0.5000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.6000f , 0.4000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.7000f , 0.3000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.8000f , 0.2000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.9000f , 0.1000f , 1.0000f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.f , 1.0000f , 1.0f ) ,
// ImPlotColormap_Pink
ImVec4 ( 0.2887f , 0.f , 0.f , 1.0f ) ,
ImVec4 ( 0.4830f , 0.2582f , 0.2582f , 1.0f ) ,
ImVec4 ( 0.6191f , 0.3651f , 0.3651f , 1.0f ) ,
ImVec4 ( 0.7303f , 0.4472f , 0.4472f , 1.0f ) ,
ImVec4 ( 0.7746f , 0.5916f , 0.5164f , 1.0f ) ,
ImVec4 ( 0.8165f , 0.7071f , 0.5774f , 1.0f ) ,
ImVec4 ( 0.8563f , 0.8062f , 0.6325f , 1.0f ) ,
ImVec4 ( 0.8944f , 0.8944f , 0.6831f , 1.0f ) ,
ImVec4 ( 0.9309f , 0.9309f , 0.8028f , 1.0f ) ,
ImVec4 ( 0.9661f , 0.9661f , 0.9068f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 1.0000f , 1.0f ) ,
// ImPlotColormap_Jet
ImVec4 ( 0.f , 0.f , 0.6667f , 1.0f ) ,
ImVec4 ( 0.f , 0.f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.f , 0.3333f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.f , 0.6667f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.f , 1.0000f , 1.0000f , 1.0f ) ,
ImVec4 ( 0.3333f , 1.0000f , 0.6667f , 1.0f ) ,
ImVec4 ( 0.6667f , 1.0000f , 0.3333f , 1.0f ) ,
ImVec4 ( 1.0000f , 1.0000f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.6667f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.3333f , 0.f , 1.0f ) ,
ImVec4 ( 1.0000f , 0.f , 0.f , 1.0f )
} ;
// TODO: Calculate offsets at compile time
gp . Colormap = & cdata [ coffs . Offsets [ colormap ] ] ;
gp . ColormapSize = csizes [ colormap ] ;
2020-06-03 23:18:47 -04:00
if ( samples > 1 ) {
static ImVector < ImVec4 > resampled ;
resampled . resize ( samples ) ;
for ( int i = 0 ; i < samples ; + + i ) {
float t = i * 1.0f / ( samples - 1 ) ;
resampled [ i ] = LerpColormap ( t ) ;
}
SetColormap ( & resampled [ 0 ] , samples ) ;
}
2020-06-02 13:34:14 -04:00
}
2020-05-29 17:31:50 -04:00
} // namespace ImPlot