Scroom 0.14-49-gb7ae7a6d
Loading...
Searching...
No Matches
Ruler Class Reference

#include <ruler.hh>

Collaboration diagram for Ruler:
Collaboration graph

Public Types

enum  Orientation { HORIZONTAL , VERTICAL }
 
using Ptr = std::shared_ptr< Ruler >
 

Public Member Functions

 ~Ruler ()
 
 Ruler (const Ruler &)=delete
 
 Ruler (Ruler &&)=delete
 
Ruler operator= (const Ruler &)=delete
 
Ruler operator= (Ruler &&)=delete
 
void setRange (double lower, double upper)
 

Static Public Member Functions

static Ptr create (Orientation orientation, GtkWidget *drawArea)
 

Private Member Functions

 Ruler (RulerDrawStrategy::Ptr strategy, GtkWidget *drawingArea)
 
void draw (GtkWidget *widget, cairo_t *cr)
 
void updateAllocatedSize (int newWidth, int newHeight)
 
void updateMajorTickInterval ()
 
void drawTicks (cairo_t *cr, double lower, double upper, double lineLength)
 
void drawSingleTick (cairo_t *cr, double linePosition, double lineLength, bool drawLabel, const std::string &label)
 
void drawSubTicks (cairo_t *cr, double lower, double upper, int depth, double lineLength)
 

Static Private Member Functions

static gboolean drawCallback (GtkWidget *widget, cairo_t *cr, gpointer data)
 
static void sizeAllocateCallback (GtkWidget *widget, GdkRectangle *allocation, gpointer data)
 

Private Attributes

GtkWidget * drawingArea {}
 
double lowerLimit {DEFAULT_LOWER}
 
double upperLimit {DEFAULT_UPPER}
 
int width {}
 
int height {}
 
int majorInterval {1}
 
int majorTickSpacing {}
 
RulerDrawStrategy::Ptr drawStrategy
 
GdkRGBA lineColor {0, 0, 0, 1}
 

Static Private Attributes

static constexpr double DEFAULT_LOWER {0}
 
static constexpr double DEFAULT_UPPER {10}
 
static constexpr std::array< int, 2 > SUBTICK_SEGMENTS {5, 2}
 
static constexpr int MIN_SPACE_SUBTICKS {5}
 
static constexpr double FONT_SIZE {11}
 
static constexpr double LABEL_OFFSET {4}
 
static constexpr double LABEL_ALIGN {0.7}
 
static constexpr double LINE_MULTIPLIER {0.6}
 
static constexpr double LINE_WIDTH {1}
 
static constexpr double MAJOR_TICK_LENGTH {0.8}
 

Detailed Description

This class draws a ruler to a GtkDrawingArea. It is intended as a replacement for the old GTK2 ruler widget and is written to mimic that widget's behavior as close as possible.

Member Typedef Documentation

◆ Ptr

using Ruler::Ptr = std::shared_ptr<Ruler>

Member Enumeration Documentation

◆ Orientation

Enumerator
HORIZONTAL 
VERTICAL 
22 {
25 };
@ VERTICAL
Definition ruler.hh:24
@ HORIZONTAL
Definition ruler.hh:23

Constructor & Destructor Documentation

◆ ~Ruler()

Ruler::~Ruler ( )
49{
50 // Disconnect all signal handlers for this object from the drawing area
51 g_signal_handlers_disconnect_by_data(drawingArea, this);
52 // Decrement reference count drawing area
53 g_object_unref(drawingArea);
54}
GtkWidget * drawingArea
Definition ruler.hh:49

◆ Ruler() [1/3]

Ruler::Ruler ( const Ruler )
delete

◆ Ruler() [2/3]

Ruler::Ruler ( Ruler &&  )
delete

◆ Ruler() [3/3]

Ruler::Ruler ( RulerDrawStrategy::Ptr  strategy,
GtkWidget *  drawingArea 
)
private

Creates a Ruler.

Parameters
rulerOrientationThe rulerOrientation of the ruler.
drawingAreaThe GtkDrawingArea to draw the ruler to.
28 : drawingArea{drawingAreaWidget}
29 , width{gtk_widget_get_allocated_width(drawingAreaWidget)}
30 , height{gtk_widget_get_allocated_height(drawingAreaWidget)}
31 , drawStrategy{std::move(strategy)}
32{
33 require(drawingArea != nullptr);
34
35 // Increment reference count of drawing area
36 g_object_ref_sink(drawingArea);
37
38 // Set size for strategy
39 this->drawStrategy->setAllocatedSize(width, height);
40
41 // Connect signal handlers
42 g_signal_connect(drawingAreaWidget, "draw", G_CALLBACK(drawCallback), this);
43 g_signal_connect(drawingAreaWidget, "size-allocate", G_CALLBACK(sizeAllocateCallback), this);
44 // Calculate tick intervals and spacing
46}
#define require(expr)
Definition assertions.hh:30
int width
Definition ruler.hh:65
static gboolean drawCallback(GtkWidget *widget, cairo_t *cr, gpointer data)
Definition ruler.cc:106
int height
Definition ruler.hh:66
RulerDrawStrategy::Ptr drawStrategy
Definition ruler.hh:76
void updateMajorTickInterval()
Definition ruler.cc:86
static void sizeAllocateCallback(GtkWidget *widget, GdkRectangle *allocation, gpointer data)
Definition ruler.cc:76
Here is the call graph for this function:

Member Function Documentation

◆ create()

Ruler::Ptr Ruler::create ( Ruler::Orientation  orientation,
GtkWidget *  drawArea 
)
static

Creates a ruler.

Parameters
orientationThe orientation of the ruler.
drawAreaThe GtkDrawingArea to draw the ruler to.
Returns
The newly created ruler.
13{
15 // We pass a different drawing strategy to the ruler depending on orientation
16 if(orientation == HORIZONTAL)
17 {
19 }
20 else
21 {
23 }
24 return ruler;
25}
static RulerDrawStrategy::Ptr create()
Definition rulerstrategies.cc:16
Definition ruler.hh:16
std::shared_ptr< Ruler > Ptr
Definition ruler.hh:19
static RulerDrawStrategy::Ptr create()
Definition rulerstrategies.cc:18
Ruler::Ptr const ruler
Definition ruler-tests.cc:12

Referenced by View::View().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw()

void Ruler::draw ( GtkWidget *  widget,
cairo_t *  cr 
)
private

Draws the ruler to the given Cairo context.

Parameters
widgetThe widget that received the draw signal.
crCairo context to draw to.
115{
116 // Initialize cairo
117 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
118 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
119
120 // Draw background using widget's style context
121 GtkStyleContext* context = gtk_widget_get_style_context(widget);
122 gtk_render_background(context, cr, 0, 0, width, height);
123
124 // Draw outline
125 gdk_cairo_set_source_rgba(cr, &lineColor);
126 drawStrategy->drawOutline(cr, LINE_WIDTH);
127 cairo_set_line_width(cr, Ruler::LINE_WIDTH);
128
129 // The majorInterval is invalid, don't attempt to draw anything else
130 if(majorInterval <= 0)
131 {
132 return;
133 }
134
135 // Calculate the line length for the major ticks given the size of the ruler
136 const double lineLength = drawStrategy->getMajorTickLength(MAJOR_TICK_LENGTH);
137
139
140 // Draw the range [0, upperLimit]
141 drawTicks(cr, firstTick, upperLimit, lineLength);
142}
static int firstTick(double lower, int interval)
Definition ruler.cc:303
double lowerLimit
Definition ruler.hh:61
int majorInterval
Definition ruler.hh:69
static constexpr double MAJOR_TICK_LENGTH
Definition ruler.hh:97
static constexpr double LINE_WIDTH
Definition ruler.hh:94
GdkRGBA lineColor
Definition ruler.hh:92
void drawTicks(cairo_t *cr, double lower, double upper, double lineLength)
Definition ruler.cc:144
double upperLimit
Definition ruler.hh:62
cairo_t * cr
Definition transformpresentation_test.cc:72

Referenced by drawCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drawCallback()

gboolean Ruler::drawCallback ( GtkWidget *  widget,
cairo_t *  cr,
gpointer  data 
)
staticprivate

A callback to be connected to a GtkDrawingArea's "draw" signal. Draws the ruler to the drawing area.

Parameters
widgetThe widget that received the signal.
crCairo context to draw to.
dataPointer to a ruler instance.
Returns
TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
107{
108 auto* ruler = static_cast<Ruler*>(data);
109 ruler->draw(widget, cr);
110
111 return FALSE;
112}
uint8_t data
Definition blob-tests.cc:36
void draw(GtkWidget *widget, cairo_t *cr)
Definition ruler.cc:114

Referenced by Ruler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drawSingleTick()

void Ruler::drawSingleTick ( cairo_t *  cr,
double  linePosition,
double  lineLength,
bool  drawLabel,
const std::string &  label 
)
private

Draws a single tick, taking into account the ruler's orientation.

Parameters
crCairo context to draw to.
linePositionThe position of the line along the ruler.
lineLengthLength of the line in pixels.
drawLabelTrue if a label should be drawn to the right/top of the line.
labelThe label to draw if drawLabel is true.
169{
170 const double DRAW_AREA_SIZE = drawStrategy->getDrawAreaSize();
171 // Draw the line if is within the drawing area
172 if(0 < linePosition && linePosition < DRAW_AREA_SIZE)
173 {
174 // Draw line
175 drawStrategy->drawTickLine(cr, linePosition, LINE_WIDTH, lineLength);
176 }
177
178 // We'll be modifying the transformation matrix so
179 // we save the current one to restore later
180 cairo_save(cr);
181 if(drawLabel) // Draw the tick label
182 {
183 // Set text font and size
184 cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
185 cairo_set_font_size(cr, FONT_SIZE);
186 // drawTickText(cairo_t *cr, std::string label, double linePosition, double labelOffset, double labelAlign, double lineLength,
187 // int width, int height) = 0;
188 drawStrategy->drawTickText(cr, label, linePosition, LABEL_OFFSET, LABEL_ALIGN, lineLength);
189 }
190 cairo_restore(cr);
191}
static constexpr double FONT_SIZE
Definition ruler.hh:81
static constexpr double LABEL_ALIGN
Definition ruler.hh:87
static constexpr double LABEL_OFFSET
Definition ruler.hh:84

Referenced by drawSubTicks(), and drawTicks().

Here is the caller graph for this function:

◆ drawSubTicks()

void Ruler::drawSubTicks ( cairo_t *  cr,
double  lower,
double  upper,
int  depth,
double  lineLength 
)
private

Draws the smaller ticks in between the major ticks from left-to-right / bottom-to-top.

Parameters
crCairo context to draw to.
lowerThe lower limit of the range in draw space.
upperThe upper limit of the range in draw space.
depthThe depth of this recursive function. Functions as an index into the ruler's SUBTICK_SEGMENTS array.
lineLengthLength of the lines in pixels.
194{
195 // We don't need to divide the segment any further so return
196 if(static_cast<unsigned int>(depth) >= SUBTICK_SEGMENTS.size())
197 {
198 return;
199 }
200
201 const int numSegments = SUBTICK_SEGMENTS.at(depth);
202 const double interval = abs(upper - lower) / numSegments;
203
204 if(interval < MIN_SPACE_SUBTICKS)
205 {
206 return;
207 }
208
209 // We draw from lower->upper / upper->lower, but in the process, we might be exceeding
210 // the ruler area, so we also check that we're still inside the drawing area
211 const double DRAW_AREA_SIZE = drawStrategy->getDrawAreaSize();
212 const double limit = DRAW_AREA_SIZE;
213
214 // Position along the ruler to draw tick at
215 double tick = 0;
216 double pos = lower;
217
218 // Draw at most (numSegments - 1) ticks, while not exceeding the limit
219 while(tick < numSegments && pos < limit)
220 {
221 // We don't want to draw the tick for tick == 0, because
222 // we would end up drawing over other ticks
223 if(tick != 0)
224 {
225 drawSingleTick(cr, pos, lineLength, false, "");
226 }
227 tick++;
228 // Draw ticks at level below
229 drawSubTicks(cr, pos, pos + interval, depth + 1, LINE_MULTIPLIER * lineLength);
230
231 pos += interval;
232 }
233}
static constexpr int MIN_SPACE_SUBTICKS
Definition ruler.hh:79
void drawSingleTick(cairo_t *cr, double linePosition, double lineLength, bool drawLabel, const std::string &label)
Definition ruler.cc:168
static constexpr std::array< int, 2 > SUBTICK_SEGMENTS
Definition ruler.hh:58
void drawSubTicks(cairo_t *cr, double lower, double upper, int depth, double lineLength)
Definition ruler.cc:193
static constexpr double LINE_MULTIPLIER
Definition ruler.hh:90

Referenced by drawSubTicks(), and drawTicks().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drawTicks()

void Ruler::drawTicks ( cairo_t *  cr,
double  lower,
double  upper,
double  lineLength 
)
private

Draws the tick marks of the ruler for a given subset of the range from left-to-right / bottom-to-top.

Parameters
crCairo context to draw to.
lowerThe lower limit of the range to draw.
upperThe upper limit of the range to draw.
lineLengthLength of the lines in pixels.
145{
146 // Position in ruler range
147 double pos = lower;
148
149 const double DRAW_AREA_ORIGIN = 0;
150 // We need to scale to either [0, width] or [0, height] depending
151 // on the orientation of the ruler
152 const double DRAW_AREA_SIZE = drawStrategy->getDrawAreaSize();
153
154 // Move pos across range
155 while(pos < upper)
156 {
157 // Map pos from the ruler range to a drawing area position
158 const double s =
159 RulerCalculations::scaleToRange(pos, lowerLimit, upperLimit, DRAW_AREA_ORIGIN, DRAW_AREA_ORIGIN + DRAW_AREA_SIZE);
160 // Draw tick for this position
161 drawSingleTick(cr, s, lineLength, true, std::to_string(static_cast<int>(floor(pos))));
162
163 drawSubTicks(cr, s, s + majorTickSpacing, 0, LINE_MULTIPLIER * lineLength);
164 pos += majorInterval;
165 }
166}
static double scaleToRange(double x, double src_lower, double src_upper, double dest_lower, double dest_upper)
Definition ruler.cc:235
int majorTickSpacing
Definition ruler.hh:72
BitmapSurface::Ptr const s
Definition transformpresentation_test.cc:70

Referenced by draw().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=() [1/2]

Ruler Ruler::operator= ( const Ruler )
delete

◆ operator=() [2/2]

Ruler Ruler::operator= ( Ruler &&  )
delete

◆ setRange()

void Ruler::setRange ( double  lower,
double  upper 
)

Sets the range for the ruler to display.

Parameters
lowerLower limit of the ruler range. Must be strictly less than upper.
upperUpper limit of the ruler range. Must be strictly greater than lower.
57{
58 lowerLimit = lower;
59 upperLimit = upper;
60
62
63 // We need to manually trigger the widget to redraw
64 gtk_widget_queue_draw(drawingArea);
65}
Here is the call graph for this function:

◆ sizeAllocateCallback()

void Ruler::sizeAllocateCallback ( GtkWidget *  widget,
GdkRectangle *  allocation,
gpointer  data 
)
staticprivate

A callback to be connected to a GtkDrawingArea's "size-allocate" signal. Updates the internal state of the ruler when the size of the ruler changes.

Parameters
widgetThe widget that received the signal.
allocationThe region which has been allocated to the widget.
dataPointer to a ruler instance.
77{
78 auto* ruler = static_cast<Ruler*>(data);
79
80 const int width = gtk_widget_get_allocated_width(widget);
81 const int height = gtk_widget_get_allocated_height(widget);
82
83 ruler->updateAllocatedSize(width, height);
84}

Referenced by Ruler().

Here is the caller graph for this function:

◆ updateAllocatedSize()

void Ruler::updateAllocatedSize ( int  newWidth,
int  newHeight 
)
private

Updates the stored allocated size of the ruler.

Parameters
newWidthThe newWidth of the ruler in pixels.
newHeightThe newHeight of the ruler in pixels.
68{
69 this->width = newWidth;
70 this->height = newHeight;
71 drawStrategy->setAllocatedSize(newWidth, newHeight);
72
74}
Here is the call graph for this function:

◆ updateMajorTickInterval()

void Ruler::updateMajorTickInterval ( )
private

Calculates an appropriate interval between major ticks, given the current range and dimensions.

87{
88 const double ALLOCATED_SIZE = drawStrategy->getDrawAreaSize();
89
90 // lowerLimit could equal upperLimit, ALLOCATED_SIZE could be 0
91 if(lowerLimit < upperLimit && 0 < ALLOCATED_SIZE)
92 {
93 // Calculate the interval between major ruler ticks
95 // Calculate the spacing in pixels between major ruler ticks
97 }
98 else
99 {
100 // Arbitrary numbers
101 majorInterval = 10;
102 majorTickSpacing = 10;
103 }
104}
static int calculateInterval(double lower, double upper, double allocatedSize)
Definition ruler.cc:244
static int intervalPixelSpacing(double interval, double lower, double upper, double allocatedSize)
Definition ruler.cc:294

Referenced by Ruler(), setRange(), and updateAllocatedSize().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ DEFAULT_LOWER

constexpr double Ruler::DEFAULT_LOWER {0}
staticconstexprprivate
51{0};

◆ DEFAULT_UPPER

constexpr double Ruler::DEFAULT_UPPER {10}
staticconstexprprivate
52{10};

◆ drawingArea

GtkWidget* Ruler::drawingArea {}
private
49{};

Referenced by create(), Ruler(), setRange(), and ~Ruler().

◆ drawStrategy

◆ FONT_SIZE

constexpr double Ruler::FONT_SIZE {11}
staticconstexprprivate
81{11};

Referenced by drawSingleTick().

◆ height

int Ruler::height {}
private

◆ LABEL_ALIGN

constexpr double Ruler::LABEL_ALIGN {0.7}
staticconstexprprivate

Alignment of tick label along the tick line as a fraction of line height.

87{0.7};

Referenced by drawSingleTick().

◆ LABEL_OFFSET

constexpr double Ruler::LABEL_OFFSET {4}
staticconstexprprivate

Offset of tick label from the tick line in pixels.

84{4};

Referenced by drawSingleTick().

◆ LINE_MULTIPLIER

constexpr double Ruler::LINE_MULTIPLIER {0.6}
staticconstexprprivate

The length of a tick one "level" down, as a fraction of the line length of the ticks one level up.

90{0.6};

Referenced by drawSubTicks(), and drawTicks().

◆ LINE_WIDTH

constexpr double Ruler::LINE_WIDTH {1}
staticconstexprprivate
94{1};

Referenced by draw(), and drawSingleTick().

◆ lineColor

GdkRGBA Ruler::lineColor {0, 0, 0, 1}
private
92{0, 0, 0, 1};

Referenced by draw().

◆ lowerLimit

double Ruler::lowerLimit {DEFAULT_LOWER}
private
static constexpr double DEFAULT_LOWER
Definition ruler.hh:51

Referenced by draw(), drawTicks(), setRange(), and updateMajorTickInterval().

◆ MAJOR_TICK_LENGTH

constexpr double Ruler::MAJOR_TICK_LENGTH {0.8}
staticconstexprprivate

Length of the major tick lines as a fraction of the width/height.

97{0.8};

Referenced by draw().

◆ majorInterval

int Ruler::majorInterval {1}
private

The chosen interval between major ticks.

69{1};

Referenced by draw(), drawTicks(), and updateMajorTickInterval().

◆ majorTickSpacing

int Ruler::majorTickSpacing {}
private

The space between major ticks when drawn.

72{};

Referenced by drawTicks(), and updateMajorTickInterval().

◆ MIN_SPACE_SUBTICKS

constexpr int Ruler::MIN_SPACE_SUBTICKS {5}
staticconstexprprivate

The minimum space between sub-ticks.

79{5};

Referenced by drawSubTicks().

◆ SUBTICK_SEGMENTS

constexpr std::array<int, 2> Ruler::SUBTICK_SEGMENTS {5, 2}
staticconstexprprivate

Each space between major ticks is split into 5 smaller segments and those segments are split into 2. (Assuming there's enough space.)

58{5, 2};

Referenced by drawSubTicks().

◆ upperLimit

double Ruler::upperLimit {DEFAULT_UPPER}
private
static constexpr double DEFAULT_UPPER
Definition ruler.hh:52

Referenced by draw(), drawTicks(), setRange(), and updateMajorTickInterval().

◆ width

int Ruler::width {}
private

The documentation for this class was generated from the following files: