/* === S Y N F I G ========================================================= */ /*! \file widget_ruler.cpp ** \brief Template File ** ** $Id$ ** ** \legal ** ......... ... 2014 Ivan Mahonin ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as ** published by the Free Software Foundation; either version 2 of ** the License, or (at your option) any later version. ** ** This package is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** \endlegal */ /* ========================================================================= */ /* === H E A D E R S ======================================================= */ #ifdef USING_PCH # include "pch.h" #else #ifdef HAVE_CONFIG_H # include #endif #include #include "widgets/widget_ruler.h" #include "general.h" #endif /* === U S I N G =========================================================== */ using namespace std; using namespace synfig; using namespace studio; /* === M A C R O S ========================================================= */ /* === G L O B A L S ======================================================= */ /* === P R O C E D U R E S ================================================= */ /* === M E T H O D S ======================================================= */ Widget_Ruler::Widget_Ruler(bool is_vertical): is_vertical(is_vertical), layout(Pango::Layout::create(get_pango_context())), min(0.0), max(0.0), position(0.0) { } Widget_Ruler::~Widget_Ruler() { } void Widget_Ruler::set_min(synfig::Real value) { if (min != value) { min = value; this->queue_draw(); } } void Widget_Ruler::set_max(synfig::Real value) { if (max != value) { max = value; this->queue_draw(); } } void Widget_Ruler::set_position(synfig::Real value) { if (position != value) { position = value; this->queue_draw(); } } void Widget_Ruler::draw_line( const ::Cairo::RefPtr< ::Cairo::Context>& cr, synfig::Real position, synfig::Real size, const Gdk::RGBA &color, synfig::Real width, synfig::Real height ) { position = round(position) - 0.5; cr->set_line_width(0.5); cr->set_source_rgba(color.get_red(), color.get_green(), color.get_blue(), color.get_alpha()); if (is_vertical) { cr->move_to(width - size, position); cr->line_to(width, position); } else { cr->move_to(position, height - size); cr->line_to(position, height); } cr->stroke(); } void Widget_Ruler::draw_text( const ::Cairo::RefPtr< ::Cairo::Context>& cr, synfig::Real position, const synfig::String &text, int size, const Gdk::RGBA &color, synfig::Real offset, synfig::Real width, synfig::Real height ) { layout->set_text(text); int w = 0, h = 0; Pango::AttrList attr_list; Pango::AttrInt pango_size(Pango::Attribute::create_attr_size(Pango::SCALE*size)); pango_size.set_start_index(0); pango_size.set_end_index(64); attr_list.change(pango_size); layout->set_attributes(attr_list); layout->get_pixel_size(w, h); if (is_vertical) { cr->save(); cr->set_source_rgba(color.get_red(), color.get_green(), color.get_blue(), color.get_alpha()); cr->rotate_degrees(-90.f); cr->move_to(-position + 3, width - offset - h); layout->show_in_cairo_context(cr); cr->restore(); } else { cr->set_source_rgba(color.get_red(), color.get_green(), color.get_blue(), color.get_alpha()); cr->move_to(position + 3, height - offset - h); layout->show_in_cairo_context(cr); } } bool Widget_Ruler::on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr) { const Real min_screen_text_mark_distance = 50.0; const Real mark_1_size = 18.0; const Real mark_2_size = 18.0; const Real mark_3_size = 5.0; const Real mark_4_size = 3.0; const int text_size = 8; const Real text_offset = 5.0; Real screen_min = get_screen_min(); Real screen_max = get_screen_max(); Gdk::RGBA color = get_style_context()->get_color(Gtk::STATE_FLAG_NORMAL); Real min_text_mark_distance = fabs(distance_from_screen(min_screen_text_mark_distance)); int text_degree = (int)round(ceil(log10(min_text_mark_distance))); Real text_mark_distance = exp(log(10)*(Real)text_degree); Real screen_text_mark_distance = fabs(distance_to_screen(text_mark_distance)); int mode = 0.2*screen_text_mark_distance >= min_screen_text_mark_distance ? 2 : 0.5*screen_text_mark_distance >= min_screen_text_mark_distance ? 5 : 10; int sub_divisions_count = 100/mode; Real mark_distance = text_mark_distance/(Real)sub_divisions_count; Real screen_mark_distance = fabs(distance_to_screen(mark_distance)); Real begin, end; if (min < max) { begin = floor(min/(10.0*text_mark_distance))*(10.0*text_mark_distance); end = ceil(max/(10.0*text_mark_distance))*(10.0*text_mark_distance); } else { begin = ceil(min/(10.0*text_mark_distance))*(10.0*text_mark_distance); end = floor(max/(10.0*text_mark_distance))*(10.0*text_mark_distance); } Real screen_begin = position_to_screen(begin); Real screen_position = get_screen_position(); int total_marks_count = sub_divisions_count*(int)round(fabs(end - begin)/text_mark_distance) + 1; if (total_marks_count > 16384) return true; Real width = (Real)get_width(); Real height = (Real)get_height(); // draw background //if (is_vertical) // cr->rectangle(0.0, screen_min, width, screen_max - screen_min); //else // cr->rectangle(screen_min, 0.0, screen_max - screen_min, height); //cr->set_source_rgb(1, 1, 1); //cr->fill(); // draw bounds //draw_line(cr, screen_min, is_vertical ? width : height, width, height); //draw_line(cr, screen_max, is_vertical ? width : height, width, height); // draw marks for(int i = 0; i < total_marks_count; ++i) { Real screen_pos = screen_begin + (Real)i*screen_mark_distance; if (screen_pos <= screen_min || screen_pos >= screen_max) continue; Real pos = min < max ? begin + (Real)i*mark_distance : begin - (Real)i*mark_distance; if ((int)round(pos/mark_distance) == 0) pos = 0.0; if (i%sub_divisions_count == 0) { draw_line(cr, screen_pos, mark_1_size, color, width, height); String format = etl::strprintf("%%.%df", text_degree < 0 ? -text_degree : 0); String text = etl::strprintf(format.c_str(), pos); draw_text(cr, screen_pos, text, text_size, color, text_offset, width, height); } else if ( (mode == 5 && i%10 == 0) || (mode == 2 && i%10 == 0) ) { draw_line(cr, screen_pos, mark_2_size, color, width, height); String format = etl::strprintf("%%.%df", text_degree < 1 ? 1-text_degree : 0); String text = etl::strprintf(format.c_str(), pos); draw_text(cr, screen_pos, text, text_size, color, text_offset, width, height); } else if ( (mode == 10 && i%2 == 0) || (mode == 5 && i%2 == 0) || (mode == 2 && i%5 == 0) ) { draw_line(cr, screen_pos, mark_3_size, color, width, height); } else { draw_line(cr, screen_pos, mark_4_size, color, width, height); } } // draw current position if (screen_position > screen_min && screen_position < screen_max) draw_line(cr, screen_position, is_vertical ? width : height, color, width, height); return true; }