an awful lot of tweaks to drawing details
This commit is contained in:
parent
0ce393f051
commit
a1f858d3b2
|
@ -1208,14 +1208,13 @@ AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
|
|||
v = min (1.0, v * 3.0);
|
||||
|
||||
c = ArdourCanvas::hsv_to_color (h, s, v, _region->muted() ? MUTED_ALPHA : 1.0);
|
||||
|
||||
|
||||
wave->set_fill_color (c);
|
||||
}
|
||||
|
||||
wave->set_clip_color (ARDOUR_UI::config()->get_canvasvar_WaveFormClip());
|
||||
wave->set_zero_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine());
|
||||
// CAIROCANVAS
|
||||
// wave->property_zero_line() = true;
|
||||
wave->set_show_zero_line (true);
|
||||
|
||||
switch (Config->get_waveform_shape()) {
|
||||
case Rectified:
|
||||
|
|
|
@ -45,11 +45,11 @@ EditorCursor::EditorCursor (Editor& ed, bool (Editor::*callbck)(GdkEvent*,Ardour
|
|||
_time_bars_canvas_item.set_head_width (0, 16);
|
||||
_time_bars_canvas_item.set_head_outward (0, false);
|
||||
_time_bars_canvas_item.set_show_head (1, false); // head only
|
||||
_time_bars_canvas_item.set_outline_width (1.5);
|
||||
_time_bars_canvas_item.set_outline_width (0.5);
|
||||
|
||||
_time_bars_canvas_item.set_data ("cursor", this);
|
||||
_track_canvas_item.set_data ("cursor", this);
|
||||
_track_canvas_item.set_outline_width (1.5);
|
||||
_track_canvas_item.set_outline_width (0.5);
|
||||
|
||||
_time_bars_canvas_item.Event.connect (sigc::bind (sigc::mem_fun (ed, callbck), &_time_bars_canvas_item));
|
||||
_track_canvas_item.Event.connect (sigc::bind (sigc::mem_fun (ed, callbck), &_track_canvas_item));
|
||||
|
@ -70,7 +70,11 @@ EditorCursor::set_position (framepos_t frame)
|
|||
{
|
||||
PositionChanged (frame);
|
||||
|
||||
double const new_pos = _editor.sample_to_pixel (frame);
|
||||
/* See Cairo FAQ question on single pixel lines to understand
|
||||
why we add 0.5
|
||||
*/
|
||||
|
||||
double const new_pos = _editor.sample_to_pixel (frame) + 0.5;
|
||||
|
||||
if (new_pos != _time_bars_canvas_item.x ()) {
|
||||
_time_bars_canvas_item.set_x (new_pos);
|
||||
|
|
|
@ -111,8 +111,12 @@ TempoLines::draw (const ARDOUR::TempoMap::BBTPointList::const_iterator& begin,
|
|||
line->set_ignore_events (true);
|
||||
}
|
||||
|
||||
line->set_x0 (xpos);
|
||||
line->set_x1 (xpos);
|
||||
/* move to 0.5 offset to ensure single pixel lines (see Cairo
|
||||
* FAQ for info on why we do this).
|
||||
*/
|
||||
|
||||
line->set_x0 (xpos + 0.5);
|
||||
line->set_x1 (xpos + 0.5);
|
||||
line->set_y0 (0.0);
|
||||
line->set_y1 (_height);
|
||||
line->set_outline_color (color);
|
||||
|
|
|
@ -59,9 +59,9 @@ ThemeManager::ThemeManager()
|
|||
, light_button (_("Light Theme"))
|
||||
, reset_button (_("Restore Defaults"))
|
||||
, flat_buttons (_("Draw \"flat\" buttons"))
|
||||
, waveform_gradient_depth (0, 1.0, 0.1)
|
||||
, waveform_gradient_depth (0, 1.0, 0.05)
|
||||
, waveform_gradient_depth_label (_("Waveforms color gradient depth"))
|
||||
, timeline_item_gradient_depth (0, 2.0, 0.1)
|
||||
, timeline_item_gradient_depth (0, 1.0, 0.05)
|
||||
, timeline_item_gradient_depth_label (_("Timeline item gradient depth"))
|
||||
, all_dialogs (_("All floating windows are dialogs"))
|
||||
{
|
||||
|
|
|
@ -731,30 +731,15 @@ TimeAxisViewItem::set_colors()
|
|||
set_trim_handle_colors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame color depending on whether this item is selected
|
||||
*/
|
||||
void
|
||||
TimeAxisViewItem::set_frame_color()
|
||||
uint32_t
|
||||
TimeAxisViewItem::get_fill_color () const
|
||||
{
|
||||
uint32_t f = 0;
|
||||
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_selected) {
|
||||
|
||||
f = ARDOUR_UI::config()->get_canvasvar_SelectedFrameBase();
|
||||
|
||||
if (fill_opacity) {
|
||||
f = UINT_RGBA_CHANGE_A (f, fill_opacity);
|
||||
}
|
||||
|
||||
if (!rect_visible) {
|
||||
f = UINT_RGBA_CHANGE_A (f, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (_recregion) {
|
||||
|
@ -766,15 +751,32 @@ TimeAxisViewItem::set_frame_color()
|
|||
} else {
|
||||
f = fill_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fill_opacity) {
|
||||
f = UINT_RGBA_CHANGE_A (f, fill_opacity);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
if (!rect_visible) {
|
||||
f = UINT_RGBA_CHANGE_A (f, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the frame color depending on whether this item is selected
|
||||
*/
|
||||
void
|
||||
TimeAxisViewItem::set_frame_color()
|
||||
{
|
||||
uint32_t f = 0;
|
||||
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
f = get_fill_color ();
|
||||
|
||||
if (fill_opacity) {
|
||||
f = UINT_RGBA_CHANGE_A (f, fill_opacity);
|
||||
}
|
||||
|
||||
if (!rect_visible) {
|
||||
f = UINT_RGBA_CHANGE_A (f, 0);
|
||||
}
|
||||
|
||||
frame->set_fill_color (f);
|
||||
|
@ -806,7 +808,7 @@ TimeAxisViewItem::set_frame_gradient ()
|
|||
ArdourCanvas::Fill::StopList stops;
|
||||
double r, g, b, a;
|
||||
double h, s, v;
|
||||
ArdourCanvas::Color f (frame->fill_color());
|
||||
ArdourCanvas::Color f (get_fill_color());
|
||||
|
||||
/* need to get alpha value */
|
||||
ArdourCanvas::color_to_rgba (f, r, g, b, a);
|
||||
|
@ -816,10 +818,8 @@ TimeAxisViewItem::set_frame_gradient ()
|
|||
/* now a darker version */
|
||||
|
||||
ArdourCanvas::color_to_hsv (f, h, s, v);
|
||||
s *= ARDOUR_UI::config()->get_timeline_item_gradient_depth();
|
||||
if (s > 1.0) {
|
||||
s = 1.0;
|
||||
}
|
||||
|
||||
v = min (1.0, v * (1.0 - ARDOUR_UI::config()->get_timeline_item_gradient_depth()));
|
||||
|
||||
ArdourCanvas::Color darker = ArdourCanvas::hsv_to_color (h, s, v, a);
|
||||
stops.push_back (std::make_pair (1.0, darker));
|
||||
|
|
|
@ -74,6 +74,8 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList
|
|||
void set_y (double);
|
||||
void set_color (Gdk::Color const &);
|
||||
|
||||
uint32_t get_fill_color () const;
|
||||
|
||||
ArdourCanvas::Item* get_canvas_frame();
|
||||
ArdourCanvas::Group* get_canvas_group();
|
||||
ArdourCanvas::Item* get_name_highlight();
|
||||
|
|
|
@ -80,6 +80,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
|
|||
/* there's a common area between the root and the requested
|
||||
area, so render it.
|
||||
*/
|
||||
|
||||
_root.render (*draw, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
#include <stdint.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <cairomm/refptr.h>
|
||||
|
||||
namespace Cairo {
|
||||
struct Context;
|
||||
}
|
||||
|
||||
namespace ArdourCanvas
|
||||
{
|
||||
|
||||
|
@ -89,6 +95,9 @@ struct Rect
|
|||
bool contains (Duple) const;
|
||||
Rect fix () const;
|
||||
|
||||
Rect convert_to_device (Cairo::RefPtr<Cairo::Context>) const;
|
||||
Rect convert_to_user (Cairo::RefPtr<Cairo::Context>) const;
|
||||
|
||||
Distance width () const {
|
||||
return x1 - x0;
|
||||
}
|
||||
|
|
|
@ -56,10 +56,15 @@ void
|
|||
Line::render (Rect const & /*area*/, Cairo::RefPtr<Cairo::Context> context) const
|
||||
{
|
||||
setup_outline_context (context);
|
||||
|
||||
Duple p0 = item_to_window (Duple (_points[0].x, _points[0].y));
|
||||
Duple p1 = item_to_window (Duple (_points[1].x, _points[1].y));
|
||||
context->move_to (p0.x, p0.y);
|
||||
context->line_to (p1.x, p1.y);
|
||||
|
||||
/* See Cairo FAQ on single pixel lines to understand why we add 0.5
|
||||
*/
|
||||
|
||||
context->move_to (p0.x + 0.5, p0.y + 0.5);
|
||||
context->line_to (p1.x + 0.5, p1.y + 0.5);
|
||||
context->stroke ();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,69 +68,40 @@ Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) con
|
|||
draw.y0 = max (self.y0, max (0.0, draw.y0 - boundary));
|
||||
draw.y1 = min (self.y1, min (2000.0, draw.y1 + boundary));
|
||||
|
||||
Rect fill_rect = draw;
|
||||
Rect stroke_rect = fill_rect.expand (0.5);
|
||||
|
||||
if (_fill) {
|
||||
setup_fill_context (context);
|
||||
|
||||
context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
|
||||
|
||||
if (!_outline) {
|
||||
context->fill ();
|
||||
} else {
|
||||
|
||||
/* special/common case: outline the entire rectangle is
|
||||
* requested, so just use the same path for the fill
|
||||
* and stroke.
|
||||
*/
|
||||
|
||||
if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
|
||||
context->fill_preserve();
|
||||
setup_outline_context (context);
|
||||
context->stroke ();
|
||||
} else {
|
||||
context->fill ();
|
||||
}
|
||||
}
|
||||
}
|
||||
context->rectangle (fill_rect.x0, fill_rect.y0, fill_rect.width(), fill_rect.height());
|
||||
context->fill ();
|
||||
}
|
||||
|
||||
if (_outline) {
|
||||
|
||||
|
||||
setup_outline_context (context);
|
||||
|
||||
if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
|
||||
|
||||
/* if we filled and use full outline, we are already
|
||||
* done. otherwise, draw the frame here.
|
||||
*/
|
||||
|
||||
if (!_fill) {
|
||||
context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
|
||||
context->stroke ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (_outline_what & LEFT) {
|
||||
context->move_to (draw.x0, draw.y0);
|
||||
context->line_to (draw.x0, draw.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & BOTTOM) {
|
||||
context->move_to (draw.x0, draw.y1);
|
||||
context->line_to (draw.x1, draw.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & RIGHT) {
|
||||
context->move_to (draw.x1, draw.y0);
|
||||
context->line_to (draw.x1, draw.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & TOP) {
|
||||
context->move_to (draw.x0, draw.y0);
|
||||
context->line_to (draw.x1, draw.y0);
|
||||
}
|
||||
|
||||
context->stroke ();
|
||||
if (_outline_what & LEFT) {
|
||||
context->move_to (stroke_rect.x0, stroke_rect.y0);
|
||||
context->line_to (stroke_rect.x0, stroke_rect.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & BOTTOM) {
|
||||
context->move_to (stroke_rect.x0, stroke_rect.y1);
|
||||
context->line_to (stroke_rect.x1, stroke_rect.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & RIGHT) {
|
||||
context->move_to (stroke_rect.x1, stroke_rect.y0);
|
||||
context->line_to (stroke_rect.x1, stroke_rect.y1);
|
||||
}
|
||||
|
||||
if (_outline_what & TOP) {
|
||||
context->move_to (stroke_rect.x0, stroke_rect.y0);
|
||||
context->line_to (stroke_rect.x1, stroke_rect.y0);
|
||||
}
|
||||
|
||||
context->stroke ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cassert>
|
||||
|
||||
#include <cairomm/context.h>
|
||||
|
||||
#include "canvas/types.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -118,6 +121,39 @@ Rect::fix () const
|
|||
return r;
|
||||
}
|
||||
|
||||
Rect
|
||||
Rect::convert_to_device (Cairo::RefPtr<Cairo::Context> c) const
|
||||
{
|
||||
Coord xa, ya, xb, yb;
|
||||
|
||||
xa = x0;
|
||||
xb = x1;
|
||||
ya = y0;
|
||||
yb = y1;
|
||||
|
||||
c->user_to_device (xa, ya);
|
||||
c->user_to_device (xb, yb);
|
||||
|
||||
return Rect (xa, ya, xb, yb);
|
||||
}
|
||||
|
||||
|
||||
Rect
|
||||
Rect::convert_to_user (Cairo::RefPtr<Cairo::Context> c) const
|
||||
{
|
||||
Coord xa, ya, xb, yb;
|
||||
|
||||
xa = x0;
|
||||
xb = x1;
|
||||
ya = y0;
|
||||
yb = y1;
|
||||
|
||||
c->device_to_user (xa, ya);
|
||||
c->device_to_user (xb, yb);
|
||||
|
||||
return Rect (xa, ya, xb, yb);
|
||||
}
|
||||
|
||||
Duple
|
||||
ArdourCanvas::operator- (Duple const & o)
|
||||
{
|
||||
|
|
|
@ -178,6 +178,7 @@ WaveView::ensure_cache (framecnt_t start, framecnt_t end,
|
|||
sample_start = max ((framepos_t) 0, (center - canvas_samples));
|
||||
sample_end = min (center + canvas_samples, _region->source_length (0));
|
||||
|
||||
#if 0
|
||||
if (sample_end <= sample_start) {
|
||||
cerr << "sample start = " << sample_start << endl;
|
||||
cerr << "center+ = " << center<< endl;
|
||||
|
@ -188,13 +189,15 @@ WaveView::ensure_cache (framecnt_t start, framecnt_t end,
|
|||
cerr << "END: " << sample_end << endl;
|
||||
assert (false);
|
||||
}
|
||||
#endif
|
||||
|
||||
start = floor (sample_start / (double) _samples_per_pixel);
|
||||
end = ceil (sample_end / (double) _samples_per_pixel);
|
||||
|
||||
assert (end > start);
|
||||
|
||||
cerr << name << " cache miss - new CE, span " << start << " .. " << end << " (" << sample_start << " .. " << sample_end << ")\n";
|
||||
// cerr << name << " cache miss - new CE, span " << start << " .. " << end << " (" << sample_start << " .. " << sample_end << ")\n";
|
||||
|
||||
_cache = new CacheEntry (this, start, end, sample_start, sample_end);
|
||||
}
|
||||
|
||||
|
@ -254,7 +257,19 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
|
|||
// cerr << "Offset into image to place at zero: " << image_offset << endl;
|
||||
|
||||
context->rectangle (draw_start, draw.y0, draw_end - draw_start, draw.height());
|
||||
context->set_source (_cache->image(), self.x0 + image_offset, self.y0);
|
||||
|
||||
/* round image origin position to an exact pixel in device space to
|
||||
* avoid blurring
|
||||
*/
|
||||
|
||||
double x = self.x0 + image_offset;
|
||||
double y = self.y0;
|
||||
context->user_to_device (x, y);
|
||||
x = round (x);
|
||||
y = round (y);
|
||||
context->device_to_user (x, y);
|
||||
|
||||
context->set_source (_cache->image(), x, y);
|
||||
context->fill ();
|
||||
}
|
||||
|
||||
|
@ -408,18 +423,6 @@ WaveView::region_resized ()
|
|||
|
||||
_pre_change_bounding_box = _bounding_box;
|
||||
|
||||
frameoffset_t s = _region->start();
|
||||
|
||||
if (s != _region_start) {
|
||||
/* if the region start changes, the information we have
|
||||
in the image cache is out of date and not useful
|
||||
since it will fragmented into little pieces. invalidate
|
||||
the cache.
|
||||
*/
|
||||
_region_start = _region->start();
|
||||
invalidate_whole_cache ();
|
||||
}
|
||||
|
||||
_bounding_box_dirty = true;
|
||||
compute_bounding_box ();
|
||||
|
||||
|
@ -602,9 +605,6 @@ WaveView::CacheEntry::image ()
|
|||
context->stroke ();
|
||||
|
||||
#else
|
||||
cerr << "draw, logscaled = " << _wave_view->_logscaled << " global " << WaveView::_global_logscaled << endl;
|
||||
cerr << "gradient depth: " << _wave_view->gradient_depth() << endl;
|
||||
|
||||
boost::scoped_array<LineTips> tips (new LineTips[_n_peaks]);
|
||||
|
||||
if (_wave_view->_shape == WaveView::Rectified) {
|
||||
|
@ -656,8 +656,8 @@ WaveView::CacheEntry::image ()
|
|||
|
||||
} else {
|
||||
for (int i = 0; i < _n_peaks; ++i) {
|
||||
tips[i].top = floor (position (_peaks[i].min));
|
||||
tips[i].bot = ceil (position (_peaks[i].max));
|
||||
tips[i].top = position (_peaks[i].min);
|
||||
tips[i].bot = position (_peaks[i].max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -687,7 +687,7 @@ WaveView::CacheEntry::image ()
|
|||
/* generate a new color for the middle of the gradient */
|
||||
double h, s, v;
|
||||
color_to_hsv (_wave_view->_fill_color, h, s, v);
|
||||
/* tone down the saturation */
|
||||
/* change v towards white */
|
||||
v *= 1.0 - _wave_view->gradient_depth();
|
||||
Color center = hsv_to_color (h, s, v, a);
|
||||
color_to_rgba (center, r, g, b, a);
|
||||
|
@ -695,24 +695,26 @@ WaveView::CacheEntry::image ()
|
|||
|
||||
context->set_source (gradient);
|
||||
} else {
|
||||
cerr << "\tno gradient\n";
|
||||
set_source_rgba (context, _wave_view->_fill_color);
|
||||
}
|
||||
|
||||
/* ensure single-pixel lines */
|
||||
|
||||
context->set_line_width (0.5);
|
||||
context->translate (0.5, 0.0);
|
||||
|
||||
/* draw the lines */
|
||||
|
||||
|
||||
if (_wave_view->_shape == WaveView::Rectified) {
|
||||
for (int i = 0; i < _n_peaks; ++i) {
|
||||
context->move_to (i + 0.5, tips[i].top + 0.5); /* down 1 pixel */
|
||||
context->line_to (i + 0.5, tips[i].bot);
|
||||
context->move_to (i, tips[i].top); /* down 1 pixel */
|
||||
context->line_to (i, tips[i].bot);
|
||||
context->stroke ();
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < _n_peaks; ++i) {
|
||||
context->move_to (i + 0.5, tips[i].top + 0.5); /* down 1 pixel */
|
||||
context->line_to (i + 0.5, tips[i].bot - 0.5); /* up 1 pixel */
|
||||
context->move_to (i, tips[i].top);
|
||||
context->line_to (i, tips[i].bot);
|
||||
context->stroke ();
|
||||
}
|
||||
}
|
||||
|
@ -721,14 +723,16 @@ WaveView::CacheEntry::image ()
|
|||
* modelled on pyramix, except that we add clipping indicators.
|
||||
*/
|
||||
|
||||
context->set_source_rgb (0, 0, 0);
|
||||
context->set_source_rgba (0, 0, 0, 1.0);
|
||||
|
||||
for (int i = 0; i < _n_peaks; ++i) {
|
||||
context->rectangle (i + 0.5, tips[i].top, 0.5, 0.5);
|
||||
context->fill ();
|
||||
context->move_to (i, tips[i].top);
|
||||
context->rel_line_to (0, 1.0);
|
||||
context->stroke ();
|
||||
if (_wave_view->_shape != WaveView::Rectified) {
|
||||
context->rectangle (i + 0.5, tips[i].bot, 0.5, 0.5);
|
||||
context->fill ();
|
||||
context->move_to (i, tips[i].bot);
|
||||
context->rel_line_to (0, -1.0);
|
||||
context->stroke ();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -749,13 +753,17 @@ WaveView::CacheEntry::image ()
|
|||
Coord
|
||||
WaveView::CacheEntry::position (double s) const
|
||||
{
|
||||
/* it is important that this returns an integral value, so that we
|
||||
can ensure correct single pixel behaviour.
|
||||
*/
|
||||
|
||||
switch (_wave_view->_shape) {
|
||||
case Rectified:
|
||||
return _wave_view->_height - (s * _wave_view->_height);
|
||||
return floor (_wave_view->_height - (s * _wave_view->_height));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (1.0-s) * (_wave_view->_height / 2.0);
|
||||
return floor ((1.0-s) * (_wave_view->_height / 2.0));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in New Issue