Scroom  0.14
Ruler Class Reference

#include <ruler.hh>

Collaboration diagram for Ruler:
Collaboration graph

Public Types

enum  Orientation { HORIZONTAL, VERTICAL }
 
using Ptr = boost::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}
 
constexpr static 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 = boost::shared_ptr<Ruler>

Member Enumeration Documentation

◆ Orientation

Enumerator
HORIZONTAL 
VERTICAL 
21  {
22  HORIZONTAL,
23  VERTICAL
24  };

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 }

◆ Ruler() [1/3]

Ruler::Ruler ( const Ruler )
delete

Referenced by create().

Here is the caller graph for this function:

◆ 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 }

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 {
14  Ruler::Ptr ruler;
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 }

Referenced by BOOST_AUTO_TEST_CASE().

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 
138  const int firstTick = RulerCalculations::firstTick(lowerLimit, majorInterval);
139 
140  // Draw the range [0, upperLimit]
141  drawTicks(cr, firstTick, upperLimit, lineLength);
142 }

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 }
Here is the call 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 }

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 }

Referenced by 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 }

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 }

◆ 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 }

Referenced by 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

◆ DEFAULT_UPPER

constexpr double Ruler::DEFAULT_UPPER {10}
staticconstexprprivate

◆ drawingArea

GtkWidget* Ruler::drawingArea {}
private

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

◆ drawStrategy

◆ FONT_SIZE

constexpr double Ruler::FONT_SIZE {11}
staticconstexprprivate

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.

Referenced by drawSingleTick().

◆ LABEL_OFFSET

constexpr double Ruler::LABEL_OFFSET {4}
staticconstexprprivate

Offset of tick label from the tick line in pixels.

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.

Referenced by drawSubTicks(), and drawTicks().

◆ LINE_WIDTH

constexpr double Ruler::LINE_WIDTH {1}
staticconstexprprivate

Referenced by draw(), and drawSingleTick().

◆ lineColor

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

Referenced by draw().

◆ lowerLimit

double Ruler::lowerLimit {DEFAULT_LOWER}
private

◆ 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.

Referenced by draw().

◆ majorInterval

int Ruler::majorInterval {1}
private

The chosen interval between major ticks.

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

◆ majorTickSpacing

int Ruler::majorTickSpacing {}
private

The space between major ticks when drawn.

Referenced by drawTicks(), and updateMajorTickInterval().

◆ MIN_SPACE_SUBTICKS

constexpr int Ruler::MIN_SPACE_SUBTICKS {5}
staticconstexprprivate

The minimum space between sub-ticks.

Referenced by drawSubTicks().

◆ SUBTICK_SEGMENTS

constexpr static 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.)

Referenced by drawSubTicks().

◆ upperLimit

double Ruler::upperLimit {DEFAULT_UPPER}
private

◆ width

int Ruler::width {}
private

The documentation for this class was generated from the following files:
Ruler::Ruler
Ruler(const Ruler &)=delete
Ruler::drawSingleTick
void drawSingleTick(cairo_t *cr, double linePosition, double lineLength, bool drawLabel, const std::string &label)
Definition: ruler.cc:168
RulerCalculations::intervalPixelSpacing
static int intervalPixelSpacing(double interval, double lower, double upper, double allocatedSize)
Definition: ruler.cc:294
Ruler::drawCallback
static gboolean drawCallback(GtkWidget *widget, cairo_t *cr, gpointer data)
Definition: ruler.cc:106
Ruler::LABEL_ALIGN
static constexpr double LABEL_ALIGN
Definition: ruler.hh:86
Ruler::drawTicks
void drawTicks(cairo_t *cr, double lower, double upper, double lineLength)
Definition: ruler.cc:144
Ruler::sizeAllocateCallback
static void sizeAllocateCallback(GtkWidget *widget, GdkRectangle *allocation, gpointer data)
Definition: ruler.cc:76
Ruler::width
int width
Definition: ruler.hh:64
Ruler::updateMajorTickInterval
void updateMajorTickInterval()
Definition: ruler.cc:86
Ruler::LINE_MULTIPLIER
static constexpr double LINE_MULTIPLIER
Definition: ruler.hh:89
VerticalDrawStrategy::create
static RulerDrawStrategy::Ptr create()
Definition: rulerstrategies.cc:18
require
#define require(expr)
Definition: assertions.hh:28
RulerCalculations::firstTick
static int firstTick(double lower, int interval)
Definition: ruler.cc:303
Ruler::lineColor
GdkRGBA lineColor
Definition: ruler.hh:91
Ruler::MAJOR_TICK_LENGTH
static constexpr double MAJOR_TICK_LENGTH
Definition: ruler.hh:96
Ruler::majorInterval
int majorInterval
Definition: ruler.hh:68
Ruler::draw
void draw(GtkWidget *widget, cairo_t *cr)
Definition: ruler.cc:114
Ruler::VERTICAL
@ VERTICAL
Definition: ruler.hh:23
Ruler::LABEL_OFFSET
static constexpr double LABEL_OFFSET
Definition: ruler.hh:83
Ruler::SUBTICK_SEGMENTS
constexpr static std::array< int, 2 > SUBTICK_SEGMENTS
Definition: ruler.hh:57
RulerCalculations::scaleToRange
static double scaleToRange(double x, double src_lower, double src_upper, double dest_lower, double dest_upper)
Definition: ruler.cc:235
Ruler::LINE_WIDTH
static constexpr double LINE_WIDTH
Definition: ruler.hh:93
Ruler::height
int height
Definition: ruler.hh:65
Scroom::TiledBitmap::to_string
std::string to_string(const BitmapMetaData &bmd)
Definition: layerspecforbitmap.cc:30
Ruler::drawSubTicks
void drawSubTicks(cairo_t *cr, double lower, double upper, int depth, double lineLength)
Definition: ruler.cc:193
Ruler::upperLimit
double upperLimit
Definition: ruler.hh:61
Ruler::drawStrategy
RulerDrawStrategy::Ptr drawStrategy
Definition: ruler.hh:75
Ruler::lowerLimit
double lowerLimit
Definition: ruler.hh:60
Ruler::drawingArea
GtkWidget * drawingArea
Definition: ruler.hh:48
Ruler::MIN_SPACE_SUBTICKS
static constexpr int MIN_SPACE_SUBTICKS
Definition: ruler.hh:78
Ruler::Ptr
boost::shared_ptr< Ruler > Ptr
Definition: ruler.hh:18
Ruler::FONT_SIZE
static constexpr double FONT_SIZE
Definition: ruler.hh:80
Ruler
Definition: ruler.hh:14
Ruler::majorTickSpacing
int majorTickSpacing
Definition: ruler.hh:71
RulerCalculations::calculateInterval
static int calculateInterval(double lower, double upper, double allocatedSize)
Definition: ruler.cc:244
Ruler::HORIZONTAL
@ HORIZONTAL
Definition: ruler.hh:22
HorizontalDrawStrategy::create
static RulerDrawStrategy::Ptr create()
Definition: rulerstrategies.cc:16