16#include <glibmm/ustring.h>
17#include <gtkmm/stringobject.h>
22#include <glibmm/i18n.h>
23#include <glibmm/convert.h>
24#include <glibmm/regex.h>
25#include <giomm/file.h>
27#include <gtkmm/popover.h>
28#include <gtkmm/filedialog.h>
29#include <gtkmm/scale.h>
30#include <sigc++/functors/mem_fun.h>
60 set_orientation(Gtk::Orientation::VERTICAL);
61 set_column_spacing(12);
77 Glib::ustring
const &
label,
79 Glib::ustring
const &suffix,
80 const Glib::ustring &tip,
82 Gtk::Widget *other_widget)
85 widget.set_tooltip_text(tip);
87 auto const hb = Gtk::make_managed<Gtk::Box>();
89 hb->set_hexpand(
true);
91 hb->set_valign(Gtk::Align::CENTER);
95 auto const label_widget = Gtk::make_managed<Gtk::Label>(
label, Gtk::Align::START,
96 Gtk::Align::CENTER,
true);
97 label_widget->set_mnemonic_widget(widget);
98 label_widget->set_markup(label_widget->get_text());
101 label_widget->set_margin_start(12);
104 label_widget->set_valign(Gtk::Align::CENTER);
105 attach_next_to(*label_widget, Gtk::PositionType::BOTTOM);
107 attach_next_to(*hb, *label_widget, Gtk::PositionType::RIGHT, 1, 1);
110 hb->set_margin_start(12);
113 attach_next_to(*hb, Gtk::PositionType::BOTTOM, 2, 1);
117 if (!suffix.empty()) {
118 auto const suffix_widget = Gtk::make_managed<Gtk::Label>(suffix, Gtk::Align::START, Gtk::Align::CENTER,
true);
119 suffix_widget->set_markup(suffix_widget->get_text());
130 if (
name.empty())
return;
132 auto const label_widget = Gtk::make_managed<Gtk::Label>(Glib::ustring(
"<b>").
append(
name).
append(
"</b>"),
133 Gtk::Align::START, Gtk::Align::CENTER,
true);
135 label_widget->set_use_markup(
true);
136 label_widget->set_valign(Gtk::Align::CENTER);
137 attach_next_to(*label_widget, Gtk::PositionType::BOTTOM, columns, 1);
142 if (
name.empty())
return;
144 auto const label_widget = Gtk::make_managed<Gtk::Label>(Glib::ustring(
"<i>").
append(
name).
append(
"</i>"),
145 Gtk::Align::START , Gtk::Align::CENTER,
true);
146 label_widget->set_use_markup(
true);
147 label_widget->set_valign(Gtk::Align::CENTER);
148 label_widget->set_wrap(
true);
149 label_widget->set_wrap_mode(Pango::WrapMode::WORD);
150 attach_next_to(*label_widget, Gtk::PositionType::BOTTOM, 2, 1);
155 widget.set_tooltip_text (tip);
164 this->set_label(
label);
170 if (this->get_visible())
179 Glib::ustring
const &string_value,
bool default_value,
PrefRadioButton* group_member)
185 this->set_label(
label);
189 this->set_group(*group_member);
197 this->set_active(
false );
206 this->set_label(
label);
210 this->set_group(*group_member);
224 if (this->get_visible() && this->get_active() )
238 for (
auto&&
item : buttons) {
239 auto* btn = Gtk::make_managed<PrefRadioButton>();
241 btn->set_tooltip_text(
item.tooltip);
243 if (!group) group = btn;
248 double lower,
double upper,
double step_increment,
double ,
249 double default_value,
bool is_int,
bool is_percent)
266 this->set_range (lower, upper);
267 this->set_increments (step_increment, 0);
268 this->set_value (value);
269 this->set_width_chars(6);
272 else if (step_increment < 0.1)
283 if (this->get_visible())
299 double lower,
double upper,
double step_increment,
300 double default_value, UnitType unit_type, Glib::ustring
const &default_unit)
303 _is_percent = (unit_type == UNIT_TYPE_DIMENSIONLESS);
309 if (step_increment < 0.1) {
318 if (unitstr.length() == 0) {
319 unitstr = default_unit;
361 PangoLayout* layout = pango_cairo_create_layout (cr);
362 pango_layout_set_text(layout, txt, -1);
365 std::ostringstream sizestr;
367 fontdesc = fontdesc +
" " + sizestr.str();
369 pango_layout_set_font_description(layout, font_desc);
370 pango_font_description_free (font_desc);
372 PangoRectangle logical_extent;
373 pango_layout_get_pixel_extents(layout,
nullptr, &logical_extent);
375 pango_cairo_show_layout(cr, layout);
380 std::ostringstream number;
382 draw_text(cr, pos, number.str().c_str(),
true);
391 double const dist,
int const major_interval)
394 const double zoomcorr = prefs->
getDouble(
"/options/zoomcorrection/value", 1.0);
397 double step = dist * zoomcorr /
_unitconv;
398 bool draw_minor =
true;
409 if ((i % major_interval) == 0) {
411 if (
static_cast<int>(mark) > last_pos) {
413 cr->line_to(mark, 0);
417 last_pos =
static_cast<int>(mark) + 1;
419 }
else if (draw_minor) {
434 auto const fg = get_color();
435 cr->set_line_width(1);
436 cr->set_source_rgb(fg.get_red(), fg.get_green(), fg.get_blue());
443 Glib::ustring abbr = prefs->
getString(
"/options/zoomcorrection/unit");
446 }
else if (abbr ==
"in") {
448 }
else if (abbr ==
"mm") {
450 }
else if (abbr ==
"pc") {
452 }
else if (abbr ==
"pt") {
454 }
else if (abbr ==
"px") {
465 if (this->get_visible() ||
freeze)
469 prefs->
setDouble(
"/options/zoomcorrection/value",
_slider->get_value() / 100.0);
479 if (this->get_visible() ||
freeze)
483 prefs->
setDouble(
"/options/zoomcorrection/value",
_sb->get_value() / 100.0);
492 if (!
_unit.get_sensitive()) {
501 if (
_ruler.get_visible()) {
508 return _sb->mnemonic_activate ( group_cycling );
513 double step_increment,
double page_increment,
double default_value)
516 double value = prefs->
getDoubleLimited(
"/options/zoomcorrection/value", default_value, lower, upper) * 100.0;
522 _slider = Gtk::make_managed<Gtk::Scale>(Gtk::Orientation::HORIZONTAL);
525 _slider->set_range (lower, upper);
526 _slider->set_increments (step_increment, page_increment);
531 _sb = Gtk::make_managed<Inkscape::UI::Widget::SpinButton>();
535 _sb->set_range (lower, upper);
536 _sb->set_increments (step_increment, 0);
537 _sb->set_value (value);
539 _sb->set_max_width_chars(5);
540 _sb->set_halign(Gtk::Align::CENTER);
541 _sb->set_valign(Gtk::Align::END);
543 _unit.set_sensitive(
false);
545 _unit.set_sensitive(
true);
547 _unit.set_halign(Gtk::Align::CENTER);
548 _unit.set_valign(Gtk::Align::END);
552 auto const table = Gtk::make_managed<Gtk::Grid>();
553 table->attach(*
_slider, 0, 0, 1, 1);
554 table->attach(*
_sb, 1, 0, 1, 1);
555 table->attach(
_ruler, 0, 1, 1, 1);
556 table->attach(
_unit, 1, 1, 1, 1);
564 if (this->get_visible() ||
freeze)
577 if (this->get_visible() ||
freeze)
591 return _sb ?
_sb->mnemonic_activate ( group_cycling ) :
false;
595 double lower,
double upper,
double step_increment,
double page_increment,
double default_value,
int digits)
604 _slider = Gtk::make_managed<Gtk::Scale>(Gtk::Orientation::HORIZONTAL);
606 _slider->set_range (lower, upper);
607 _slider->set_increments (step_increment, page_increment);
612 _sb = Gtk::make_managed<Inkscape::UI::Widget::SpinButton>();
614 _sb->set_range (lower, upper);
615 _sb->set_increments (step_increment, 0);
616 _sb->set_value (value);
617 _sb->set_digits(digits);
618 _sb->set_halign(Gtk::Align::CENTER);
619 _sb->set_valign(Gtk::Align::CENTER);
622 auto const table = Gtk::make_managed<Gtk::Grid>();
624 table->attach(*
_slider, 0, 0, 1, 1);
625 if (
_sb) table->attach(*
_sb, 1, 0, 1, 1);
631 std::span<Glib::ustring const> labels,
632 std::span<int const> values,
633 int const default_value)
635 int const labels_size = labels.size();
636 int const values_size = values.size();
637 if (values_size != labels_size) {
638 std::cerr <<
"PrefCombo::"
639 <<
"Different number of values/labels in " <<
prefs_path.raw() << std::endl;
646 int value = prefs->getInt(
_prefs_path, default_value);
648 for (
int i = 0; i < labels_size; ++i) {
651 if (value == values[i]) {
656 property_selected().signal_changed().connect([
this](){
on_changed(); });
660 std::span<Glib::ustring const> labels,
661 std::span<Glib::ustring const> values,
662 Glib::ustring
const &default_value)
664 int const labels_size = labels.size();
665 int const values_size = values.size();
666 if (values_size != labels_size) {
667 std::cerr <<
"PrefCombo::"
668 <<
"Different number of values/labels in " <<
prefs_path.raw() << std::endl;
675 Glib::ustring value = prefs->getString(
_prefs_path);
677 value = default_value;
680 for (
int i = 0; i < labels_size; ++i) {
683 if (value == values[i]) {
688 property_selected().signal_changed().connect([
this](){
on_changed(); });
693 if (!get_visible())
return;
696 auto row = get_selected();
706 bool visibility, Glib::ustring
const &default_string)
726 if (this->get_visible())
735 if (this->get_visible())
745 return relatedEntry->mnemonic_activate ( group_cycling );
760 auto const pixlabel = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 3);
761 auto const im =
sp_get_icon_image(
"applications-graphics", Gtk::IconSize::NORMAL);
763 auto const l = Gtk::make_managed<Gtk::Label>();
764 l->set_markup_with_mnemonic(_(
"_Browse..."));
779 if (this->get_visible()) {
787 if (this->get_visible()) {
790 static std::string current_folder;
797 auto filter_app = Gtk::FileFilter::create();
798 filter_app->set_name(_(
"Applications"));
799 filter_app->add_mime_type(
"application/x-executable");
800 filter_app->add_mime_type(
"application/x-pie-executable");
801 filter_app->add_mime_type(
"application/x-mach-binary");
802 filter_app->add_mime_type(
"application/vnd.microsoft.portable-executable");
803 filter_app->add_suffix(
"exe");
804 filters->append(filter_app);
807 auto filter_all = Gtk::FileFilter::create();
808 filter_all->set_name(_(
"All Files"));
809 filter_all->add_pattern(
"*");
810 filters->append(filter_all);
815 auto file =
choose_file_open(_(
"Select an editor"), window, filters, current_folder, _(
"Select"));
829 return relatedEntry->mnemonic_activate ( group_cycling );
836 auto const pixlabel = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 3);
839 auto const l = Gtk::make_managed<Gtk::Label>();
840 l->set_markup_with_mnemonic(_(
"Open"));
853 g_mkdir_with_parents(
relatedEntry->get_text().c_str(), 0700);
864 warningPopup = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 3);
871 popover = Gtk::make_managed<Gtk::Popover>();
880 resetButton->set_tooltip_text(_(
"Reset to default directory"));
887 openButton = Gtk::make_managed<Gtk::Button>();
890 openButton->set_tooltip_text(_(
"Open directory"));
897 relatedPathBox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 0);
902 auto const selectl = Gtk::make_managed<Gtk::Label>();
903 selectl->set_markup_with_mnemonic(_(
"..."));
905 selectButton->set_tooltip_text(_(
"Select a new directory"));
918 relatedEntry->signal_icon_press().connect([&](Gtk::Entry::IconPosition) {
933 static std::string current_folder;
937 auto dialog = Gtk::FileDialog::create();
938 dialog->set_initial_folder(Gio::File::create_for_path(current_folder));
939 dialog->select_folder(
dynamic_cast<Gtk::Window &
>(*get_root()), sigc::track_object([&dialog = *dialog,
this] (
auto &
result) {
941 if (
auto folder = dialog.select_folder_finish(
result)) {
943 setFolderPath(folder);
946 }
catch (Gtk::DialogError
const& e) {
947 if (e.code() == Gtk::DialogError::Code::FAILED) {
948 std::cerr <<
"PrefEditFolder::onChangeButtonClickedCallback: "
949 <<
"Gtk::FileDialog returned " << e.what() << std::endl;
957 Glib::ustring folder_path = folder->get_parse_name();
984 checkPathValidityResults(info);
992 if (fileInfo->get_file_type() == Gio::FileType::DIRECTORY) {
1003 relatedEntry->unset_icon(Gtk::Entry::IconPosition::SECONDARY);
1006 relatedEntry->set_icon_sensitive(Gtk::Entry::IconPosition::SECONDARY,
false);
1012 relatedEntry->set_icon_from_icon_name(
"dialog-warning", Gtk::Entry::IconPosition::SECONDARY);
1014 relatedEntry->set_icon_tooltip_markup(_(
"This is a file. Please select a directory."), Gtk::Entry::IconPosition::SECONDARY);
1015 relatedEntry->set_icon_sensitive(Gtk::Entry::IconPosition::SECONDARY,
true);
1021 relatedEntry->set_icon_from_icon_name(
"dialog-warning", Gtk::Entry::IconPosition::SECONDARY);
1023 relatedEntry->set_icon_sensitive(Gtk::Entry::IconPosition::SECONDARY,
true);
1024 relatedEntry->set_icon_tooltip_markup(_(
"This directory does not exist."), Gtk::Entry::IconPosition::SECONDARY);
1030 std::cerr <<
"PrefEditFolder::checkPathValidityResults: "
1031 <<
"Invalid fileis value!" << std::endl;
1043 g_mkdir_with_parents(
relatedEntry->get_text().c_str(), 0700);
1053 this->set_invisible_char(
'*');
1054 this->set_visibility(visibility);
1060 if (this->get_visible())
1069 if (this->get_visible())
1080 set_size_request(100,
height);
1081 set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
1082 set_has_frame(
true);
1089 value = Glib::Regex::create(
"\\|")->replace_literal(value, 0,
"\n", (Glib::Regex::MatchFlags)0);
1090 _text.get_buffer()->set_text(value);
1099 Glib::ustring value =
_text.get_buffer()->get_text();
1100 value = Glib::Regex::create(
"\\n")->replace_literal(value, 0,
"|", (Glib::Regex::MatchFlags)0);
1116 if (this->get_visible()) {
1132 if (this->get_visible())
_PangoFontDescription PangoFontDescription
struct _PangoLayout PangoLayout
Two-dimensional point that doubles as a vector.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
void setDoubleUnit(Glib::ustring const &pref_path, double value, Glib::ustring const &unit_abbr)
Set a floating point value with unit.
Glib::ustring getUnit(Glib::ustring const &pref_path)
Retrieve the unit string.
double getDouble(Glib::ustring const &pref_path, double def=0.0, Glib::ustring const &unit="")
Retrieve a floating point value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
Colors::Color getColor(Glib::ustring const &pref_path, std::string const &def="black")
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
void setColor(Glib::ustring const &pref_path, Colors::Color const &color)
Set an RGBA color value.
void setString(Glib::ustring const &pref_path, Glib::ustring const &value)
Set an UTF-8 string value.
void setDouble(Glib::ustring const &pref_path, double value)
Set a floating point value.
void setInt(Glib::ustring const &pref_path, int value)
Set an integer value.
int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX)
Retrieve a limited integer.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
double getDoubleLimited(Glib::ustring const &pref_path, double def=0.0, double min=DBL_MIN, double max=DBL_MAX, Glib::ustring const &unit="")
Retrieve a limited floating point value.
void add_group_note(Glib::ustring name)
void add_group_header(Glib::ustring name, int columns=1)
void add_line(bool indent, Glib::ustring const &label, Gtk::Widget &widget, Glib::ustring const &suffix, Glib::ustring const &tip, bool expand=true, Gtk::Widget *other_widget=nullptr)
Add a widget to the bottom row of the dialog page.
void set_tip(Gtk::Widget &widget, Glib::ustring const &tip)
void onRelatedEntryChangedCallback()
void onRelatedButtonClickedCallback()
bool on_mnemonic_activate(bool group_cycling) override
Gtk::Entry * relatedEntry
Glib::ustring _prefs_path
void init(Glib::ustring const &prefs_path, bool mask, Glib::ustring const &default_string)
Gtk::Button * relatedButton
Glib::ustring _default_string
void onRelatedButtonClickedCallback()
void onRelatedEntryChangedCallback()
bool on_mnemonic_activate(bool group_cycling) override
Gtk::Entry * relatedEntry
Glib::ustring _prefs_path
void init(Glib::ustring const &prefs_path, bool mask)
Gtk::Button * relatedButton
void on_changed() override
void init(Glib::ustring const &prefs_path, bool mask)
void on_changed() override
Glib::ustring _prefs_path
void init(Glib::ustring const &prefs_path, int height)
Glib::ustring _prefs_path
To do: update description of desktop.
InkscapeWindow const * getInkscapeWindow() const
char const * label() const
Gets the author-visible label property for the object or a default if no label is defined.
Editable view implementation.
static Glib::ustring const prefs_path
macro for checking gtkmm version
Gtk::Image * sp_get_icon_image(Glib::ustring const &icon_name, int size)
Inkscape - An SVG editor.
Raw stack of active status messages.
void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir)
Find the start directory for a file dialog.
void pack_end(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the end of box.
static void popup_at(Gtk::Popover &popover, Gtk::Widget &widget, double const x_offset, double const y_offset, int width, int height)
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
void system_open(const Glib::ustring &path)
Opens the given path with platform-specific tools.
static void append(std::vector< T > &target, std::vector< T > &&source)
Glib::RefPtr< Gio::File > choose_file_open(Glib::ustring const &title, Gtk::Window *parent, Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > const &filters_model, std::string ¤t_folder, Glib::ustring const &accept)
Synchronously run a Gtk::FileDialog to open a single file for reading data.
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
void cairo_move_to(cairo_t *cr, Geom::Point p1)
Singleton class to access the preferences file in a convenient way.
static Inkscape::Colors::Color default_color(SPItem *item)
Find default color based on colors in existing fill.