wdiagram.cc
来自「Click is a modular router toolkit. To us」· CC 代码 · 共 882 行 · 第 1/2 页
CC
882 行
#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <click/config.h>#include <click/userutils.hh>#include <click/confparse.hh>#include <click/bitvector.hh>#include <clicktool/processingt.hh>#include <clicktool/elementmap.hh>#include <list>#include <math.h>#include <cairo-ps.h>#include <cairo-pdf.h>#include "wdiagram.hh"#include "dwidget.hh"#include "crouter.hh"#include "whandler.hh"#include "scopechain.hh"extern "C" {#include "support.h"}namespace clicky {extern "C" {static void diagram_map(GtkWidget *, gpointer);static gboolean on_diagram_event(GtkWidget *, GdkEvent *, gpointer);static gboolean diagram_expose(GtkWidget *, GdkEventExpose *, gpointer);static void on_diagram_size_allocate(GtkWidget *, GtkAllocation *, gpointer);}cdiagram::cdiagram(crouter *cr, PangoLayout *pl, unsigned generation) : _relt(new delt){ if (cr->router()) { ScopeChain chain(cr->router()); _relt->create_elements(cr, cr->router(), cr->processing(), &_elt_map, chain); _relt->assign_z_indexes(0); _relt->create_connections(cr); dcontext dcx(cr, pl, 0, generation, 0, 1); ElementMap::push_default(cr->element_map()); _relt->layout_main(dcx); ElementMap::pop_default(); } _relt->insert_all(_rects); assign(*_relt);}cdiagram::~cdiagram(){ delete _relt;}void cdiagram::layout_recompute_bounds(){ _relt->layout_recompute_bounds(); assign(*_relt);}void cdiagram::find_rect_elts(const rectangle &r, std::vector<dwidget *> &result) const{ _rects.find_all(r, result); std::sort(result.begin(), result.end(), dwidget::z_index_less); std::vector<dwidget *>::iterator eltsi = std::unique(result.begin(), result.end()); result.erase(eltsi, result.end());}delt *cdiagram::point_elt(const point &p) const{ std::vector<dwidget *> elts; _rects.find_all(p.x(), p.y(), elts); std::sort(elts.begin(), elts.end(), dwidget::z_index_greater); std::vector<dwidget *>::iterator eltsi = std::unique(elts.begin(), elts.end()); elts.erase(eltsi, elts.end()); for (eltsi = elts.begin(); eltsi != elts.end(); ++eltsi) if ((*eltsi)->contains(p)) if (delt *e = (*eltsi)->cast_elt()) if (dedisp_visible(e->display())) return e; return 0;}extern "C" {static cairo_status_t cairo_surface_ignore_write(void *, const unsigned char *, unsigned){ return CAIRO_STATUS_SUCCESS;}static cairo_status_t cairo_surface_stdout_write(void *, const unsigned char *str, unsigned len){ ignore_result(fwrite(str, 1, len, stdout)); return CAIRO_STATUS_SUCCESS;}}void cdiagram::export_pdf(const char *filename, crouter *cr, point page_size, point margin, double scale, bool multipage){ cr->set_ccss_media("print"); cairo_surface_t *crs = cairo_pdf_surface_create_for_stream(cairo_surface_ignore_write, 0, 612, 792); cairo_t *cairo = cairo_create(crs); PangoLayout *pl = pango_cairo_create_layout(cairo); unsigned generation = dcontext::step_generation(); cdiagram *cd = new cdiagram(cr, pl, generation); g_object_unref(G_OBJECT(pl)); cairo_destroy(cairo); cairo_surface_destroy(crs); cd->export_pdf(filename, false, cr, generation, page_size, margin, scale, multipage); delete cd;}void cdiagram::export_pdf(const char *filename, bool eps, crouter *cr, unsigned generation, point page_size, point margin, double scale, bool multipage){ if (eps || !page_size) page_size = point(width() / scale + 2 * margin.x(), height() / scale + 2 * margin.y()); cairo_surface_t *crs; if (eps) { crs = cairo_ps_surface_create(filename, page_size.x(), page_size.y());#if CAIRO_VERSION_MINOR >= 6 || (CAIRO_VERSION_MINOR == 5 && CAIRO_VERSION_MICRO >= 2) cairo_ps_surface_set_eps(crs, TRUE);#endif } else if (!filename || strcmp(filename, "") == 0 || strcmp(filename, "-") == 0) crs = cairo_pdf_surface_create_for_stream(cairo_surface_stdout_write, 0, page_size.x(), page_size.y()); else crs = cairo_pdf_surface_create(filename, page_size.x(), page_size.y()); cairo_t *cairo = cairo_create(crs); dcontext dcx(cr, pango_cairo_create_layout(cairo), cairo, generation, 1 /* position precisely */, 1); cr->set_ccss_media("print"); point visible_area = point(page_size.x() - 2 * margin.x(), page_size.y() - 2 * margin.y()); for (int jj = 0; scale * jj * visible_area.y() < height(); ++jj) for (int ii = 0; scale * ii * visible_area.x() < width(); ++ii) { cairo_save(cairo); cairo_translate(cairo, -x() - ii * visible_area.x() + margin.x(), -y() - jj * visible_area.y() + margin.y()); cairo_rectangle(cairo, x() + ii * visible_area.x() - 5, y() + jj * visible_area.y() - 5, visible_area.x() + 10, visible_area.y() + 10); cairo_scale(cairo, 1./scale, 1./scale); cairo_clip(cairo); rectangle rect(-x() + scale * ii * visible_area.x() - scale * 5, -y() + scale * jj * visible_area.y() - scale * 5, scale * visible_area.x() + scale * 10, scale * visible_area.y() + scale * 10); std::vector<dwidget *> elts; find_rect_elts(rect, elts); for (std::vector<dwidget *>::iterator eltsi = elts.begin(); eltsi != elts.end(); ++eltsi) (*eltsi)->draw(dcx); cairo_restore(cairo); if (multipage) cairo_show_page(cairo); } cr->set_ccss_media("screen"); g_object_unref(G_OBJECT(dcx.pl)); cairo_destroy(dcx.cairo); cairo_surface_destroy(crs);}wdiagram::wdiagram(wmain *rw) : _rw(rw), _cdiagram(0), _generation(dcontext::step_generation()), _scale_step(0), _scale(1), _penumbra(2), _origin_x(0), _origin_y(0), _drag_state(drag_none){ _widget = lookup_widget(_rw->_window, "diagram"); gtk_widget_realize(_widget); gtk_widget_add_events(_widget, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_LEAVE_NOTIFY_MASK); GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(_widget->parent); _horiz_adjust = gtk_scrolled_window_get_hadjustment(sw); _vert_adjust = gtk_scrolled_window_get_vadjustment(sw);#if 0 PangoFontMap *fm = pango_cairo_font_map_get_default(); PangoFontFamily **fms; int nfms; pango_font_map_list_families(fm, &fms, &nfms); for (int i = 0; i < nfms; i++) fprintf(stderr, " %s\n", pango_font_family_get_name(fms[i])); g_free(fms);#endif g_signal_connect(G_OBJECT(_widget), "event", G_CALLBACK(on_diagram_event), this); g_signal_connect(G_OBJECT(_widget), "expose-event", G_CALLBACK(diagram_expose), this); g_signal_connect(G_OBJECT(_widget), "map", G_CALLBACK(diagram_map), this); g_signal_connect(G_OBJECT(_widget), "size-allocate", G_CALLBACK(on_diagram_size_allocate), this); for (int i = 0; i < 3; i++) _highlight[i].clear(); static_assert((int) ncursors > (int) deg_corner_lrt && (int) c_element == (int) deg_element); for (int i = 0; i < ncursors; i++) _cursor[i] = 0; _last_cursorno = c_main;}wdiagram::~wdiagram(){ delete _cdiagram; for (int i = c_main; i < ncursors; i++) if (_cursor[i]) gdk_cursor_unref(_cursor[i]);}void wdiagram::initialize(){ if (!_cursor[c_main]) { _cursor[c_main] = _rw->_normal_cursor; _cursor[deg_element] = gdk_cursor_new(GDK_HAND1); _cursor[deg_corner_ulft] = gdk_cursor_new(GDK_TOP_LEFT_CORNER); _cursor[deg_border_top] = gdk_cursor_new(GDK_TOP_SIDE); _cursor[deg_corner_urt] = gdk_cursor_new(GDK_TOP_RIGHT_CORNER); _cursor[deg_border_rt] = gdk_cursor_new(GDK_RIGHT_SIDE); _cursor[deg_corner_lrt] = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); _cursor[deg_border_bot] = gdk_cursor_new(GDK_BOTTOM_SIDE); _cursor[deg_corner_llft] = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER); _cursor[deg_border_lft] = gdk_cursor_new(GDK_LEFT_SIDE); _cursor[c_hand] = gdk_cursor_new(GDK_FLEUR); for (int i = c_main; i < ncursors; i++) gdk_cursor_ref(_cursor[i]); }}void wdiagram::on_ccss_changed(){ _generation = dcontext::step_generation();}void wdiagram::element_show(const String &ename, bool scroll_to){ if (_cdiagram) if (delt *e = _cdiagram->elt(ename)) { while (!e->root() && !e->visible()) e = e->parent(); if (!e->root() && (!e->highlighted(dhlt_click) || scroll_to)) highlight(e, dhlt_click, scroll_to, true); }}void wdiagram::scroll_recenter(point old_ctr){ if (!_cdiagram) return; if (old_ctr.x() < -1000000) old_ctr = scroll_center(); gtk_layout_set_size(GTK_LAYOUT(_widget), MAX((gint) (_cdiagram->width() * scale() + 0.5), _widget->allocation.width), MAX((gint) (_cdiagram->height() * scale() + 0.5), _widget->allocation.height)); GtkAdjustment *ha = _horiz_adjust; double scaled_width = ha->page_size / scale(); if (scaled_width >= _cdiagram->width()) { _origin_x = (int) ((_cdiagram->center_x() - scaled_width / 2) * scale() + 0.5); gtk_adjustment_set_value(ha, 0); } else { _origin_x = (int) (_cdiagram->x() * scale() + 0.5); if (old_ctr.x() - scaled_width / 2 < _cdiagram->x()) gtk_adjustment_set_value(ha, 0); else if (old_ctr.x() + scaled_width / 2 > _cdiagram->x2()) gtk_adjustment_set_value(ha, _cdiagram->width() * scale() - ha->page_size); else gtk_adjustment_set_value(ha, (old_ctr.x() - scaled_width / 2) * scale() - _origin_x); } GtkAdjustment *va = _vert_adjust; double scaled_height = va->page_size / scale(); if (scaled_height >= _cdiagram->height()) { _origin_y = (int) ((_cdiagram->center_y() - scaled_height / 2) * scale() + 0.5); gtk_adjustment_set_value(va, 0); } else { _origin_y = (int) (_cdiagram->y() * scale() + 0.5); if (old_ctr.y() - scaled_height / 2 < _cdiagram->y()) gtk_adjustment_set_value(va, 0); else if (old_ctr.y() + scaled_height / 2 > _cdiagram->y2()) gtk_adjustment_set_value(va, _cdiagram->height() * scale() - va->page_size); else gtk_adjustment_set_value(va, (old_ctr.y() - scaled_height / 2) * scale() - _origin_y); } redraw();}void wdiagram::zoom(bool incremental, int amount){ if (!incremental && amount <= -10000 && _cdiagram) { // best fit // window_width / 3**(scale_step/2) <= contents_width // && window_height / 3**(scale_step/2) <= contents_height double ssw = 3 * log2(_horiz_adjust->page_size / _cdiagram->width()); double ssh = 3 * log2(_vert_adjust->page_size / _cdiagram->height()); _scale_step = (int) floor(std::min(ssw, ssh)); } else _scale_step = (incremental ? _scale_step + amount : amount); double new_scale = pow(2.0, _scale_step / 3.0); if (_cdiagram) { point old_ctr = scroll_center(); _scale = new_scale; _penumbra = 2; scroll_recenter(old_ctr); } else _scale = new_scale;}void wdiagram::router_create(bool incremental, bool always){ if (!incremental) { for (int i = 0; i < 3; ++i) highlight(0, i); delete _cdiagram; _cdiagram = 0; } // don't bother creating if widget not mapped if (!always && !GTK_WIDGET_VISIBLE(_widget)) return; if (!_cursor[0]) initialize(); if (!_cdiagram) { PangoLayout *pl = gtk_widget_create_pango_layout(_widget, NULL); _cdiagram = new cdiagram(_rw, pl, _generation); g_object_unref(G_OBJECT(pl)); scroll_recenter(point(0, 0)); } if (handler_value *hv = _rw->hvalues().find_placeholder("active_ports", hflag_r | hflag_notify_delt)) hv->refresh(_rw, true); if (!incremental) redraw();}/***** * * Layout * */void wdiagram::on_expose(const GdkRectangle *area){ if (!_cdiagram) router_create(true, true); cairo_t *cr = gdk_cairo_create(GTK_LAYOUT(_widget)->bin_window); cairo_rectangle(cr, area->x, area->y, area->width, area->height); cairo_clip(cr); // background cairo_rectangle(cr, area->x, area->y, area->width, area->height); //const GdkColor &bgcolor = _widget->style->bg[GTK_STATE_NORMAL]; //cairo_set_source_rgb(cr, bgcolor.red / 65535., bgcolor.green / 65535., bgcolor.blue / 65535.); cairo_set_source_rgb(cr, 1, 1, 1); cairo_fill(cr); // highlight rectangle if (_drag_state == drag_rect_dragging) { cairo_set_line_width(cr, 2); const GdkColor &bgcolor = _widget->style->bg[GTK_STATE_ACTIVE]; rectangle r = canvas_to_window(_dragr).normalize(); if (r.width() > 4 && r.height() > 4) { cairo_set_source_rgb(cr, bgcolor.red / 65535., bgcolor.green / 65535., bgcolor.blue / 65535.); cairo_rectangle(cr, r.x() + 2, r.y() + 2, r.width() - 4, r.height() - 4); cairo_fill(cr); } cairo_set_source_rgb(cr, bgcolor.red / 80000., bgcolor.green / 80000., bgcolor.blue / 80000.); if (r.width() <= 4 || r.height() <= 4) { cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill(cr); } else { cairo_rectangle(cr, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2); cairo_stroke(cr); } } cairo_translate(cr, -_origin_x, -_origin_y); cairo_scale(cr, scale(), scale()); dcontext dcx(main(), gtk_widget_create_pango_layout(_widget, NULL), cr, _generation, _scale_step, _scale); rectangle r(area->x + _origin_x, area->y + _origin_y, area->width, area->height); r.scale(1 / scale()); r.expand(_penumbra); std::vector<dwidget *> elts; _cdiagram->find_rect_elts(r, elts); for (std::vector<dwidget *>::iterator eltsi = elts.begin(); eltsi != elts.end(); ++eltsi) (*eltsi)->draw(dcx); g_object_unref(G_OBJECT(dcx.pl)); _penumbra = std::max(_penumbra, dcx.penumbra); cairo_destroy(cr);}extern "C" {static gboolean diagram_expose(GtkWidget *, GdkEventExpose *e, gpointer user_data){ wdiagram *cd = reinterpret_cast<wdiagram *>(user_data); cd->on_expose(&e->area); return FALSE;}static void diagram_map(GtkWidget *, gpointer user_data){ reinterpret_cast<wdiagram *>(user_data)->router_create(true, true);}static void on_diagram_size_allocate(GtkWidget *, GtkAllocation *, gpointer user_data){ wdiagram *cd = reinterpret_cast<wdiagram *>(user_data); cd->scroll_recenter(point(-1000001, -1000001));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?