23#include <gtkmm/layoutmanager.h>
24#include <gtkmm/binlayout.h>
25#include <glibmm/fileutils.h>
26#include <glibmm/i18n.h>
27#include <glibmm/main.h>
28#include <gtkmm/button.h>
29#include <gtkmm/checkbutton.h>
30#include <gtkmm/flowbox.h>
31#include <gtkmm/grid.h>
32#include <gtkmm/image.h>
33#include <gtkmm/label.h>
34#include <gtkmm/menubutton.h>
35#include <gtkmm/picture.h>
36#include <gtkmm/spinbutton.h>
37#include <gtkmm/togglebutton.h>
38#include <gtkmm/window.h>
52#define noTIMING_INFO 1;
65 width *= device_scale;
72 cairo_set_line_width(ctx, 1.0 * device_scale);
75 cairo_surface_set_device_scale(
surface, device_scale, device_scale);
86 return value ? value :
"";
91 return strtod(val.c_str(),
nullptr);
95 Glib::ObjectBase{
"MarkerComboBox"},
98 _combo_id(
std::move(id)),
105 _link_scale(
get_widget<
Gtk::Button>(_builder,
"link-scale")),
108 _scale_with_stroke(
get_widget<
Gtk::CheckButton>(_builder,
"scale-with-stroke")),
109 _menu_btn(
get_widget<
Gtk::MenuButton>(_builder,
"menu-btn")),
114 _orient_auto_rev(
get_widget<
Gtk::ToggleButton>(_builder,
"orient-auto-rev")),
115 _orient_auto(
get_widget<
Gtk::ToggleButton>(_builder,
"orient-auto")),
116 _orient_angle(
get_widget<
Gtk::ToggleButton>(_builder,
"orient-angle")),
117 _orient_flip_horz(
get_widget<
Gtk::Button>(_builder,
"btn-horz-flip")),
118 _current_img(
get_widget<
Gtk::Picture>(_builder,
"current-img")),
119 _edit_marker(
get_widget<
Gtk::Button>(_builder,
"edit-marker"))
123 _current_img.set_layout_manager(Gtk::BinLayout::create());
129 auto device_scale = get_scale_factor();
143 lm->resized.connect([
this] {
151 image->set_content_fit(Gtk::ContentFit::SCALE_DOWN);
152 image->set_layout_manager(Gtk::BinLayout::create());
153 image->set_visible(
true);
154 auto const box = Gtk::make_managed<Gtk::FlowBoxChild>();
155 box->set_child(*
image);
156 if (
item->separator) {
157 image->set_sensitive(
false);
158 image->set_focusable(
false);
159 image->set_size_request(-1, 10);
160 box->set_sensitive(
false);
161 box->set_focusable(
false);
162 box->add_css_class(
"marker-separator");
166 box->add_css_class(
"marker-item-box");
169 box->set_size_request(
item->width,
item->height);
172 box->set_focusable(
false);
180 _marker_list.signal_selected_children_changed().connect([
this](){
187 _marker_list.signal_child_activated().connect([
this](Gtk::FlowBoxChild* box){
191 auto set_orient = [
this](
bool enable_angle,
const char* value) {
196 _orient_auto_rev.signal_toggled().connect([=](){ set_orient(
false,
"auto-start-reverse"); });
197 _orient_auto.signal_toggled().connect([=]() { set_orient(
false,
"auto"); });
201 _angle_btn.signal_value_changed().connect([
this]() {
206 auto set_scale = [
this](
bool changeWidth) {
233 auto idle_set_scale = [=,
this](
bool changeWidth) {
237 _idle = Glib::signal_idle().connect([=,
this](){
239 if (marker == orig_marker) {
240 set_scale(changeWidth);
255 _scale_x.signal_value_changed().connect([=]() { idle_set_scale(
true); });
256 _scale_y.signal_value_changed().connect([=]() { idle_set_scale(
false); });
263 auto set_offset = [
this](){
267 _offset_x.signal_value_changed().connect([=]() { set_offset(); });
268 _offset_y.signal_value_changed().connect([=]() { set_offset(); });
287 auto units =
get_attrib(marker,
"markerUnits");
289 auto aspect =
get_attrib(marker,
"preserveAspectRatio");
298 _angle_btn.set_value(strtod(orient.c_str(),
nullptr));
299 if (orient ==
"auto-start-reverse") {
303 else if (orient ==
"auto") {
325 Cairo::RefPtr<Cairo::Surface>
surface;
336 drawing.
setRoot(
_sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY));
338 auto alloc =
_preview.get_allocation();
347 _sandbox->getRoot()->invoke_hide(visionkey);
352 std::ostringstream ost;
353 ost <<
"<small>" <<
label.raw() <<
"</small>";
371 if (!document)
return nullptr;
374 if (!defs)
return nullptr;
377 if (is<SPMarker>(&
child)) {
378 auto marker = cast<SPMarker>(&
child);
379 auto id = marker->getId();
380 if (
id && marker_id ==
id) {
397 bool selected =
false;
400 if (
auto box =
dynamic_cast<Gtk::FlowBoxChild*
>(&widget)) {
402 if (*marker == *item) {
403 _marker_list.select_child(*box);
419 if (marker !=
nullptr) {
425 Glib::RefPtr<MarkerItem> marker_item;
439 auto empty = Glib::RefPtr<MarkerItem>();
441 if (sel.size() == 1) {
503 item->history =
false;
504 item->separator =
true;
506 item->
label = filler ?
"filler" :
"Separator";
509 auto device_scale = get_scale_factor();
511 item->pix = separator;
529 auto markers_source = get_path_string(SYSTEM, MARKERS,
"markers.svg");
546 auto sp_marker = cast<SPMarker>(marker);
556 auto id = marker ? marker->
getId() :
nullptr;
578 return std::string();
584 bool stockid =
item->stock;
586 std::string markurn = stockid ?
"urn:inkscape:marker:" +
item->
id :
item->
id;
587 auto mark = cast<SPMarker>(
get_stock_item(markurn.c_str(), stockid));
593 std::ostringstream ost;
594 ost <<
"url(#" <<
id <<
")";
598 mark->getRepr()->setAttribute(
"inkscape:collect",
"always");
642 for (
int i = 0; i < fillup; ++i) {
645 for (
int i = 0; i < max; ++i) {
667 std::vector<SPMarker *> ml;
668 if (source ==
nullptr)
return ml;
676 if (is<SPMarker>(&
child)) {
677 auto marker = cast<SPMarker>(&
child);
678 ml.push_back(marker);
705 drawing.
setRoot(
_sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY));
711 item->history =
true;
712 item->separator =
false;
722auto old_time = std::chrono::high_resolution_clock::now();
725 for (
auto i:marker_list) {
734 item->source = source;
740 item->stock = !history;
741 item->history = history;
756auto current_time = std::chrono::high_resolution_clock::now();
757auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - old_time);
758g_warning(
"%s render time for %d markers: %d ms", combo_id, (
int)marker_list.size(),
static_cast<int>(elapsed.count()));
767Cairo::RefPtr<Cairo::Surface>
771 std::optional<guint32> checkerboard_color;
776 int device_scale = get_scale_factor();
777 auto const fg = get_color();
779 drawing, checkerboard_color, no_clip,
scale, device_scale);
785 if (
auto wnd =
dynamic_cast<Gtk::Window*
>(this->get_root())) {
788 gint32(0xff * color.get_red()) << 24 |
789 gint32(0xff * color.get_green()) << 16 |
790 gint32(0xff * color.get_blue()) << 8 |
794 auto const color = get_color();
796 gint32(0xff * color.get_red()) << 24 |
797 gint32(0xff * color.get_green()) << 16 |
798 gint32(0xff * color.get_blue()) << 8 |
Cairo::RefPtr< Cairo::ImageSurface > surface
Two-dimensional point with integer coordinates.
void setRoot(DrawingItem *root)
Interface for refcounted XML nodes.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
Cairo::RefPtr< Cairo::ImageSurface > render_surface(double scale)
Typed SVG document implementation.
SPDefs * getDefs()
Return the main defs object for the document.
static std::unique_ptr< SPDocument > createNewDoc(char const *filename, bool keepalive, bool make_new=false, SPDocument *parent=nullptr)
Fetches document from filename, or creates new, if NULL; public document appears in document list.
void invoke_hide(unsigned int key)
static unsigned int display_key_new(unsigned numkeys)
Allocates unique integer keys.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
char const * label() const
Gets the author-visible label property for the object or a default if no label is defined.
char const * getId() const
Returns the objects current ID string.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
char const * getAttribute(char const *name) const
sigc::connection connectModified(sigc::slot< void(SPObject *, unsigned int)> slot)
Connects to the modification notification signal.
static Glib::RefPtr< SizeReporter > create()
struct _cairo_surface cairo_surface_t
std::unique_ptr< Magick::Image > image
static constexpr int ITEM_HEIGHT
static constexpr int ITEM_WIDTH
Combobox for selecting dash patterns - implementation.
std::string get_filename(Type type, char const *filename, bool localized, bool silent)
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
Gtk::Widget * for_each_child(Gtk::Widget &widget, Func &&func, bool const plus_self=false, bool const recurse=false, int const level=0)
Call Func with a reference to each child of parent, until it returns _break.
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
SPDocument * cache_static_doc(F &&f)
Wrapper for a static SPDocument to ensure it is destroyed early enough.
std::unique_ptr< SPDocument > ink_markers_preview_doc(const Glib::ustring &group_id)
Returns a new document containing default start, mid, and end markers.
Cairo::RefPtr< Cairo::Surface > create_marker_image(const Glib::ustring &group_id, SPDocument *_sandbox, Gdk::RGBA marker_color, Geom::IntPoint pixel_size, const char *mname, SPDocument *source, Inkscape::Drawing &drawing, std::optional< guint32 > checkerboard, bool no_clip, double scale, int device_scale)
Creates a copy of the marker named mname, determines its visible and renderable area in the bounding ...
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
Inkscape::IO::Resource - simple resource API.
void sp_marker_set_orient(SPMarker *marker, const char *value)
void sp_marker_scale_with_stroke(SPMarker *marker, bool scale_with_stroke)
void sp_validate_marker(SPMarker *sp_marker, SPDocument *doc)
void sp_marker_set_offset(SPMarker *marker, double dx, double dy)
void sp_marker_set_uniform_scale(SPMarker *marker, bool uniform)
void sp_marker_set_size(SPMarker *marker, double sx, double sy)
void sp_marker_flip_horizontally(SPMarker *marker)
SPRoot: SVG <svg> implementation.
SPObject * get_stock_item(gchar const *urn, bool stock, SPDocument *stock_doc)
TODO: insert short description here.
void cairo_set_source_rgba(cairo_t *cr, colour c)
Glib::RefPtr< Gdk::Texture > to_texture(Cairo::RefPtr< Cairo::Surface > const &surface)
Convert an image surface in ARGB32 format to a texture.
Gdk::RGBA get_color_with_class(Gtk::Widget &widget, Glib::ustring const &css_class)