|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- #include "ovpCBottomTimeRuler.h"
- #include <cmath>
-
- namespace OpenViBE {
- namespace Plugins {
- namespace SimpleVisualization {
-
-
- #define CONVERT_TIME(i) (double((i)>>32) + double(double((i)&0xFFFFFFFF) / double((uint64_t)1<<32)))
-
- gboolean BottomRulerExposeEventCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, gpointer data)
- {
- //redraw the ruler
- auto* bottomRuler = reinterpret_cast<CBottomTimeRuler*>(data);
- bottomRuler->draw();
-
- //don't propagate this signal to the children if any
- return TRUE;
- }
-
- gboolean ResizeBottomRulerCB(GtkWidget* /*widget*/, GtkAllocation* allocation, gpointer data)
- {
- auto* bottomRuler = reinterpret_cast<CBottomTimeRuler*>(data);
- bottomRuler->onResizeEventCB(allocation->width, allocation->height);
- return FALSE;
- }
-
- CBottomTimeRuler::CBottomTimeRuler(CBufferDatabase& database, const int width, const int height)
- : m_database(&database), m_height(height)
- {
- //creates the main drawing area
- m_bottomRuler = gtk_drawing_area_new();
-
- gtk_widget_set_size_request(m_bottomRuler, width, height);
- g_signal_connect_after(G_OBJECT(m_bottomRuler), "expose_event", G_CALLBACK(BottomRulerExposeEventCB), this);
- }
-
- void CBottomTimeRuler::draw()
- {
- //if the widget is invisible, no need to redraw it
- if (!GTK_WIDGET_VISIBLE(m_bottomRuler)) { return; }
-
- //gets the number of buffers to display
- const uint64_t nBufferToDisplay = m_database->m_NBufferToDisplay;
-
- if (m_database->m_DimSizes[1] == 1 && nBufferToDisplay != 1) { /* nBufferToDisplay--;*/ }
-
- //gets the widget's size
- gint bottomRulerWidth;
- gint bottomRulerHeight;
- gdk_drawable_get_size(m_bottomRuler->window, &bottomRulerWidth, &bottomRulerHeight);
-
- //in ms
- const double intervalWidth = CONVERT_TIME(nBufferToDisplay * m_database->m_BufferDuration);
- //if(m_Database->areEpochsContiguous() == true){intervalWidth = CONVERT_TIME(nBufferToDisplay * m_Database->m_BufferDuration);}
- //else { intervalWidth = CONVERT_TIME(nBufferToDisplay * m_Database->m_BufferDuration); }
-
- //available width per buffer
- const double widthPerBuffer = double(bottomRulerWidth) / double(nBufferToDisplay);
-
- //computes the step of the values displayed on the ruler
- const auto nearestSmallerPowerOf10 = double(pow(10, floor(log10(intervalWidth))));
- const auto maxNumberOfLabels = uint64_t(bottomRulerWidth / m_pixelsPerLabel);
-
- double valueStep = nearestSmallerPowerOf10;
- if (uint64_t(floor(intervalWidth / nearestSmallerPowerOf10)) > maxNumberOfLabels) { valueStep = 2 * nearestSmallerPowerOf10; }
- else if (uint64_t(floor(intervalWidth / nearestSmallerPowerOf10)) < maxNumberOfLabels / 2) { valueStep = nearestSmallerPowerOf10 / 2; }
-
- if (m_database->getDisplayMode() == Scroll)
- {
- //compute start, end time and base value of the step
- double startTime = 0;
- if (!m_database->m_StartTime.empty()) { startTime = CONVERT_TIME(m_database->m_StartTime[0]); }
-
- const double endTime = startTime + intervalWidth;
- const double baseValue = valueStep * floor(startTime / valueStep);
-
- //X position of the first label (if there are less buffers than needed)
- auto baseX = int64_t(floor(bottomRulerWidth - (m_database->m_SampleBuffers.size() * widthPerBuffer)));
- if (baseX < 0) { baseX = 0; }
-
- //draw ruler base (horizontal line)
- gdk_draw_line(m_bottomRuler->window, m_bottomRuler->style->fg_gc[GTK_WIDGET_STATE(m_bottomRuler)], gint(baseX), 0, gint(bottomRulerWidth), 0);
-
- const int clipLeft = 0;
- const int clipRight = bottomRulerWidth - 1;
-
- drawRuler(baseX, bottomRulerWidth, startTime, endTime, intervalWidth, baseValue, valueStep, clipLeft, clipRight);
- }
- else //scan mode
- {
- //draw ruler base (horizontal line)
- gdk_draw_line(m_bottomRuler->window, m_bottomRuler->style->fg_gc[GTK_WIDGET_STATE(m_bottomRuler)], 0, 0, gint(bottomRulerWidth), 0);
-
- //left part of the ruler (recent data)
- size_t leftmostBufferToDisplay = 0;
- m_database->getIndexOfBufferStartingAtTime(m_leftmostDisplayedTime, leftmostBufferToDisplay);
- double startTime = 0;
- if (!m_database->m_StartTime.empty()) { startTime = CONVERT_TIME(m_leftmostDisplayedTime); }
- double endTime = startTime + intervalWidth;
- double baseValue = valueStep * floor(startTime / valueStep);
- int clipLeft = 0;
- int clipRight = int(double(m_database->m_NBufferToDisplay - leftmostBufferToDisplay) * widthPerBuffer);
-
- drawRuler(0, bottomRulerWidth, startTime, endTime, intervalWidth, baseValue, valueStep, clipLeft, clipRight);
-
- //right part (older data)
- startTime -= intervalWidth;
- endTime = startTime + intervalWidth;
- baseValue = valueStep * floor(startTime / valueStep);
- clipLeft = clipRight + 1;
- clipRight = bottomRulerWidth - 1;
-
- drawRuler(0, bottomRulerWidth, startTime, endTime, intervalWidth, baseValue, valueStep, clipLeft, clipRight);
- }
- }
-
- void CBottomTimeRuler::onResizeEventCB(const gint width, gint /*height*/) const { gtk_widget_set_size_request(m_bottomRuler, width, m_height); }
-
- void CBottomTimeRuler::drawRuler(const int64_t baseX, const int rulerWidth, const double startTime, const double endTime, const double length,
- const double baseValue, const double valueStep, const int clipLeft, const int clipRight)
- {
- for (double i = baseValue; i < double(0.5 + endTime); i += valueStep)
- {
- //compute the position of the label
- const gint textX = gint(baseX + ((i - startTime) * ((double(rulerWidth)) / length)));
- //is text clipped?
- if (textX < clipLeft) { continue; }
-
- std::string timeLabel = std::to_string(i);
- PangoLayout* text = gtk_widget_create_pango_layout(m_bottomRuler, timeLabel.c_str());
-
- int textWidth;
- pango_layout_get_pixel_size(text, &textWidth, nullptr);
-
- //is text beyond visible range?
- if (textX + textWidth > clipRight)
- {
- g_object_unref(text);
- break;
- }
-
- //if the width allocated per label becomes too small compared to the effective width of the label
- if (uint64_t(textWidth) >= m_pixelsPerLabel - 20)
- {
- //increases the allocated width per label
- m_pixelsPerLabel = textWidth + 30;
- }
-
- //display it
- gdk_draw_layout(m_bottomRuler->window, m_bottomRuler->style->fg_gc[GTK_WIDGET_STATE(m_bottomRuler)], textX, 4, text);
-
- //draw a small line above it
- gdk_draw_line(m_bottomRuler->window, m_bottomRuler->style->fg_gc[GTK_WIDGET_STATE(m_bottomRuler)], textX, 0, textX, 3);
-
- g_object_unref(text);
- }
- }
-
- void CBottomTimeRuler::linkWidthToWidget(GtkWidget* widget)
- {
- //adds a callback to the widget for the size-allocate signal
- g_signal_connect(G_OBJECT(widget), "size-allocate", G_CALLBACK(ResizeBottomRulerCB), this);
- }
- } // namespace SimpleVisualization
- } // namespace Plugins
- } // namespace OpenViBE
|