Zep’s display layer is a minimal abstraction that allows you to render the editor using any graphics API. By implementing just four drawing methods, you can integrate Zep with ImGui, Qt, SDL, or any other rendering system.
ZepDisplay Abstract Class
From include/zep/display.h:71-83:
class ZepDisplay
{
public:
virtual ~ZepDisplay (){};
ZepDisplay ();
// Renderer specific overrides
// Implement these to draw the buffer using whichever system you prefer
virtual void DrawLine ( const NVec2f & start , const NVec2f & end ,
const NVec4f & color = NVec4f ( 1.0 f ),
float width = 1.0 f ) const = 0 ;
virtual void DrawChars ( ZepFont & font , const NVec2f & pos ,
const NVec4f & col ,
const uint8_t* text_begin ,
const uint8_t* text_end = nullptr ) const = 0 ;
virtual void DrawRectFilled ( const NRectf & rc ,
const NVec4f & col = NVec4f ( 1.0 f )) const = 0 ;
virtual void SetClipRect ( const NRectf & rc ) = 0 ;
DrawLine Draw a line between two points with color and width
DrawChars Render text at a position using the specified font
DrawRectFilled Draw a filled rectangle
SetClipRect Set the clipping region for rendering
That’s it! These four methods are all you need to implement to render the entire editor with full functionality.
ZepFont Abstract Class
Along with the display, you need to implement a font class:
From include/zep/display.h:36-58:
class ZepFont
{
public:
ZepFont ( ZepDisplay & display )
: m_display (display)
{
}
// Implemented in API specific ways
virtual void SetPixelHeight ( int height ) = 0 ;
virtual NVec2f GetTextSize ( const uint8_t* pBegin ,
const uint8_t* pEnd = nullptr ) const = 0 ;
virtual int GetPixelHeight () const
{
return m_pixelHeight;
}
virtual const NVec2f & GetDefaultCharSize ();
virtual const NVec2f & GetDotSize ();
virtual void BuildCharCache ();
virtual void InvalidateCharCache ();
virtual NVec2f GetCharSize ( const uint8_t* pChar );
Font Requirements
SetPixelHeight : Configure the font size
GetTextSize : Measure text dimensions for layout
Character caching : Optional optimization for common chars
Zep uses monospace fonts. The GetDefaultCharSize() method returns the width and height of a typical character, which is used for grid layout.
Null Renderer Example
Zep includes a null renderer for testing:
From include/zep/display.h:127-174:
class ZepDisplayNull : public ZepDisplay
{
public:
ZepDisplayNull ()
: ZepDisplay ()
{
}
virtual void DrawLine ( const NVec2f & start , const NVec2f & end ,
const NVec4f & color = NVec4f ( 1.0 f ),
float width = 1.0 f ) const override
{
// No-op: discard
};
virtual void DrawChars ( ZepFont & , const NVec2f & pos , const NVec4f & col ,
const uint8_t* text_begin ,
const uint8_t* text_end = nullptr ) const override
{
// No-op: discard
}
virtual void DrawRectFilled ( const NRectf & a ,
const NVec4f & col = NVec4f ( 1.0 f )) const override
{
// No-op: discard
};
virtual void SetClipRect ( const NRectf & rc ) override
{
// No-op: discard
}
virtual ZepFont & GetFont ( ZepTextType type ) override
{
if ( m_fonts [( int )type] == nullptr )
{
if (m_spDefaultFont == nullptr )
{
m_spDefaultFont = std :: make_shared < ZepFontNull >( * this );
}
return * m_spDefaultFont;
}
return * m_fonts [( int )type];
}
};
ZepFontNull Implementation
From include/zep/display.h:108-125: class ZepFontNull : public ZepFont
{
public:
ZepFontNull ( ZepDisplay & display )
: ZepFont (display)
{
}
virtual void SetPixelHeight ( int val ) override
{
// No-op
}
virtual NVec2f GetTextSize ( const uint8_t* pBegin ,
const uint8_t* pEnd = nullptr ) const override
{
return NVec2f ( float (pEnd - pBegin), 10.0 f );
}
};
The null font assumes 1 pixel per character width, 10 pixels height.
Font Types
Zep supports multiple font types for different UI elements:
From include/zep/display.h:24-32:
enum class ZepTextType
{
UI , // UI elements, tabs, status bar
Text , // Main editor text
Heading1 , // Markdown heading level 1
Heading2 , // Markdown heading level 2
Heading3 , // Markdown heading level 3
Count
};
From include/zep/display.h:89-90:
virtual void SetFont ( ZepTextType type , std :: shared_ptr < ZepFont > spFont );
virtual ZepFont & GetFont ( ZepTextType type ) = 0 ;
You can provide different fonts for headings and UI elements, or use the same font for everything.
Rendering Flow
When Zep renders, the following sequence occurs:
What Gets Drawn
Background rectangles - Editor background, line highlights
Text characters - Buffer content with syntax colors
Selection highlights - Visual mode selections
Cursors - Block or line cursor
Line numbers - Left gutter
Status bar - File info, mode, position
Tabs - Multiple file tabs
Indicators - Error markers, search highlights
Coordinate System
Zep uses a standard 2D coordinate system:
Origin : Top-left corner
Units : Pixels
Types :
NVec2f - 2D float vector (x, y)
NVec4f - 4D float vector for colors (r, g, b, a)
NRectf - Rectangle (topLeft, bottomRight)
struct NVec2f {
float x, y;
};
struct NVec4f {
float x, y, z, w; // or r, g, b, a
};
struct NRectf {
NVec2f topLeftPx;
NVec2f bottomRightPx;
};
DPI Scaling
Zep supports high-DPI displays through pixel scale:
From include/zep/display.h:91-92:
const NVec2f & GetPixelScale () const ;
void SetPixelScale ( const NVec2f & scale );
From include/zep/editor.h:224-227:
#define DPI_VEC2 ( value ) (value * GetEditor (). GetDisplay (). GetPixelScale ())
#define DPI_Y ( value ) ( GetEditor (). GetDisplay (). GetPixelScale (). y * value)
#define DPI_X ( value ) ( GetEditor (). GetDisplay (). GetPixelScale (). x * value)
#define DPI_RECT ( value ) (value * GetEditor (). GetDisplay (). GetPixelScale ())
Set pixel scale to (2.0, 2.0) for Retina/4K displays to ensure crisp rendering.
Implementing a Custom Display
Here’s a minimal example for a hypothetical graphics API:
class MyCustomDisplay : public ZepDisplay
{
public:
MyCustomDisplay ( MyRenderer * renderer )
: m_renderer (renderer)
{
}
void DrawLine ( const NVec2f & start , const NVec2f & end ,
const NVec4f & color , float width ) const override
{
m_renderer -> DrawLine (
start . x , start . y ,
end . x , end . y ,
Color ( color . x , color . y , color . z , color . w ),
width
);
}
void DrawChars ( ZepFont & font , const NVec2f & pos ,
const NVec4f & col ,
const uint8_t* text_begin ,
const uint8_t* text_end ) const override
{
// Convert to string
std ::string text (text_begin, text_end);
// Use your renderer's text drawing
m_renderer -> DrawText (
pos . x , pos . y ,
text,
Color ( col . x , col . y , col . z , col . w ),
& font
);
}
void DrawRectFilled ( const NRectf & rc , const NVec4f & col ) const override
{
m_renderer -> FillRect (
rc . topLeftPx . x , rc . topLeftPx . y ,
rc . bottomRightPx . x - rc . topLeftPx . x , // width
rc . bottomRightPx . y - rc . topLeftPx . y , // height
Color ( col . x , col . y , col . z , col . w )
);
}
void SetClipRect ( const NRectf & rc ) override
{
m_renderer -> SetScissor (
rc . topLeftPx . x , rc . topLeftPx . y ,
rc . bottomRightPx . x , rc . bottomRightPx . y
);
}
ZepFont & GetFont ( ZepTextType type ) override
{
// Return appropriate font
return * m_fonts [( int )type];
}
private:
MyRenderer * m_renderer;
};
Font Implementation Example
class MyCustomFont : public ZepFont
{
public:
MyCustomFont ( ZepDisplay & display , MyFontHandle * fontHandle )
: ZepFont (display)
, m_fontHandle (fontHandle)
{
}
void SetPixelHeight ( int height ) override
{
m_pixelHeight = height;
m_fontHandle -> SetSize (height);
// Rebuild character cache
InvalidateCharCache ();
BuildCharCache ();
}
NVec2f GetTextSize ( const uint8_t* pBegin ,
const uint8_t* pEnd ) const override
{
if ( ! pEnd)
{
pEnd = pBegin + strlen (( const char * )pBegin);
}
std ::string text (pBegin, pEnd);
auto size = m_fontHandle -> MeasureText (text);
return NVec2f ( size . width , size . height );
}
private:
MyFontHandle * m_fontHandle;
};
Layout and Dirty Flags
Zep tracks when layout needs to be recalculated:
From include/zep/display.h:86-87:
virtual bool LayoutDirty () const ;
virtual void SetLayoutDirty ( bool changed = true );
Layout becomes dirty when:
Window size changes
Font size changes
Text wrapping settings change
Display scale changes
Check LayoutDirty() in your render loop. If true, the editor will recalculate text positions.
Display Region Setup
The editor needs to know its drawing region:
From include/zep/editor.h:395-397:
// Setup the display size for the editor
void SetDisplayRegion ( const NVec2f & topLeft , const NVec2f & bottomRight );
void UpdateSize ();
Call SetDisplayRegion() when your window resizes:
void OnWindowResize ( int width , int height )
{
editor . SetDisplayRegion (
NVec2f ( 0 , 0 ),
NVec2f (width, height)
);
}
Font Size Management
From include/zep/display.h:94-95:
void Bigger (); // Increase font size
void Smaller (); // Decrease font size
These methods adjust all fonts proportionally.
Colors use RGBA float format (0.0 to 1.0):
NVec4f color (
1.0 f , // Red
0.5 f , // Green
0.0 f , // Blue
1.0 f // Alpha (opacity)
);
Colors come from the theme system:
auto color = editor . GetTheme (). GetColor ( ThemeColor ::Text);
Best Practices
Batch Drawing Minimize state changes by batching similar draw calls
Cache Fonts Load fonts once and cache them for performance
Clip Properly Use SetClipRect to avoid drawing outside bounds
Handle DPI Implement pixel scaling for high-DPI displays
Next Steps
Architecture Understand how display fits in the architecture
Syntax Highlighting Learn how syntax colors are applied during rendering