void Renderer_Dragbox::render_vfunc( const Glib::RefPtr<Gdk::Window>& drawable, const Gdk::Rectangle& /*expose_area*/ ) { assert(get_work_area()); if(!get_work_area()) return; // const synfig::Vector focus_point(get_work_area()->get_focus_point()); // Warning : Unused focus_point int drawable_w = drawable->get_width(); int drawable_h = drawable->get_height(); Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context(); const synfig::Vector::value_type window_startx(get_work_area()->get_window_tl()[0]); const synfig::Vector::value_type window_starty(get_work_area()->get_window_tl()[1]); const float pw(get_pw()),ph(get_ph()); const synfig::Point& curr_point(get_curr_point()); const synfig::Point& drag_point(get_drag_point()); { cr->save(); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_line_width(1.0); cr->set_source_rgb(0,0,0); std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); Point tl(std::min(drag_point[0],curr_point[0]),std::min(drag_point[1],curr_point[1])); Point br(std::max(drag_point[0],curr_point[0]),std::max(drag_point[1],curr_point[1])); tl[0]=(tl[0]-window_startx)/pw; tl[1]=(tl[1]-window_starty)/ph; br[0]=(br[0]-window_startx)/pw; br[1]=(br[1]-window_starty)/ph; if(tl[0]>br[0]) swap(tl[0],br[0]); if(tl[1]>br[1]) swap(tl[1],br[1]); cr->rectangle( tl[0], tl[1], br[0]-tl[0], br[1]-tl[1] ); cr->stroke(); cr->restore(); } }
/** Drawing event handler. */ virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { switch (_curShape) { case SHAPE_RECTANGLE: cr->rectangle(20, 20, 200, 100); cr->set_source_rgb(0, 0.8, 0); cr->fill_preserve(); break; case SHAPE_ELLIPSE: cr->arc(150, 100, 90, 0, 2 * 3.14); cr->set_source_rgb(0.8, 0, 0); cr->fill_preserve(); break; case SHAPE_TRIANGLE: cr->move_to(40, 40); cr->line_to(200, 40); cr->line_to(120, 160); cr->line_to(40, 40); cr->set_source_rgb(0.8, 0, 0.8); cr->fill_preserve(); cr->set_line_cap(Cairo::LINE_CAP_ROUND); cr->set_line_join(Cairo::LINE_JOIN_ROUND); break; } cr->set_line_width(3); cr->set_source_rgb(0, 0, 0); cr->stroke(); return true; }
void Renderer_BBox::render_vfunc( const Glib::RefPtr<Gdk::Window>& drawable, const Gdk::Rectangle& /*expose_area*/ ) { assert(get_work_area()); if(!get_work_area()) return; Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context(); const synfig::Vector::value_type window_startx(get_work_area()->get_window_tl()[0]); const synfig::Vector::value_type window_starty(get_work_area()->get_window_tl()[1]); const float pw(get_pw()),ph(get_ph()); const synfig::Point curr_point(get_bbox().get_min()); const synfig::Point drag_point(get_bbox().get_max()); if(get_bbox().area()<10000000000000000.0 && get_bbox().area()>0.00000000000000001) { Point tl(std::min(drag_point[0],curr_point[0]),std::min(drag_point[1],curr_point[1])); Point br(std::max(drag_point[0],curr_point[0]),std::max(drag_point[1],curr_point[1])); tl[0]=(tl[0]-window_startx)/pw; tl[1]=(tl[1]-window_starty)/ph; br[0]=(br[0]-window_startx)/pw; br[1]=(br[1]-window_starty)/ph; if(tl[0]>br[0]) swap(tl[0],br[0]); if(tl[1]>br[1]) swap(tl[1],br[1]); cr->save(); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_line_width(1.0); cr->set_source_rgb(1.0,1.0,1.0); // Operator difference was added in Cairo 1.9.4 // It currently isn't supported by Cairomm #if CAIRO_VERSION >= 10904 cairo_set_operator(cr->cobj(), CAIRO_OPERATOR_DIFFERENCE); #else // Fallback: set color to black cr->set_source_rgb(0,0,0); #endif cr->rectangle( int(tl[0])+0.5, int(tl[1])+0.5, int(br[0]-tl[0]+1), int(br[1]-tl[1]+1) ); cr->stroke(); cr->restore(); } }
//! Only renders the shield background, the text is rendered in renderLabels void Renderer::renderShields(const Cairo::RefPtr<Cairo::Context>& cr, std::vector<shared_ptr<Shield> >& shields) const { cr->save(); cr->set_line_join(Cairo::LINE_JOIN_ROUND); for (auto& shield : shields) { const Style* s = shield->style; double x0, y0, height, width; double border = ceil(s->shield_frame_width/2.0 + s->shield_casing_width); x0 = shield->shield.minX + border; y0 = shield->shield.minY + border; width = shield->shield.getWidth() - 2*border; height = shield->shield.getHeight() - 2*border; if ((int) s->shield_frame_width % 2 == 1) { x0 -= 0.5; y0 -= 0.5; } if (s->shield_shape == Style::ShieldShape::ROUNDED) { cr->arc(x0 + height/2.0, y0 + height/2.0, height/2.0, boost::math::constants::pi<double>()/2.0, 3.0*boost::math::constants::pi<double>()/2.0); cr->arc(x0 + width - height/2.0, y0 + height/2.0, height/2.0, 3.0*boost::math::constants::pi<double>()/2.0, boost::math::constants::pi<double>()/2.0); cr->close_path(); } else cr->rectangle(x0, y0, width, height); // shield casing if (s->shield_casing_width > 0) { cr->set_source_color(s->shield_casing_color), cr->set_line_width(s->shield_frame_width + s->shield_casing_width * 2.0); cr->stroke_preserve(); } // shield background cr->set_source_color(s->shield_color), cr->fill_preserve(); // shield frame cr->set_source_color(s->shield_frame_color), cr->set_line_width(s->shield_frame_width); cr->stroke(); } cr->restore(); }
void Renderer::renderLabels(const Cairo::RefPtr<Cairo::Context>& cr, std::vector<shared_ptr<LabelType> >& labels, AssetCache& cache) const { cr->save(); cr->set_line_join(Cairo::LINE_JOIN_ROUND); for (auto it = labels.rbegin(); it != labels.rend(); it++) { const shared_ptr<LabelType>& label = *it; const Style* s = label->style; cr->set_font_size(s->font_size); cr->move_to(label->origin.x, label->origin.y); cr->set_font_face(cache.getFont( s->font_family.str(), s->font_style == Style::STYLE_ITALIC ? Cairo::FONT_SLANT_ITALIC : Cairo::FONT_SLANT_NORMAL, s->font_weight == Style::WEIGHT_BOLD ? Cairo::FONT_WEIGHT_BOLD : Cairo::FONT_WEIGHT_NORMAL )); cr->text_path(label->text.str()); if (s->text_halo_radius > 0.0) { cr->set_source_color(s->text_halo_color); cr->set_line_width(s->text_halo_radius*2.0); cr->stroke_preserve(); } cr->set_source_color(s->text_color); cr->fill(); } cr->restore(); }
void Renderer_Grid::render_vfunc( const Glib::RefPtr<Gdk::Window>& drawable, const Gdk::Rectangle& /*expose_area*/ ) { assert(get_work_area()); if(!get_work_area()) return; Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context(); int drawable_w = drawable->get_width(); int drawable_h = drawable->get_height(); synfig::Vector grid_size(get_grid_size()); if(grid_size[0] < 0) grid_size[0] = -grid_size[0]; if(grid_size[1] < 0) grid_size[1] = -grid_size[1]; const synfig::Vector::value_type window_startx(get_work_area()->get_window_tl()[0]); const synfig::Vector::value_type window_endx(get_work_area()->get_window_br()[0]); const synfig::Vector::value_type window_starty(get_work_area()->get_window_tl()[1]); const synfig::Vector::value_type window_endy(get_work_area()->get_window_br()[1]); const float pw(get_pw()),ph(get_ph()); synfig::Color grid_color(get_work_area()->get_grid_color()); // Draw out the grid if(grid_size[0]>pw*3.5 && grid_size[1]>ph*3.5) { synfig::Vector::value_type x,y; x=floor(window_startx/grid_size[0])*grid_size[0]; y=floor(window_starty/grid_size[1])*grid_size[1]; cr->save(); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_line_width(1.0); cr->set_source_rgb(grid_color.get_r(),grid_color.get_g(),grid_color.get_b()); std::valarray<double> dashes(2); dashes[0]=4.0; dashes[1]=4.0; cr->set_dash(dashes, 0); if(x<window_endx) for(;x<window_endx;x+=grid_size[0]) { cr->move_to( round_to_int((x-window_startx)/pw), 0 ); cr->line_to( round_to_int((x-window_startx)/pw), drawable_h ); cr->stroke(); } else for(;x>window_endx;x-=grid_size[0]) { cr->move_to( round_to_int((x-window_startx)/pw), 0 ); cr->line_to( round_to_int((x-window_startx)/pw), drawable_h ); cr->stroke(); } if(y<window_endy) for(;y<window_endy;y+=grid_size[1]) { cr->move_to( 0, round_to_int((y-window_starty)/ph) ); cr->line_to( drawable_w, round_to_int((y-window_starty)/ph) ); cr->stroke(); } else for(;y>window_endy;y-=grid_size[1]) { cr->move_to( 0, round_to_int((y-window_starty)/ph) ); cr->line_to( drawable_w, round_to_int((y-window_starty)/ph) ); cr->stroke(); } cr->restore(); } }
void Renderer_Guides::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& drawable, const Gdk::Rectangle& /*expose_area*/ ) { assert(get_work_area()); if(!get_work_area()) return; int drawable_w,drawable_h; drawable->get_size(drawable_w,drawable_h); Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context(); const synfig::Vector::value_type window_startx(get_work_area()->get_window_tl()[0]); const synfig::Vector::value_type window_starty(get_work_area()->get_window_tl()[1]); const float pw(get_pw()),ph(get_ph()); // Draw out the guides { Duckmatic::GuideList::const_iterator iter; cr->save(); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_line_width(1.0); std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); // vertical for(iter=get_guide_list_x().begin();iter!=get_guide_list_x().end();++iter) { const float x((*iter-window_startx)/pw); if(iter==get_work_area()->curr_guide) cr->set_source_rgb(1.0,111.0/255.0,111.0/255.0); else cr->set_source_rgb(111.0/255.0,111.0/255.0,1.0); cr->move_to( x, 0 ); cr->line_to( x, drawable_h ); cr->stroke(); } // horizontal for(iter=get_guide_list_y().begin();iter!=get_guide_list_y().end();++iter) { const float y((*iter-window_starty)/ph); if(iter==get_work_area()->curr_guide) cr->set_source_rgb(1.0,111.0/255.0,111.0/255.0); else cr->set_source_rgb(111.0/255.0,111.0/255.0,1.0); cr->move_to( 0, y ); cr->line_to( drawable_w, y ); cr->stroke(); } cr->restore(); } }
bool studio::Widget_NavView::on_expose_draw(GdkEventExpose */*exp*/) { #ifdef SINGLE_THREADED // don't redraw if the previous redraw is still running single-threaded // or we end up destroying the renderer that's rendering it if (App::single_threaded && renderer && renderer->updating) return false; #endif //print out the zoom //HACK kind of... //zoom_print.set_text(strprintf("%.1f%%",100*unit_to_zoom(adj_zoom.get_value()))); //draw the good stuff on_start_render(); //if we've got a preview etc. display it... if(get_canvas_view() && prev) { //axis transform from units to pixel coords float xaxis = 0, yaxis = 0; int canvw = get_canvas_view()->get_canvas()->rend_desc().get_w(); //int canvh = get_canvas_view()->get_canvas()->rend_desc().get_h(); float pw = get_canvas_view()->get_canvas()->rend_desc().get_pw(); float ph = get_canvas_view()->get_canvas()->rend_desc().get_ph(); int w = prev->get_width(); int h = prev->get_height(); //scale up/down to the nearest pixel ratio... //and center in center int offx=0, offy=0; float sx, sy; int nw,nh; sx = drawto.get_width() / (float)w; sy = drawto.get_height() / (float)h; //synfig::warning("Nav redraw: now to scale the bitmap: %.3f x %.3f",sx,sy); //round to smallest scale (fit entire thing in window without distortion) if(sx > sy) sx = sy; //else sy = sx; //scaling and stuff // the point to navpixel space conversion should be: // (navpixels / canvpixels) * (canvpixels / canvsize) // or (navpixels / prevpixels) * (prevpixels / navpixels) xaxis = sx * w / (float)canvw; yaxis = xaxis/ph; xaxis /= pw; //scale to a new pixmap and then copy over to the window nw = (int)(w*sx); nh = (int)(h*sx); //must now center to be cool offx = (drawto.get_width() - nw)/2; offy = (drawto.get_height() - nh)/2; //trivial escape if(nw == 0 || nh == 0)return true; //draw to drawing area Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(drawto.get_window()); Cairo::RefPtr<Cairo::Context> cr = drawto.get_window()->create_cairo_context(); //synfig::warning("Nav: Scaling pixmap to off (%d,%d) with size (%d,%d)", offx,offy,nw, nh); Glib::RefPtr<Gdk::Pixbuf> scalepx = prev->scale_simple(nw,nh,Gdk::INTERP_NEAREST); cr->save(); //synfig::warning("Nav: Drawing scaled bitmap"); Gdk::Cairo::set_source_pixbuf( cr, //cairo context scalepx, //pixbuf offx, offy //coordinates to place upper left corner of pixbuf ); cr->paint(); //draw fancy red rectangle around focus point const Point &wtl = get_canvas_view()->work_area->get_window_tl(), &wbr = get_canvas_view()->work_area->get_window_br(); //it must be clamped to the drawing area though int l=0,rw=0,t=0,rh=0; const Point fp = -get_canvas_view()->work_area->get_focus_point(); //get focus point in normal space rw = (int)(abs((wtl[0]-wbr[0])*xaxis)); rh = (int)(abs((wtl[1]-wbr[1])*yaxis)); //transform into pixel space l = (int)(drawto.get_width()/2 + fp[0]*xaxis - rw/2); t = (int)(drawto.get_height()/2 + fp[1]*yaxis - rh/2); //coord system: // tl : (offx,offy) // axis multipliers = xaxis,yaxis //synfig::warning("Nav: tl (%f,%f), br (%f,%f)", wtl[0],wtl[1],wbr[0],wbr[1]); //synfig::warning("Nav: tl (%f,%f), br (%f,%f)", wtl[0],wtl[1],wbr[0],wbr[1]); //synfig::warning("Nav: Drawing Rectangle (%d,%d) with dim (%d,%d)", l,t,rw,rh); cr->set_line_width(2.0); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_source_rgb(1,0,0); cr->rectangle(l,t,rw,rh); cr->stroke(); cr->restore(); } return false; //draw everything else too }
bool studio::Widget_NavView::on_drawto_draw(const Cairo::RefPtr<Cairo::Context> &cr) { #ifdef SINGLE_THREADED // don't redraw if the previous redraw is still running single-threaded // or we end up destroying the renderer that's rendering it if (App::single_threaded && renderer && renderer->updating) return false; #endif //draw the good stuff on_start_render(); //if we've got a preview etc. display it... if(get_canvas_view()) { //axis transform from units to pixel coords float xaxis = 0, yaxis = 0; int canvw = get_canvas_view()->get_canvas()->rend_desc().get_w(); int w, h; float pw = get_canvas_view()->get_canvas()->rend_desc().get_pw(); float ph = get_canvas_view()->get_canvas()->rend_desc().get_ph(); if(prev && !studio::App::navigator_uses_cairo) { w = prev->get_width(); h = prev->get_height(); } if(studio::App::navigator_uses_cairo) { w=cairo_image_surface_get_width(cairo_surface); h=cairo_image_surface_get_height(cairo_surface); } //scale up/down to the nearest pixel ratio... //and center in center float offx=0, offy=0; float sx, sy; int nw,nh; sx = drawto.get_width() / (float)w; sy = drawto.get_height() / (float)h; //round to smallest scale (fit entire thing in window without distortion) if(sx > sy) sx = sy; //else sy = sx; //scaling and stuff // the point to navpixel space conversion should be: // (navpixels / canvpixels) * (canvpixels / canvsize) // or (navpixels / prevpixels) * (prevpixels / navpixels) xaxis = sx * w / (float)canvw; yaxis = xaxis/ph; xaxis /= pw; //scale to a new pixmap and then copy over to the window nw = (int)(w*sx); nh = (int)(h*sx); //must now center to be cool offx = (drawto.get_width() - nw)/2; offy = (drawto.get_height() - nh)/2; //trivial escape if(nw == 0 || nh == 0)return true; //draw to drawing area if(prev && !studio::App::navigator_uses_cairo) { Glib::RefPtr<Gdk::Pixbuf> scalepx = prev->scale_simple(nw,nh,Gdk::INTERP_NEAREST); cr->save(); //synfig::warning("Nav: Drawing scaled bitmap"); Gdk::Cairo::set_source_pixbuf( cr, //cairo context scalepx, //pixbuf (int)offx, (int)offy //coordinates to place upper left corner of pixbuf ); cr->paint(); cr->restore(); } if(studio::App::navigator_uses_cairo) { cr->save(); cr->scale(sx, sx); cairo_set_source_surface(cr->cobj(), cairo_surface, offx/sx, offy/sx); cairo_pattern_set_filter(cairo_get_source(cr->cobj()), CAIRO_FILTER_NEAREST); cr->paint(); cr->restore(); } cr->save(); //draw fancy red rectangle around focus point const Point &wtl = get_canvas_view()->work_area->get_window_tl(), &wbr = get_canvas_view()->work_area->get_window_br(); //it must be clamped to the drawing area though int l=0,rw=0,t=0,rh=0; const Point fp = -get_canvas_view()->work_area->get_focus_point(); //get focus point in normal space rw = (int)(abs((wtl[0]-wbr[0])*xaxis)); rh = (int)(abs((wtl[1]-wbr[1])*yaxis)); //transform into pixel space l = (int)(drawto.get_width()/2 + fp[0]*xaxis - rw/2); t = (int)(drawto.get_height()/2 + fp[1]*yaxis - rh/2); //coord system: // tl : (offx,offy) // axis multipliers = xaxis,yaxis cr->set_line_width(2.0); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_antialias(Cairo::ANTIALIAS_NONE); // Visually distinguish when using Cairo on Navigator or not. if(!studio::App::navigator_uses_cairo) cr->set_source_rgb(1,0,0); else cr->set_source_rgb(0,1,0); cr->rectangle(l,t,rw,rh); cr->stroke(); cr->restore(); } return false; //draw everything else too }
void FrequencyGraph( Cairo::RefPtr<Cairo::Context> cr, bool active, float x, float y, float xS, float yS, EqualizerState state) { cr->set_line_cap( Cairo::LINE_CAP_ROUND ); cr->set_line_join( Cairo::LINE_JOIN_ROUND); int xSize = xS; int ySize = yS; // works but a bit simple cr -> move_to( x , y ); cr -> line_to( x + xSize, y ); cr -> line_to( x + xSize, y + ySize ); cr -> line_to( x , y + ySize ); cr -> close_path(); // Draw outline shape cr -> set_source_rgb (0.1,0.1,0.1); cr -> fill(); // draw "frequency guides" std::valarray< double > dashes(2); dashes[0] = 2.0; dashes[1] = 2.0; cr->set_dash (dashes, 0.0); cr->set_line_width(1.0); cr->set_source_rgb (0.4,0.4,0.4); for ( int i = 0; i < 4; i++ ) { cr->move_to( x + ((xSize / 4.f)*i), y ); cr->line_to( x + ((xSize / 4.f)*i), y + ySize ); } for ( int i = 0; i < 4; i++ ) { cr->move_to( x , y + ((ySize / 4.f)*i) ); cr->line_to( x +xSize, y + ((ySize / 4.f)*i) ); } cr->stroke(); cr->unset_dash(); // set colour based on active or not if ( active ) setColour(cr, COLOUR_BLUE_1, 0.2 ); else setColour(cr, COLOUR_GREY_1, 0.2 ); int tmpX = x; int tmpY = y; // precalculate some variables float oldGainPix = (ySize / 60.f) * (state.gain[0] - 0.5 ) * 40; float oldXLoc = 0; float qPix = ((xSize * 0.2) / 3.f ); //float oldCutoff = 0; // move to bottom left, draw line to middle left cr->move_to( tmpX, tmpY + ySize ); cr->line_to( tmpX, tmpY + (ySize * 0.5) - oldGainPix ); for ( int i = 0; i < 4; i++ ) { //float cutoff = state.cutoffFreq[i] / 20000; float gainPix = (ySize / 60.f) * (state.gain[i] - 0.5 ) * 40; float xLoc = xSize * 0.2 * (i+1); //std::cout << "I: " << i << " GainPix: " << gainPix << " tmpY - gainPix" << tmpY - gainPix << std::endl; cr->curve_to( tmpX + oldXLoc + qPix, tmpY + (ySize * 0.5) - oldGainPix ,// control point 1 tmpX + xLoc - qPix , tmpY + (ySize * 0.5) - gainPix , // control point 2 tmpX + xLoc , tmpY + (ySize * 0.5) - gainPix ); // end of curve // update variables for next iter oldGainPix = gainPix; oldXLoc = xLoc; //oldCutoff = cutoff; } // last bit of curve to the right edge cr->curve_to( tmpX + oldXLoc + qPix, tmpY + (ySize * 0.5) - oldGainPix, // control point 1 tmpX + xSize - qPix, tmpY + (ySize * 0.5) - oldGainPix, // control point 2 tmpX + xSize , tmpY + (ySize * 0.5) - oldGainPix); // end of curve cr->line_to( tmpX + xSize , tmpY + ySize ); cr->close_path(); cr->fill_preserve(); cr->set_line_width(2.5); if ( active ) setColour(cr, COLOUR_BLUE_1 ); else setColour(cr, COLOUR_GREY_1 ); cr->stroke(); // outline cr->rectangle( x, y , xS, yS ); cr->set_line_width(3); if ( active ) setColour(cr, COLOUR_GREY_2 ); else setColour(cr, COLOUR_GREY_3 ); cr->stroke(); //std::cout << "LupppWidget::FrequencyGraph() called!" << std::endl; }
Cairo::RefPtr<Cairo::ImageSurface> TextSurface::create_cairo_surface(const std::string& text, const TextProperties& text_props, Cairo::TextExtents& out_text_extents, Cairo::FontExtents& out_font_extents) { { // get TextExtents and FontExtents Cairo::RefPtr<Cairo::ImageSurface> tmp_surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, 0, 0); Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(tmp_surface); cr->set_font_size(text_props.get_font_size()); cr->select_font_face(text_props.get_font(), Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); cr->get_text_extents(text, out_text_extents); cr->get_font_extents(out_font_extents); } Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, static_cast<int>(out_text_extents.width + text_props.get_line_width()), static_cast<int>(out_text_extents.height + text_props.get_line_width())); Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface); // set the font cr->set_font_size(text_props.get_font_size()); cr->select_font_face(text_props.get_font(), Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL); if (text_props.get_line_width() != 0) { // create path cr->move_to(-out_text_extents.x_bearing + text_props.get_line_width()/2.0, -out_text_extents.y_bearing + text_props.get_line_width()/2.0); cr->text_path(text); // paint cr->set_line_width(text_props.get_line_width()); cr->set_line_join(Cairo::LINE_JOIN_ROUND); cr->set_source_rgb(0.0, 0.0, 0.0); cr->stroke(); } // print text cr->move_to(-out_text_extents.x_bearing + text_props.get_line_width()/2.0, -out_text_extents.y_bearing + text_props.get_line_width()/2.0); cr->set_source_rgb(1.0, 1.0, 0.0); double y = -out_text_extents.y_bearing - out_font_extents.ascent; // toying around with color gradients if (false) { Cairo::RefPtr<Cairo::LinearGradient> gradient = Cairo::LinearGradient::create(0, y, 0, y + out_font_extents.ascent + out_font_extents.descent); gradient->add_color_stop_rgb(0.0, 1.0, 1.0, 0.0); gradient->add_color_stop_rgb(0.5, 1.0, 1.0, 1.0); gradient->add_color_stop_rgb(0.5, 0.4, 0.4, 0.2); gradient->add_color_stop_rgb(1.0, 1.0, 1.0, 0.0); cr->set_source(gradient); } cr->show_text(text); return surface; }
void Renderer_Ducks::render_vfunc( const Glib::RefPtr<Gdk::Drawable>& drawable, const Gdk::Rectangle& /*expose_area*/ ) { assert(get_work_area()); if(!get_work_area()) return; const synfig::Point window_start(get_work_area()->get_window_tl()); const float pw(get_pw()),ph(get_ph()); const bool solid_lines(get_work_area()->solid_lines); bool alternative = get_work_area()->get_alternative_mode(); const std::list<etl::handle<Duckmatic::Bezier> >& bezier_list(get_work_area()->bezier_list()); const std::list<handle<Duckmatic::Stroke> >& stroke_list(get_work_area()->stroke_list()); Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_work_area()->get_pango_context())); Cairo::RefPtr<Cairo::Context> cr = drawable->create_cairo_context(); cr->save(); cr->set_line_cap(Cairo::LINE_CAP_BUTT); cr->set_line_join(Cairo::LINE_JOIN_MITER); // Render the strokes for(std::list<handle<Duckmatic::Stroke> >::const_iterator iter=stroke_list.begin();iter!=stroke_list.end();++iter) { cr->save(); std::list<synfig::Point>::iterator iter2; for(iter2=(*iter)->stroke_data->begin();iter2!=(*iter)->stroke_data->end();++iter2) { cr->line_to( ((*iter2)[0]-window_start[0])/pw, ((*iter2)[1]-window_start[1])/ph ); } cr->set_line_width(1.0); cr->set_source_rgb( colorconv_synfig2gdk((*iter)->color).get_red_p(), colorconv_synfig2gdk((*iter)->color).get_green_p(), colorconv_synfig2gdk((*iter)->color).get_blue_p() ); cr->stroke(); cr->restore(); } // Render the beziers for(std::list<handle<Duckmatic::Bezier> >::const_iterator iter=bezier_list.begin();iter!=bezier_list.end();++iter) { Point p1((*iter)->p1->get_trans_point()-window_start); Point p2((*iter)->p2->get_trans_point()-window_start); Point c1((*iter)->c1->get_trans_point()-window_start); Point c2((*iter)->c2->get_trans_point()-window_start); p1[0]/=pw;p1[1]/=ph; p2[0]/=pw;p2[1]/=ph; c1[0]/=pw;c1[1]/=ph; c2[0]/=pw;c2[1]/=ph; cr->save(); cr->move_to(p1[0], p1[1]); cr->curve_to(c1[0], c1[1], c2[0], c2[1], p2[0], p2[1]); /* if (solid_lines) { cr->set_source_rgb(0,0,0); // DUCK_COLOR_BEZIER_1 cr->set_line_width(3.0); cr->stroke_preserve(); cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0); //DUCK_COLOR_BEZIER_2 cr->set_line_width(1.0); cr->stroke(); } else */ { //Solid line background cr->set_line_width(1.0); cr->set_source_rgb(0,0,0); // DUCK_COLOR_BEZIER_1 cr->stroke_preserve(); //Dashes cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0); //DUCK_COLOR_BEZIER_2 std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); cr->stroke(); } cr->restore(); } const DuckList duck_list(get_work_area()->get_duck_list()); std::list<ScreenDuck> screen_duck_list; const float radius((abs(pw)+abs(ph))*4); etl::handle<Duck> hover_duck(get_work_area()->find_duck(get_work_area()->get_cursor_pos(),radius, get_work_area()->get_type_mask())); // Render the ducks for(std::list<handle<Duck> >::const_iterator iter=duck_list.begin();iter!=duck_list.end();++iter) { // If this type of duck has been masked, then skip it if(!(*iter)->get_type() || (!(get_work_area()->get_type_mask() & (*iter)->get_type()))) continue; Point sub_trans_point((*iter)->get_sub_trans_point()); Point sub_trans_origin((*iter)->get_sub_trans_origin()); if (App::restrict_radius_ducks && (*iter)->is_radius()) { if (sub_trans_point[0] < sub_trans_origin[0]) sub_trans_point[0] = sub_trans_origin[0]; if (sub_trans_point[1] < sub_trans_origin[1]) sub_trans_point[1] = sub_trans_origin[1]; } Point point((*iter)->get_transform_stack().perform(sub_trans_point)); Point origin((*iter)->get_transform_stack().perform(sub_trans_origin)); point[0]=(point[0]-window_start[0])/pw; point[1]=(point[1]-window_start[1])/ph; bool has_connect = (*iter)->get_tangent() || ((*iter)->get_type()&( Duck::TYPE_ANGLE | Duck::TYPE_SKEW | Duck::TYPE_SCALE_X | Duck::TYPE_SCALE_Y )); if((*iter)->get_connect_duck()) { has_connect=true; origin=(*iter)->get_connect_duck()->get_trans_point(); } origin[0]=(origin[0]-window_start[0])/pw; origin[1]=(origin[1]-window_start[1])/ph; bool selected(get_work_area()->duck_is_selected(*iter)); bool hover(*iter==hover_duck || (*iter)->get_hover()); if(get_work_area()->get_selected_value_node()) { synfigapp::ValueDesc value_desc((*iter)->get_value_desc()); if (value_desc.is_valid() && ((value_desc.is_value_node() && get_work_area()->get_selected_value_node() == value_desc.get_value_node()) || (value_desc.parent_is_value_node() && get_work_area()->get_selected_value_node() == value_desc.get_parent_value_node()))) { cr->save(); cr->rectangle( round_to_int(point[0]-5), round_to_int(point[1]-5), 10, 10 ); cr->set_line_width(2.0); cr->set_source_rgb(1, 0, 0); //DUCK_COLOR_SELECTED cr->stroke(); cr->restore(); } } if((*iter)->get_box_duck()) { Point boxpoint((*iter)->get_box_duck()->get_trans_point()); boxpoint[0]=(boxpoint[0]-window_start[0])/pw; boxpoint[1]=(boxpoint[1]-window_start[1])/ph; Point tl(min(point[0],boxpoint[0]),min(point[1],boxpoint[1])); cr->save(); cr->rectangle( round_to_int(tl[0]), round_to_int(tl[1]), round_to_int(abs(boxpoint[0]-point[0])), round_to_int(abs(boxpoint[1]-point[1])) ); // Solid white box cr->set_line_width(1.0); cr->set_source_rgb(1,1,1); //DUCK_COLOR_BOX_1 cr->stroke_preserve(); // Dashes cr->set_source_rgb(0,0,0); //DUCK_COLOR_BOX_2 std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); cr->stroke(); cr->restore(); } if((*iter)->is_axes_tracks()) { Point pos((*iter)->get_point()); Point points[] = { (*iter)->get_sub_trans_origin(), (*iter)->get_sub_trans_point(Point(pos[0],0)), (*iter)->get_sub_trans_point(), (*iter)->get_sub_trans_point(Point(0,pos[1])), (*iter)->get_sub_trans_origin() }; cr->save(); for(int i = 0; i < 5; i++) { Point p((*iter)->get_transform_stack().perform(points[i])); Real x = (p[0]-window_start[0])/pw; Real y = (p[1]-window_start[1])/ph; if (i == 0) cr->move_to(x, y); else cr->line_to(x, y); } // Solid white box cr->set_line_width(1.0); cr->set_source_rgb(1,1,1); //DUCK_COLOR_BOX_1 cr->stroke_preserve(); // Dashes cr->set_source_rgb(0,0,0); //DUCK_COLOR_BOX_2 std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); cr->stroke(); cr->restore(); } ScreenDuck screen_duck; screen_duck.pos=point; screen_duck.selected=selected; screen_duck.hover=hover; screen_duck.has_alternative=(*iter)->get_alternative_value_desc().is_valid(); if(!(*iter)->get_editable(alternative)) screen_duck.color=(DUCK_COLOR_NOT_EDITABLE); else if((*iter)->get_tangent()) if(0){ // Tangents have different color depending on the split state (disabled for now) // // Check if we can reach the canvas and set the time to // evaluate the split value accordingly synfig::Canvas::Handle canvas_h(get_work_area()->get_canvas()); synfig::Time time(canvas_h?canvas_h->get_time():synfig::Time(0)); // Retrieve the split value of the bline point. const synfigapp::ValueDesc& v_d((*iter)->get_value_desc()); synfig::LinkableValueNode::Handle parent; if(v_d.parent_is_linkable_value_node()) { parent=v_d.get_parent_value_node(); bool split; synfig::ValueNode::Handle child(parent->get_link("split")); if(synfig::ValueNode_Animated::Handle::cast_dynamic(child)) { synfig::ValueNode_Animated::Handle animated_child(synfig::ValueNode_Animated::Handle::cast_dynamic(child)); split=animated_child->new_waypoint_at_time(time).get_value(time).get(split); } else if(synfig::ValueNode_Const::Handle::cast_dynamic(child)) { synfig::ValueNode_Const::Handle const_child(synfig::ValueNode_Const::Handle::cast_dynamic(child)); split=(const_child->get_value()).get(split); } screen_duck.color=(split? DUCK_COLOR_TANGENT_2 : DUCK_COLOR_TANGENT_1); } else screen_duck.color=DUCK_COLOR_TANGENT_1; } else { // All tangents are the same color screen_duck.color=((*iter)->get_scalar()<0 ? DUCK_COLOR_TANGENT_1 : DUCK_COLOR_TANGENT_1); } else if((*iter)->get_type()&Duck::TYPE_VERTEX) screen_duck.color=DUCK_COLOR_VERTEX; else if((*iter)->get_type()&Duck::TYPE_RADIUS) screen_duck.color=((*iter)->is_linear() ? DUCK_COLOR_LINEAR : DUCK_COLOR_RADIUS); else if((*iter)->get_type()&Duck::TYPE_WIDTH) screen_duck.color=DUCK_COLOR_WIDTH; else if((*iter)->get_type()&Duck::TYPE_ANGLE) screen_duck.color=(DUCK_COLOR_ANGLE); else if((*iter)->get_type()&Duck::TYPE_WIDTHPOINT_POSITION) screen_duck.color=(DUCK_COLOR_WIDTHPOINT_POSITION); else screen_duck.color=DUCK_COLOR_OTHER; screen_duck_list.push_front(screen_duck); if(has_connect) { cr->save(); cr->move_to(origin[0], origin[1]); cr->line_to(point[0], point[1]); if(solid_lines) { // Outside cr->set_line_width(3.0); cr->set_source_rgb(0,0,0); //DUCK_COLOR_CONNECT_OUTSIDE cr->stroke_preserve(); // Inside cr->set_line_width(1.0); cr->set_source_rgb(159.0/255,239.0/255,239.0/255); //DUCK_COLOR_CONNECT_INSIDE cr->stroke(); } else { // White background cr->set_line_width(1.0); cr->set_source_rgb(0,0,0); //DUCK_COLOR_CONNECT_OUTSIDE cr->stroke_preserve(); // Dashes on top of the background cr->set_source_rgb(159.0/255,239.0/255,239.0/255); //DUCK_COLOR_CONNECT_INSIDE std::valarray<double> dashes(2); dashes[0]=5.0; dashes[1]=5.0; cr->set_dash(dashes, 0); cr->stroke(); } cr->restore(); } if((*iter)->is_radius()) { if (!(*iter)->is_linear()) { const Real mag((point-origin).mag()); cr->save(); cr->arc( origin[0], origin[1], mag, 0, M_PI*2 ); if(solid_lines) { cr->set_line_width(3.0); cr->set_source_rgb(0,0,0); cr->stroke_preserve(); cr->set_source_rgb(175.0/255.0,175.0/255.0,175.0/255.0); } else { cr->set_source_rgb(1.0,1.0,1.0); // Operator difference was added in Cairo 1.9.4 // It currently isn't supported by Cairomm #if CAIRO_VERSION >= 10904 cairo_set_operator(cr->cobj(), CAIRO_OPERATOR_DIFFERENCE); #else // Fallback: set color to black cr->set_source_rgb(0,0,0); #endif } cr->set_line_width(1.0); cr->stroke(); cr->restore(); } if(hover) { Real mag; if ((*iter)->get_exponential()){ mag = log((*iter)->get_point().mag()); } else if (App::restrict_radius_ducks) { Point sub_trans_point((*iter)->get_sub_trans_point()); Point sub_trans_origin((*iter)->get_sub_trans_origin()); if (sub_trans_point[0] < sub_trans_origin[0]) sub_trans_point[0] = sub_trans_origin[0]; if (sub_trans_point[1] < sub_trans_origin[1]) sub_trans_point[1] = sub_trans_origin[1]; Point point((*iter)->get_transform_stack().perform(sub_trans_point)); Point origin((*iter)->get_transform_stack().perform(sub_trans_origin)); mag = (point-origin).mag(); } else mag = ((*iter)->get_trans_point()-(*iter)->get_trans_origin()).mag(); Distance real_mag(mag, Distance::SYSTEM_UNITS); if (!(*iter)->get_exponential()) real_mag.convert(App::distance_system,get_work_area()->get_rend_desc()); cr->save(); layout->set_text(real_mag.get_string()); cr->set_source_rgb(0,0,0); // DUCK_COLOR_WIDTH_TEXT_1 cr->move_to( point[0]+1+6, point[1]+1-8 ); layout->show_in_cairo_context(cr); cr->stroke(); cr->set_source_rgb(1,0,1); // DUCK_COLOR_WIDTH_TEXT_2 cr->move_to( point[0]+6, point[1]-8 ); layout->show_in_cairo_context(cr); cr->stroke(); cr->restore(); } } if((*iter)->get_type()&&Duck::TYPE_WIDTHPOINT_POSITION) { if(hover) { synfig::Canvas::Handle canvas_h(get_work_area()->get_canvas()); synfig::Time time(canvas_h?canvas_h->get_time():synfig::Time(0)); synfigapp::ValueDesc value_desc((*iter)->get_value_desc()); synfig::ValueNode_WPList::Handle wplist=NULL; ValueNode_Composite::Handle wpoint_composite=NULL; Real radius=0.0; Real new_value; Point p(sub_trans_point-sub_trans_origin); if(value_desc.parent_is_value_node()) wplist=synfig::ValueNode_WPList::Handle::cast_dynamic(value_desc.get_parent_value_node()); if(wplist) { bool wplistloop(wplist->get_loop()); synfig::ValueNode_BLine::Handle bline(synfig::ValueNode_BLine::Handle::cast_dynamic(wplist->get_bline())); wpoint_composite=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()); if(bline && wpoint_composite) { bool blineloop(bline->get_loop()); bool homogeneous=false; // Retrieve the homogeneous layer parameter std::set<Node*>::iterator iter; for(iter=wplist->parent_set.begin();iter!=wplist->parent_set.end();++iter) { Layer::Handle layer; layer=Layer::Handle::cast_dynamic(*iter); if(layer && layer->get_name() == "advanced_outline") { homogeneous=layer->get_param("homogeneous").get(bool()); break; } } WidthPoint wp((*wpoint_composite)(time).get(WidthPoint())); if(wplistloop) { // The wplist is looped. This may require a position parameter // outside the range of 0-1, so make sure that the position doesn't // change drastically. // First normalise the current position Real value_old(wp.get_norm_position(wplistloop)); Real value_old_b(wp.get_bound_position(wplistloop)); // If it is homogeneous then convert it to standard value_old=homogeneous?hom_to_std((*bline)(time), value_old, wplistloop, blineloop):value_old; // grab a new position given by duck's position on the bline Real value_new = synfig::find_closest_point((*bline)(time), p , radius, blineloop); // calculate the difference between old and new positions Real difference = fmod( fmod(value_new - value_old, 1.0) + 1.0 , 1.0); //fmod is called twice to avoid negative values if (difference > 0.5) difference=difference-1.0; // calculate a new value for the position new_value=value_old+difference; // restore the homogeneous value if needed new_value = homogeneous?std_to_hom((*bline)(time), new_value, wplistloop, blineloop):new_value; // this is the difference between the new value and the old value inside the boundaries Real bound_diff((wp.get_lower_bound() + new_value*(wp.get_upper_bound()-wp.get_lower_bound()))-value_old_b); // add the new diff to the current value new_value = wp.get_position() + bound_diff; } else { // grab a new position given by duck's position on the bline new_value = synfig::find_closest_point((*bline)(time), p , radius, blineloop); // if it is homogeneous then convert to it new_value=homogeneous?std_to_hom((*bline)(time), new_value, wplistloop, blineloop):new_value; // convert the value inside the boundaries new_value = wp.get_lower_bound()+new_value*(wp.get_upper_bound()-wp.get_lower_bound()); } cr->save(); layout->set_text(strprintf("%2.3f", new_value)); cr->set_source_rgb(0,0,0); // DUCK_COLOR_WIDTH_TEXT_1 cr->move_to( point[0]+1+6, point[1]+1-18 ); layout->show_in_cairo_context(cr); cr->stroke(); cr->set_source_rgb(1,0,1); // DUCK_COLOR_WIDTH_TEXT_2 cr->move_to( point[0]+6, point[1]-18 ); layout->show_in_cairo_context(cr); cr->stroke(); cr->restore(); } } } } } for(;screen_duck_list.size();screen_duck_list.pop_front()) { Gdk::Color color(screen_duck_list.front().color); double radius = 4; double outline = 1; bool duck_alternative = alternative && screen_duck_list.front().has_alternative; // Draw the hovered duck last (on top of everything) if(screen_duck_list.front().hover && !screen_duck_list.back().hover && screen_duck_list.size()>1) { screen_duck_list.push_back(screen_duck_list.front()); continue; } cr->save(); if(!screen_duck_list.front().selected) { color.set_red(color.get_red()*2/3); color.set_green(color.get_green()*2/3); color.set_blue(color.get_blue()*2/3); } if(screen_duck_list.front().hover) { radius += 1; outline += 1; } cr->arc( screen_duck_list.front().pos[0], screen_duck_list.front().pos[1], radius, 0, M_PI*2 ); cr->set_source_rgba( color.get_red_p(), color.get_green_p(), color.get_blue_p(), duck_alternative ? 0.5 : 1.0 ); cr->fill_preserve(); cr->set_line_width(outline); cr->set_source_rgba(0,0,0,1); //DUCK_COLOR_OUTLINE cr->stroke(); cr->restore(); } }