libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GtkCRNDocument.cpp
Go to the documentation of this file.
1 /* Copyright 2010-2016 CoReNum, INSA-Lyon, ENS-Lyon
2  *
3  * This file is part of libgtkcrnmm.
4  *
5  * libgtkcrnmm is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libgtkcrnmm is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libgtkcrnmm. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: GtkCRNDocument.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <libgtkcrnmm_config.h>
23 #include <CRNi18n.h>
24 #include <GtkCRNDocument.h>
25 #include <iostream>
27 #include <GtkCRNPDFAttributes.h>
28 #include <GtkCRNProgressWindow.h>
29 #include <GtkCRNApp.h>
30 #include <CRNIO/CRNFileShield.h>
31 #include <GdkCRNPixbuf.h>
32 #include <GtkCRNHelpers.h>
33 
34 #ifndef CRN_USING_GTKMM3
35 # define get_content_area get_vbox
36 #endif
37 
38 using namespace GtkCRN;
40 // C++ stuff
42 
47 Document::Document(bool show_views, bool show_tree):
48 #ifdef CRN_USING_GTKMM3
49  views_actions(Gio::SimpleActionGroup::create()),
50 #else
51  views_actions(Gtk::ActionGroup::create("views")),
52 #endif
53  view_box(crn::Orientation::VERTICAL),
54  view_frame(_("Views")),
55  show_thumbnails(true),
56  show_labels(true),
57  show_indexes(true),
58 #ifdef CRN_USING_GTKMM3
59  tree_actions(Gio::SimpleActionGroup::create()),
60 #else
61  tree_actions(Gtk::ActionGroup::create("tree")),
62 #endif
63  treecol1(uint8_t(0), 0, 0),
64  treecol2(uint8_t(255), 255, 255),
65  treetextcol(uint8_t(0), 0, 0),
66  selcol1(uint8_t(0), 127, 0),
67  selcol2(uint8_t(0), 255, 0),
68  show_subblock_labels(true),
69  fill_subblocks(true),
70  tree_frame(_("Blocks"))
71 {
73  // Actions
75  // views
76 #ifdef CRN_USING_GTKMM3
77  views_actions->add_action("document-views-add", sigc::mem_fun(this, &Document::append_views_dialog));
78  views_actions->add_action("document-views-refresh", sigc::mem_fun(this, &Document::refresh_views));
79  views_actions->add_action("document-views-select-first", sigc::mem_fun(this, &Document::select_first));
80  views_actions->add_action("document-views-select-previous", sigc::mem_fun(this, &Document::select_previous));
81  views_actions->add_action("document-views-select-next", sigc::mem_fun(this, &Document::select_next));
82  views_actions->add_action("document-views-select-last", sigc::mem_fun(this, &Document::select_last));
83  views_actions->add_action("document-views-select-all", sigc::mem_fun(this, &Document::select_all));
84  views_actions->add_action("document-views-select-none", sigc::mem_fun(this, &Document::deselect_all));
85  views_actions->add_action("document-views-select-even", sigc::mem_fun(this, &Document::select_even));
86  views_actions->add_action("document-views-select-odd", sigc::mem_fun(this, &Document::select_odd));
87  views_actions->add_action("document-views-invert-selection", sigc::mem_fun(this, &Document::invert_selection));
88  views_actions->add_action("document-views-remove", sigc::mem_fun(this, &Document::delete_selection));
89 # ifdef CRN_USING_HARU
90  views_actions->add_action("document-views-export-pdf", sigc::mem_fun(this, &Document::export_pdf));
91 # endif
92 #else
93  views_actions->add(Gtk::Action::create("document-views-menu", _("_Views"), _("Views")));
94  views_actions->add(Gtk::Action::create("document-views-add", Gtk::StockID("gtk-crn-add-view"), _("_Add Views"), _("Add Views")), sigc::mem_fun(this, &Document::append_views_dialog));
95  views_actions->add(Gtk::Action::create("document-views-refresh", Gtk::Stock::REFRESH, _("_Refresh Views"), _("Refresh Views")), sigc::mem_fun(this, &Document::refresh_views));
96  views_actions->add(Gtk::Action::create("document-views-select-first", Gtk::Stock::GOTO_FIRST, _("Select _First View"), _("Select First View")), sigc::mem_fun(this, &Document::select_first));
97  views_actions->add(Gtk::Action::create("document-views-select-previous", Gtk::Stock::GO_BACK, _("Select _Previous View"), _("Select Previous View")), sigc::mem_fun(this, &Document::select_previous));
98  views_actions->add(Gtk::Action::create("document-views-select-next", Gtk::Stock::GO_FORWARD, _("Select _Next View"), _("Select Next View")), sigc::mem_fun(this, &Document::select_next));
99  views_actions->add(Gtk::Action::create("document-views-select-last", Gtk::Stock::GOTO_LAST, _("Select _Last View"), _("Select Last View")), sigc::mem_fun(this, &Document::select_last));
100  views_actions->add(Gtk::Action::create("document-views-select-all", Gtk::Stock::SELECT_ALL, _("Select _All Views"), _("Select All Views")), sigc::mem_fun(this, &Document::select_all));
101  views_actions->add(Gtk::Action::create("document-views-select-none", Gtk::Stock::CLEAR, _("_Deselect Views"), _("Deselect Views")), sigc::mem_fun(this, &Document::deselect_all));
102  views_actions->add(Gtk::Action::create("document-views-select-even", Gtk::StockID("gtk-crn-even"), _("Select _Even Views"), _("Select _Even Views")), sigc::mem_fun(this, &Document::select_even));
103  views_actions->add(Gtk::Action::create("document-views-select-odd", Gtk::StockID("gtk-crn-odd"), _("Select _Odd Views"), _("Select _Odd Views")), sigc::mem_fun(this, &Document::select_odd));
104  views_actions->add(Gtk::Action::create("document-views-invert-selection", Gtk::StockID("gtk-crn-invert"), _("_Invert View Selection"), _("Invert View Selection")), sigc::mem_fun(this, &Document::invert_selection));
105  views_actions->add(Gtk::Action::create("document-views-remove", Gtk::StockID("gtk-crn-delete-view"), _("_Remove View Selection"), _("Remove View Selection")), sigc::mem_fun(this, &Document::delete_selection));
106 # ifdef CRN_USING_HARU
107  views_actions->add(Gtk::Action::create("document-views-export-pdf", Gtk::Stock::CONVERT, _("_Export PDF"), _("Export PDF")), sigc::mem_fun(this, &Document::export_pdf));
108 # endif
109 #endif
110  disable_action_group(views_actions);
111  // tree
112 #ifdef CRN_USING_GTKMM3
113  tree_actions->add_action("document-blocks-add", sigc::mem_fun(this, &Document::add_subblock));
114  tree_actions->add_action("document-blocks-remove", sigc::mem_fun(this, &Document::rem_subblock));
115  tree_actions->add_action_bool("document-blocks-show", sigc::mem_fun(this, &Document::show_hide_subblocks_on_image));
116  tree_actions->add_action("document-blocks-configure", sigc::mem_fun(this, &Document::configure_subblocks));
117 #else
118  tree_actions->add(Gtk::Action::create("document-blocks-add", Gtk::StockID("gtk-crn-add-block"), _("_Add Subblock"), _("Add Subblock")), sigc::mem_fun(this, &Document::add_subblock));
119  tree_actions->add(Gtk::Action::create("document-blocks-remove", Gtk::StockID("gtk-crn-delete-block"), _("_Remove Subblock"), _("Remove Subblock")), sigc::mem_fun(this, &Document::rem_subblock));
120  tree_actions->add(Gtk::ToggleAction::create("document-blocks-show", Gtk::Stock::FIND, _("_Show/Hide Subblocks"), _("Show/Hide Subblocks"), true), sigc::mem_fun(this, &Document::show_hide_subblocks_on_image));
121  tree_actions->add(Gtk::Action::create("document-blocks-configure", Gtk::Stock::PROPERTIES, _("Subblocks _Settings"), _("Subblocks Settings")), sigc::mem_fun(this, &Document::configure_subblocks));
122 #endif
123  disable_action(tree_actions, "document-blocks-add");
124  disable_action(tree_actions, "document-blocks-remove");
125 
127  // left side
128  // atop
130  vpan.show();
131  pack1(vpan, Gtk::FILL);
132  if (show_views)
133  view_frame.show();
134  view_frame.set_shadow_type(Gtk::SHADOW_NONE);
135  view_frame.add(view_box);
136  view_box.show();
137  view_box.set_homogeneous(false);
138  view_box.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
139  droppedin_handle = view_box.signal_droppedin().connect(sigc::mem_fun(this, &Document::droppedin));
140  view_box.signal_moved().connect(sigc::mem_fun(this, &Document::moved));
141  view_box.signal_selection_changed().connect(sigc::mem_fun(this, &Document::on_view_selection_changed));
142  view_box.signal_key_release_event().connect(sigc::mem_fun(this, &Document::boxkeyevents));
143  view_box.set_size_request(120, 120);
144  vpan.pack1(view_frame, Gtk::FILL);
146  // bottom
148  if (show_tree)
149  tree_frame.show();
150  tree_frame.set_shadow_type(Gtk::SHADOW_NONE);
151  tree_frame.add(tree_box);
152  tree_box.show();
153  tree_box.set_homogeneous(false);
154  // buttons
155 #ifdef CRN_USING_GTKMM3
156  // TODO add icons
157  auto builder = Gtk::Builder::create_from_string(
158  "<interface>"
159  " <object class='GtkToolButton' id='dbadd'>"
160  " <attribute name='label' translatable='yes'>_Add subblock</attribute>"
161  " <attribute name='action'>document-blocks-add</attribute>"
162  " </object>"
163  " <object class='GtkToolButton' id='dbrem'>"
164  " <attribute name='label' translatable='yes'>_Remove subblock</attribute>"
165  " <attribute name='action'>document-blocks-remove</attribute>"
166  " </object>"
167  " <object class='GtkToolButton' id='dbshow'>"
168  " <attribute name='label' translatable='yes'>_Show/Hide Subblocks</attribute>"
169  " <attribute name='action'>document-blocks-show</attribute>"
170  " </object>"
171  " <object class='GtkToolButton' id='dbconf'>"
172  " <attribute name='label' translatable='yes'>Subblocks _Settings</attribute>"
173  " <attribute name='action'>document-blocks-configure</attribute>"
174  " </object>"
175  "</interface>"
176  );
177  Gtk::ToolItem *ti;
178  builder->get_widget("dbadd", ti);
179  tree_buttons.append(*Gtk::manage(ti));
180  builder->get_widget("dbrem", ti);
181  tree_buttons.append(*Gtk::manage(ti));
182  builder->get_widget("dbshow", ti);
183  tree_buttons.append(*Gtk::manage(ti));
184  builder->get_widget("dbconf", ti);
185  tree_buttons.append(*Gtk::manage(ti));
186 #else
187  tree_buttons.append(*Gtk::manage(tree_actions->get_action("document-blocks-add")->create_tool_item()));
188  tree_buttons.append(*Gtk::manage(tree_actions->get_action("document-blocks-remove")->create_tool_item()));
189  tree_buttons.append(*Gtk::manage(tree_actions->get_action("document-blocks-show")->create_tool_item()));
190  tree_buttons.append(*Gtk::manage(tree_actions->get_action("document-blocks-configure")->create_tool_item()));
191 #endif
192  tree_buttons.show();
193  tree_box.pack_start(tree_buttons, false, true, 0);
194  // tree
195  block_tree_store = Gtk::TreeStore::create(block_columns);
196  block_tree_view.set_model(block_tree_store);
197  block_tree_view.show();
198  block_tree_view.append_column(_("Block name"), block_columns.name);
199  block_tree_view.append_column(_("Coordinates"), block_columns.coords);
200  block_tree_view.get_selection()->signal_changed().connect(sigc::mem_fun(this, &Document::subblock_selection_changed));
201  tree_sw.add(block_tree_view);
202  tree_sw.show();
203  tree_box.pack_start(tree_sw, true, true, 0);
204  vpan.pack2(tree_frame, Gtk::FILL);
205 
207  // right side
209  image_box.show();
210  pack2(image_box, Gtk::EXPAND | Gtk::FILL);
211  left_box.show();
212  image_box.pack_start(left_box, false, true, 0);
213  img.show();
214  img.signal_overlay_changed().connect(sigc::mem_fun(this, &Document::on_image_overlay_changed));
215  img.get_overlay_config(subblock_list_name).moveable = false;
216  img.get_overlay_config(subblock_list_name).editable = false;
217  img.get_overlay_config(subblock_list_name).color1 = GdkCRN::ColorFromCRNPixel(treecol1);
218  img.get_overlay_config(subblock_list_name).color2 = GdkCRN::ColorFromCRNPixel(treecol2);
219  img.get_overlay_config(subblock_list_name).text_color = GdkCRN::ColorFromCRNPixel(treetextcol);
220  img.get_overlay_config(subblock_list_name).fill = fill_subblocks;
223  image_box.pack_start(img, true, true, 0);
224  right_box.show();
225  image_box.pack_start(right_box, false, true, 0);
226 
227  set_sensitive(false);
228 }
229 
232 {
233  if (crndoc)
234  {
235  crndoc->Save();
236  }
237 }
238 
240 // General document management
242 
247 void Document::set_document(const crn::SDocument &doc)
248 {
249  crndoc = doc;
250  if (crndoc)
251  {
252  refresh_views();
253  set_sensitive(true);
254  enable_action_group(views_actions);
255  disable_action(views_actions, "document-views-remove");
256  }
257  else
258  {
259  set_sensitive(false);
260  disable_action_group(views_actions);
261  }
262 }
263 
265 // Views
267 
268 Document::View::View(const crn::String &id, crn::SDocument doc):
269  view_id(id)
270 {
271  try
272  {
273  thumb.set(doc->GetThumbnailFilename(id).CStr());
274  }
275  catch (...)
276  {
277  //thumb.set(Gtk::Stock::MISSING_IMAGE, Gtk::ICON_SIZE_BUTTON);
278  }
279  thumb.show();
280  pack_start(thumb, FALSE, TRUE, 0);
281 
282  try
283  {
284  index.set_text(crn::StringUTF8(doc->GetViewIndex(id)).CStr());
285  }
286  catch (...)
287  {
288  index.set_text("?");
289  }
290  index.show();
291  pack_start(index, FALSE, TRUE, 0);
292 
293  try
294  {
295  lab.set_text(doc->GetViewFilename(id).CStr());
296  }
297  catch (...)
298  {
299  lab.set_text(_("Inexistent view"));
300  }
301  lab.show();
302  lab.set_ellipsize(Pango::ELLIPSIZE_START);
303  pack_start(lab, FALSE, TRUE, 0);
304 }
305 
309 void Document::create_view_cache(crn::Progress *pw)
310 {
311  int nb_errors = 0;
312  for (size_t tmp = 0; tmp < crndoc->GetNbViews(); ++tmp)
313  {
314  try
315  {
316  crndoc->GetThumbnailFilename(tmp);
317  }
319  {
320  App::show_message(_("The document was never saved. It is impossible to generate thumbnails."), Gtk::MESSAGE_WARNING);
321  nb_errors = 0;
322  break;
323  }
324  catch (...)
325  {
326  nb_errors += 1;
327  }
328  pw->Advance();
329  }
330  if (nb_errors)
331  {
332  gchar message[1024];
333  g_snprintf(message, 1024, _("%i error(s) occurred during the generation of the thumbnails. Some images may be deffective."), nb_errors);
334  App::show_message(message, Gtk::MESSAGE_WARNING);
335  }
336  //throw Glib::Thread::Exit(); // is this necessary?
337 }
338 
342 {
343  // store selection
344  const std::vector<crn::String> sel(get_selected_views_ids());
345  const crn::String lastsel(get_selected_view_id());
346 
347  // empty the box
348  views.clear();
349  view_box.clear();
350 
351  if (!crndoc)
352  return;
353  if (crndoc->GetNbViews() == 0)
354  return;
355 
356  // make sure all cache images exist (with a progress bar)
357  GtkCRN::ProgressWindow pwin(_("Refresh"), (Gtk::Window*)get_ancestor(GTK_TYPE_WINDOW), true);
358  crn::Progress *prog = pwin.get_crn_progress(pwin.add_progress_bar(_("Loading view"), (int)crndoc->GetNbViews()));
360  pwin.run(sigc::bind(sigc::mem_fun(this, &Document::create_view_cache), prog));
361 
362  bool reselectlast = false;
363  // add document views
364  for (size_t tmp = 0; tmp < crndoc->GetNbViews(); ++tmp)
365  {
366  const crn::String vid = crndoc->GetViewId(tmp);
367  if (vid == lastsel)
368  {
369  reselectlast = true;
370  }
371  views.push_back(std::make_shared<View>(vid, crndoc));
372  views.back()->show();
373  view_box.pack_start(*views.back(), false, true, 0);
374  }
375  // recall selection
376  for (size_t tmp = 0; tmp < sel.size(); ++tmp)
377  {
378  try
379  {
380  const crn::String vid = sel[tmp];
381  if (vid != lastsel)
382  {
383  view_box.set_selected(crndoc->GetViewIndex(sel[tmp]), true, reselectlast || (tmp != (sel.size() - 1)));
384  }
385  }
386  catch (...)
387  { // a view was removed. that's not a problem.
388  }
389  }
390  if (reselectlast)
391  {
392  view_box.set_selected(crndoc->GetViewIndex(lastsel), true, false);
393  }
394 }
395 
396 std::vector<crn::String> Document::get_selected_views_ids()
397 {
398  std::vector<Gtk::Widget*> selection(view_box.get_selection());
399  std::vector<crn::String> selid;
400  for (Gtk::Widget *w : selection)
401  {
402  View *v = dynamic_cast<View*>(w);
403  selid.push_back(v->get_view_id());
404  }
405  return selid;
406 }
407 
409 {
410  View *v(dynamic_cast<View*>(view_box.get_last_selected()));
411  if (v)
412  {
413  return v->get_view_id();
414  }
415  return U"";
416 }
417 
423 {
424  size_t index = crndoc->GetViewIndex(view_id);
425  view_box.set_selection(index);
426 }
427 
432 void Document::droppedin(int pos, crn::StringUTF8 data)
433 {
434  std::vector<crn::StringUTF8> files(data.Split("\r\n"));
435  for (const crn::StringUTF8 &fname : files)
436  {
437  if (fname != "")
438  {
439  pos += 1; // +1 because -1 is the first drop zone.
440  crn::Path p(fname);
441  p.ToLocal();
442  crndoc->InsertView(p, pos); // TODO pass complete URI and make sure libcrn supports it!!!
443  }
444  }
445  refresh_views();
446  // TODO what about the selection?
447 }
448 
453 void Document::moved(std::vector<size_t> to, std::vector<size_t> from)
454 {
455  crndoc->ReorderViewsTo(to);
456  for (std::shared_ptr<View> v : views)
457  {
458  v->set_index(crndoc->GetViewIndex(v->get_view_id()));
459  }
460 }
461 
466 void Document::on_view_selection_changed(Gtk::Widget *last_selected_widget, const std::vector<Gtk::Widget*> selection)
467 {
468  crn::String lastselid;
469  std::vector<crn::String> selid(get_selected_views_ids());
470  try
471  {
472  if (last_selected_widget != nullptr)
473  {
474  View *v = dynamic_cast<View*>(last_selected_widget);
475  if (v)
476  {
477  lastselid = v->get_view_id();
478  current_block = crndoc->GetView(v->get_view_id());
479  load_tree(v->get_view_id());
480  enable_action(views_actions, "document-views-remove");
481  selection_changed.emit(lastselid, selid);
482  return;
483  }
484  }
485  }
486  catch (...)
487  { // could not open image (cannot be a wrong id, I think)
488  }
489  current_block = nullptr;
490  clear_tree();
491  disable_action(tree_actions, "document-blocks-add");
492  disable_action(tree_actions, "document-blocks-remove");
493  disable_action(views_actions, "document-views-remove");
494  selection_changed.emit(lastselid, selid);
495 }
496 
501 bool Document::boxkeyevents(GdkEventKey *ev)
502 {
503 #ifdef CRN_USING_GTKMM3
504  if (ev->keyval == GDK_KEY_Delete)
505 #else /* CRN_USING_GTKMM3 */
506  if (ev->keyval == GDK_Delete)
507 #endif /* CRN_USING_GTKMM3 */
508  {
510  }
511  return false;
512 }
513 
515 {
516  show_thumbnails = s;
517  for (std::shared_ptr<View> v : views)
518  {
519  v->set_show_thumbnail(s);
520  }
521 }
522 
524 {
525  show_labels = s;
526  for (std::shared_ptr<View> v : views)
527  {
528  v->set_show_label(s);
529  }
530 }
531 
533 {
534  show_indexes = s;
535  for (std::shared_ptr<View> v : views)
536  {
537  v->set_show_index(s);
538  }
539 }
540 
545 gboolean Document::tsreloadimage(DVI *data)
546 {
547  data->doc->reload_image(data->id);
548  delete data;
549  return FALSE;
550 }
551 
553 {
554  const std::vector<Gtk::Widget*> sel(view_box.get_selection());
555  if (sel.size() != 0)
556  {
557  if (!may_delete_selection.empty())
558  {
559  std::vector<crn::String> selid(get_selected_views_ids());
560  if (!may_delete_selection.emit(selid))
561  {
562  return;
563  }
564  }
565 
566  for (Gtk::Widget *w : sel)
567  {
568  View *v = dynamic_cast<View*>(w);
569  if (v)
570  {
571  try
572  {
573  crndoc->RemoveView(v->get_view_id());
574  }
575  catch (...)
576  { // invalid id, do nothing
577  }
578  }
579  }
580  refresh_views();
581  }
582 }
583 
584 void Document::append_views(const std::vector<crn::Path> &filenames)
585 {
586  for (crn::Path fname : filenames)
587  {
588  fname.ToLocal();
589  if (fname.IsNotEmpty())
590  crndoc->AddView(fname);
591  }
592  refresh_views();
593 }
594 
596 {
597  Gtk::FileChooserDialog dial((Gtk::Window&)(*get_ancestor(GTK_TYPE_WINDOW)), _("Please select views to add"), Gtk::FILE_CHOOSER_ACTION_OPEN);
598  dial.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
599 #ifdef CRN_USING_GTKMM3
600  auto ff = Gtk::FileFilter::create();
601  ff->add_pixbuf_formats();
602 #else /* CRN_USING_GTKMM3 */
603  Gtk::FileFilter ff;
604  ff.add_pixbuf_formats();
605 #endif /* CRN_USING_GTKMM3 */
606  dial.set_filter(ff);
607  dial.set_select_multiple(true);
608 #ifdef CRN_USING_GTKMM3
609  dial.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
610  dial.add_button(_("_Add"), Gtk::RESPONSE_ACCEPT);
611 #else
612  dial.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
613  dial.add_button(Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
614  std::vector<int> altbut;
615  altbut.push_back(Gtk::RESPONSE_ACCEPT);
616  altbut.push_back(Gtk::RESPONSE_CANCEL);
617  dial.set_alternative_button_order_from_array(altbut);
618 #endif
619  dial.set_default_response(Gtk::RESPONSE_ACCEPT);
620  dial.show();
621  int resp = dial.run();
622  dial.hide();
623  if (resp == Gtk::RESPONSE_ACCEPT)
624  {
625 #ifdef CRN_USING_GTKMM3
626  const auto uris = dial.get_uris();
627  auto fnames = std::vector<crn::Path>{};
628  for (const auto &uri : uris)
629  fnames.push_back(uri.c_str());
630 #else /* CRN_USING_GTKMM3 */
631  std::vector<crn::Path> fnames(dial.get_uris());
632 #endif /* CRN_USING_GTKMM3 */
633  append_views(fnames);
634  }
635 }
636 
638 {
639  view_box.select_even();
640 }
641 
643 {
644  view_box.select_odd();
645 }
646 
648 {
649  view_box.select_all();
650 }
651 
653 {
654  view_box.deselect_all();
655 }
656 
658 {
659  view_box.invert_selection();
660 }
661 
663 {
664  view_box.select_first();
665 }
666 
668 {
669  view_box.select_previous();
670 }
671 
673 {
674  view_box.select_next();
675 }
676 
678 {
679  view_box.select_last();
680 }
681 
683 // Subblock tree
685 
687 void Document::clear_tree()
688 {
689  block_tree_store->clear();
690  img.set_pixbuf(Glib::RefPtr<Gdk::Pixbuf>(nullptr));
691 }
692 
696 void Document::load_tree(const crn::String &view_id)
697 {
698  clear_tree();
699  try
700  {
701  crn::SBlock b(crndoc->GetView(view_id));
702  if (b)
703  {
704  Gtk::TreeModel::iterator it(block_tree_store->append());
705  it->set_value(block_columns.name, Glib::ustring(b->GetName().CStr()));
706  it->set_value(block_columns.block, b);
707  it->set_value(block_columns.is_tree, false);
708  it->set_value(block_columns.coords, Glib::ustring(b->GetAbsoluteBBox().ToString().CStr()));
709  tree_add_children(it, b);
710  block_tree_view.expand_row(Gtk::TreePath(it), false);
711  block_tree_view.get_selection()->select(it);
712  }
713  }
714  catch (...)
715  { // wrong id should never happen…
716  }
717 }
718 
723 void Document::tree_add_children(Gtk::TreeModel::iterator &it, crn::SBlock b)
724 {
725  std::vector<crn::String> trees(b->GetTreeNames());
726  for (const crn::String &tname : trees)
727  {
728  Gtk::TreeModel::iterator bit(block_tree_store->append(it->children()));
729  bit->set_value(block_columns.name, Glib::ustring(tname.CStr()));
730  bit->set_value(block_columns.block, b);
731  bit->set_value(block_columns.is_tree, true);
732  for (crn::SObject sbo : b->GetTree(tname))
733  {
734  crn::SBlock sb(std::static_pointer_cast<crn::Block>(sbo));
735  Gtk::TreeModel::iterator sit(block_tree_store->append(bit->children()));
736  sit->set_value(block_columns.name, Glib::ustring(sb->GetName().CStr()));
737  sit->set_value(block_columns.block, sb);
738  sit->set_value(block_columns.is_tree, false);
739  sit->set_value(block_columns.coords, Glib::ustring(sb->GetAbsoluteBBox().ToString().CStr()));
740  tree_add_children(sit, sb);
741  }
742  }
743 }
744 
746 void Document::subblock_selection_changed()
747 {
749  if (viewid.IsNotEmpty() && block_tree_view.get_selection()->count_selected_rows())
750  {
751  try
752  {
753  std::lock_guard<std::mutex> lock(crn::FileShield::GetMutex("GtkCRNDocument::" + crndoc->GetViewFilename(viewid))); // lock image
754  Gtk::TreeIter it(block_tree_view.get_selection()->get_selected());
755  // set block
756  blocksel = it->get_value(block_columns.block);
757  // load image
758  Glib::RefPtr<Gdk::Pixbuf> pb = GdkCRN::PixbufFromFile(crndoc->GetViewFilename(viewid));
759  // crop
760  crn::Rect clip(blocksel->GetAbsoluteBBox());
761  Glib::RefPtr<Gdk::Pixbuf> pb2(Gdk::Pixbuf::create_subpixbuf(pb, clip.GetLeft(), clip.GetTop(), clip.GetWidth(), clip.GetHeight()));
762  img.set_pixbuf(pb2);
763  // set sensitive the add subblock button if there is a selection on the image
764  set_enable_action(tree_actions, "document-blocks-add", img.has_selection());
765  // set sensitive the remove subblock button if the selected row is not the first
766  set_enable_action(tree_actions, "document-blocks-remove", it != block_tree_store->children()[0]);
767  }
768  catch (...)
769  { // invalid block id or cannot open image
770  img.set_pixbuf(Glib::RefPtr<Gdk::Pixbuf>(nullptr));
771  disable_action(tree_actions, "document-blocks-add");
772  disable_action(tree_actions, "document-blocks-remove");
773  }
774  }
775  else
776  {
777  // set unsensitive the remove subblock button
778  disable_action(tree_actions, "document-blocks-remove");
779  }
780  show_hide_subblocks_on_image();
781 }
782 
784 void Document::add_subblock()
785 {
786  // get data
787  crn::Rect bbox(img.get_selection_as_rect());
788  crn::SBlock b;
789  crn::StringUTF8 autoselect;
790  if (block_tree_view.get_selection()->count_selected_rows())
791  {
792  Gtk::TreeIter it(block_tree_view.get_selection()->get_selected());
793  b = it->get_value(block_columns.block);
794  if (it->get_value(block_columns.is_tree))
795  autoselect = it->get_value(block_columns.name).c_str();
796  }
797  else
798  {
799  b = current_block;
800  }
801  // create dialog
802  Gtk::Dialog dial(_("Add a subblock"), (Gtk::Window&)(*get_ancestor(GTK_TYPE_WINDOW)), true);
803  dial.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
804 #ifdef CRN_USING_GTKMM3
805  dial.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
806  dial.add_button(_("_OK"), Gtk::RESPONSE_ACCEPT);
807 #else
808  dial.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
809  dial.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
810  std::vector<int> altbut;
811  altbut.push_back(Gtk::RESPONSE_ACCEPT);
812  altbut.push_back(Gtk::RESPONSE_CANCEL);
813  dial.set_alternative_button_order_from_array(altbut);
814 #endif
815  dial.set_default_response(Gtk::RESPONSE_ACCEPT);
816  Gtk::Label lab1(_("Subblock tree"));
817  Gtk::Label lab2(_("New subblock's name"));
818 #ifdef CRN_USING_GTKMM3
819  Gtk::Grid tab;
820  tab.attach(lab1, 0, 0, 1, 1);
821  tab.attach(lab2, 0, 1, 1, 1);
822 #else
823  Gtk::Table tab(2, 2);
824  tab.attach(lab1, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
825  tab.attach(lab2, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK);
826 #endif
827 #ifdef CRN_USING_GTKMM3
828  Gtk::ComboBoxText combo(true);
829 #else /* CRN_USING_GTKMM3 */
830  Gtk::ComboBoxEntryText combo;
831 #endif /* CRN_USING_GTKMM3 */
832  std::vector<crn::String> trees(b->GetTreeNames());
833  for (const crn::String &tname : trees)
834  {
835 #ifdef CRN_USING_GTKMM3
836  combo.append(tname.CStr());
837 #else /* CRN_USING_GTKMM3 */
838  combo.append_text(tname.CStr());
839 #endif /* CRN_USING_GTKMM3 */
840  }
841  combo.get_entry()->set_text(autoselect.CStr());
842  combo.get_entry()->set_activates_default(true);
843 #ifdef CRN_USING_GTKMM3
844  tab.attach(combo, 1, 0, 1, 1);
845 #else
846  tab.attach(combo, 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
847 #endif
848  Gtk::Entry entname;
849  entname.set_text(_("New subblock"));
850  entname.set_activates_default(true);
851 #ifdef CRN_USING_GTKMM3
852  tab.attach(entname, 1, 1, 1, 1);
853 #else
854  tab.attach(entname, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
855 #endif
856  tab.show_all();
857  dial.get_content_area()->pack_start(tab, true, true, 0);
858 
859  if (dial.run() == Gtk::RESPONSE_ACCEPT)
860  {
861  dial.hide();
862  // add to block
863  crn::StringUTF8 treename(combo.get_entry()->get_text().c_str());
864  crn::SBlock nb(nullptr);
865  try
866  {
867  nb = b->AddChildRelative(treename, bbox, entname.get_text().c_str());
868  }
869  catch (...)
870  {
871  App::show_message(_("Cannot add such selection to the subblock tree."), Gtk::MESSAGE_WARNING);
872  return;
873  }
874  // find iter
875  Gtk::TreeIter it;
876  if (block_tree_view.get_selection()->count_selected_rows())
877  {
878  it = block_tree_view.get_selection()->get_selected();
879  if (it->get_value(block_columns.is_tree))
880  { // if a subblock tree is selected, we now do as if it was its parent node
881  it = it->parent();
882  }
883  }
884  else
885  it = block_tree_store->children()[0];
886  bool found = false;
887  Gtk::TreeIter newit;
888  for (const Gtk::TreeRow &row : it->children())
889  {
890  if (row.get_value(block_columns.is_tree) && (row.get_value(block_columns.name) == treename.CStr()))
891  {
892  // add to tree store
893  newit = block_tree_store->append(row.children());
894  found = true;
895  break;
896  }
897  }
898  if (!found)
899  {
900  // must create 2 entries in the store
901  // the new subblock tree
902  newit = block_tree_store->append(it->children());
903  newit->set_value(block_columns.name, Glib::ustring(treename.CStr()));
904  newit->set_value(block_columns.block, b);
905  newit->set_value(block_columns.is_tree, true);
906 
907  // the new subblock
908  newit = block_tree_store->append(newit->children());
909  }
910  newit->set_value(block_columns.name, entname.get_text());
911  newit->set_value(block_columns.block, nb);
912  newit->set_value(block_columns.is_tree, false);
913  newit->set_value(block_columns.coords, Glib::ustring(bbox.ToString().CStr()));
914  }
915 }
916 
918 void Document::rem_subblock()
919 {
920  if (block_tree_view.get_selection()->count_selected_rows())
921  { // a row is selected
922  Gtk::TreeIter it(block_tree_view.get_selection()->get_selected());
923  if (it->get_value(block_columns.is_tree))
924  {
925  crn::SBlock b(it->get_value(block_columns.block));
926  b->RemoveTree(it->get_value(block_columns.name).c_str());
927  block_tree_store->erase(it);
928  }
929  else
930  {
931  crn::SBlock b(it->get_value(block_columns.block));
932  crn::Block *pb = b->GetParent().lock().get();
933  if (pb)
934  {
935  Gtk::TreeIter pit(it->parent());
936  try
937  {
938  pb->RemoveChild(pit->get_value(block_columns.name).c_str(), b);
939  } catch (...) { }
940  block_tree_store->erase(it);
941  block_tree_view.get_selection()->select(pit);
942  }
943  }
944  }
945 }
946 
948 void Document::configure_subblocks()
949 {
950  // create dialog
951  Gtk::Dialog dial(_("Configure subblocks display"), (Gtk::Window&)(*get_ancestor(GTK_TYPE_WINDOW)), true);
952  dial.set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
953 #ifdef CRN_USING_GTKMM3
954  dial.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
955  dial.add_button(_("_OK"), Gtk::RESPONSE_ACCEPT);
956 #else
957  dial.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
958  dial.add_button(Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
959  std::vector<int> altbut;
960  altbut.push_back(Gtk::RESPONSE_ACCEPT);
961  altbut.push_back(Gtk::RESPONSE_CANCEL);
962  dial.set_alternative_button_order_from_array(altbut);
963 #endif
964  dial.set_default_response(Gtk::RESPONSE_ACCEPT);
965 
966  Gtk::Label lab1(_("Frame color"));
967  Gtk::Label lab2(_("Fill color"));
968  Gtk::CheckButton show_labels_cb(_("Show subblock _labels"));
969  show_labels_cb.set_active(show_subblock_labels);
970  Gtk::Label lab3(_("Label color"));
971 #ifdef CRN_USING_GTKMM3
972  Gtk::Grid tab;
973  tab.attach(lab1, 0, 0, 1, 1);
974  Gdk::RGBA color;
975  color.set_rgba_u(gushort(treecol1.r * 256), gushort(treecol1.g * 256), gushort(treecol1.b * 255));
976  Gtk::ColorButton cb1(color);
977  tab.attach(cb1, 1, 0, 1, 1);
978 
979  tab.attach(lab2, 0, 1, 1, 1);
980  color.set_rgba_u(gushort(treecol2.r * 256), gushort(treecol2.g * 256), gushort(treecol2.b * 255));
981  Gtk::ColorButton cb2(color);
982  tab.attach(cb2, 1, 1, 1, 1);
983 
984  tab.attach(show_labels_cb, 0, 2, 2, 1);
985 
986  color.set_rgba_u(gushort(treetextcol.r * 256), gushort(treetextcol.g * 256), gushort(treetextcol.b * 255));
987  Gtk::ColorButton cbt(color);
988  tab.attach(cbt, 1, 3, 1, 1);
989  tab.attach(lab3, 0, 3, 1, 1);
990 #else
991  Gtk::Table tab(4, 2);
992  tab.attach(lab1, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
993 
994  Gdk::Color color;
995  color.set_rgb(gushort(treecol1.r * 256), gushort(treecol1.g * 256), gushort(treecol1.b * 255));
996  Gtk::ColorButton cb1(color);
997  tab.attach(cb1, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
998 
999  tab.attach(lab2, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK);
1000  color.set_rgb(gushort(treecol2.r * 256), gushort(treecol2.g * 256), gushort(treecol2.b * 255));
1001  Gtk::ColorButton cb2(color);
1002  tab.attach(cb2, 1, 2, 1, 2, Gtk::SHRINK, Gtk::SHRINK);
1003 
1004  tab.attach(show_labels_cb, 0, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
1005 
1006  color.set_rgb(gushort(treetextcol.r * 256), gushort(treetextcol.g * 256), gushort(treetextcol.b * 255));
1007  Gtk::ColorButton cbt(color);
1008  tab.attach(cbt, 1, 2, 3, 4, Gtk::SHRINK, Gtk::SHRINK);
1009  tab.attach(lab3, 0, 1, 3, 4, Gtk::SHRINK, Gtk::SHRINK);
1010 #endif
1011  tab.show_all();
1012  dial.get_content_area()->pack_start(tab, true, true, 0);
1013 
1014  if (dial.run() == Gtk::RESPONSE_ACCEPT)
1015  {
1016  set_show_subblock_labels(show_labels_cb.get_active());
1017 #ifdef CRN_USING_GTKMM3
1018  color = cb1.get_rgba();
1019 #else
1020  color = cb1.get_color();
1021 #endif
1022  auto p1 = GdkCRN::CRNPixelRGBFromGdkColor(color);
1023 #ifdef CRN_USING_GTKMM3
1024  color = cb1.get_rgba();
1025 #else
1026  color = cb2.get_color();
1027 #endif
1028  auto p2 = GdkCRN::CRNPixelRGBFromGdkColor(color);
1029 #ifdef CRN_USING_GTKMM3
1030  color = cb1.get_rgba();
1031 #else
1032  color = cbt.get_color();
1033 #endif
1034  auto pt = GdkCRN::CRNPixelRGBFromGdkColor(color);
1035  set_subblocks_colors(p1, p2, pt);
1036  }
1037 }
1038 
1040 // Displayed image
1042 const crn::String Document::subblock_list_name(U"GtkCRN::Document::Current_subblocks");
1043 
1045 {
1046  for (std::shared_ptr<View> v : views)
1047  {
1048  if (v->get_view_id() == view_id)
1049  {
1050  v->set_thumbnail(crndoc->GetThumbnailFilename(view_id));
1051 
1052  if (get_selected_view_id() == view_id)
1053  { // the image has to be reloaded
1054  try
1055  {
1056  crn::Path lastsel = crndoc->GetViewFilename(get_selected_view_id());
1057  std::lock_guard<std::mutex> lock(crn::FileShield::GetMutex(lastsel)); // lock image
1058  Glib::RefPtr<Gdk::Pixbuf> pb = GdkCRN::PixbufFromFile(lastsel);
1059  img.set_pixbuf(pb);
1060  }
1061  catch (...)
1062  {
1063  img.set_pixbuf(Glib::RefPtr<Gdk::Pixbuf>(nullptr));
1064  }
1065  }
1066  }
1067  }
1068 }
1069 
1071 {
1072  DVI *data(new DVI(this, view_id));
1073  g_idle_add(GSourceFunc(Document::tsreloadimage), data);
1074 }
1075 
1081 void Document::on_image_overlay_changed(crn::String overlay_id, crn::String overlay_item_id, Image::MouseMode mm)
1082 {
1083  if (overlay_id == Image::selection_overlay())
1084  {
1085  set_enable_action(tree_actions, "document-blocks-add", overlay_item_id.IsNotEmpty());
1086  }
1087 }
1088 
1090 void Document::show_hide_subblocks_on_image()
1091 {
1092  // clear selections
1093  img.clear_overlay(subblock_list_name);
1094  if (is_toggle_action_active(tree_actions, "document-blocks-show"))
1095  { // must show subblocks
1096  if (block_tree_view.get_selection()->count_selected_rows())
1097  { // a row is selected
1098  Gtk::TreeIter it(block_tree_view.get_selection()->get_selected());
1099  if (it->get_value(block_columns.is_tree))
1100  { // the selected row is a tree
1101  crn::SBlock b(it->get_value(block_columns.block));
1102  crn::String name(it->get_value(block_columns.name).c_str());
1103  int cnt = 0;
1104  for (crn::SObject sbo : b->GetTree(name))
1105  {
1106  crn::SBlock sb(std::static_pointer_cast<crn::Block>(sbo));
1107  img.add_overlay_item(subblock_list_name, cnt++, sb->GetRelativeBBox(), sb->GetName().CStr());
1108  }
1109  }
1110  }
1111  }
1112 }
1113 
1115 {
1116  selcol1 = col1;
1117  selcol2 = col2;
1120 }
1121 
1123 {
1124  treecol1 = col1;
1125  treecol2 = col2;
1126  treetextcol = textcol;
1127  img.get_overlay_config(subblock_list_name).color1 = GdkCRN::ColorFromCRNPixel(treecol1);
1128  img.get_overlay_config(subblock_list_name).color2 = GdkCRN::ColorFromCRNPixel(treecol2);
1129  img.get_overlay_config(subblock_list_name).text_color = GdkCRN::ColorFromCRNPixel(treetextcol);
1130 }
1131 
1133 {
1134  show_subblock_labels = s;
1135  img.get_overlay_config(subblock_list_name).show_labels = s;
1136  /*
1137  show_hide_subblocks_on_image();
1138  */
1139 }
1140 
1141 #ifdef CRN_USING_HARU
1142 
1143 void Document::export_pdf()
1144 {
1145  static std::shared_ptr<Gtk::FileChooserDialog> dial(nullptr);
1146 #ifdef CRN_USING_GTKMM3
1147  static auto ff = Gtk::FileFilter::create();
1148 #else /* CRN_USING_GTKMM3 */
1149  static Gtk::FileFilter ff;
1150 #endif /* CRN_USING_GTKMM3 */
1151  static PDFAttributes attr;
1152  if (!dial)
1153  {
1154  dial = std::make_shared<Gtk::FileChooserDialog>((Gtk::Window&)(*get_ancestor(GTK_TYPE_WINDOW)), _("Export PDF"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1155  dial->set_position(Gtk::WIN_POS_CENTER_ON_PARENT);
1156 #ifdef CRN_USING_GTKMM3
1157  ff->add_pattern("*.pdf");
1158  ff->add_pattern("*.Pdf");
1159  ff->add_pattern("*.PDF");
1160 #else /* CRN_USING_GTKMM3 */
1161  ff.add_pattern("*.pdf");
1162  ff.add_pattern("*.Pdf");
1163  ff.add_pattern("*.PDF");
1164 #endif /* CRN_USING_GTKMM3 */
1165  dial->set_filter(ff);
1166  dial->set_select_multiple(false);
1167 #ifdef CRN_USING_GTKMM3
1168  dial->add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
1169  dial->add_button(_("_Save"), Gtk::RESPONSE_ACCEPT);
1170 #else
1171  dial->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1172  dial->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1173  std::vector<int> altbut;
1174  altbut.push_back(Gtk::RESPONSE_ACCEPT);
1175  altbut.push_back(Gtk::RESPONSE_CANCEL);
1176  dial->set_alternative_button_order_from_array(altbut);
1177 #endif
1178  dial->set_default_response(Gtk::RESPONSE_ACCEPT);
1179  attr.show();
1180  dial->get_content_area()->pack_start(attr, false, true, 0);
1181  }
1182  dial->show();
1183  int resp = dial->run();
1184  dial->hide();
1185  if (resp == Gtk::RESPONSE_ACCEPT)
1186  {
1187  crn::Path fname(dial->get_uri());
1188  ProgressWindow pwin(_("Export PDF"), (Gtk::Window*)get_ancestor(GTK_TYPE_WINDOW), false);
1189  crn::Progress *prog = pwin.get_crn_progress(pwin.add_progress_bar(_("Writing image")));
1191  pwin.set_terminate_on_exception(false);
1192  pwin.run(sigc::hide_return(sigc::bind(sigc::mem_fun(crndoc.get(), &crn::Document::ExportPDF), fname, attr.get_attributes(), prog)));
1193  }
1194 }
1195 #endif
1196 
void set_show_indexes(bool s)
Shall the views show their index.
virtual ~Document() override
Destructor.
void set_selection(size_t index)
Sets the selection (one element)
void disable_action(const Glib::RefPtr< Gtk::ActionGroup > &grp, const Glib::ustring &action)
void set_selected(size_t index, bool selected=true, bool silent=false)
Adds or remove an element from the selection.
void select_next()
If selection size is 0, the select the first element, if selection size is 1, then select the next it...
void set_policy(Gtk::PolicyType hscrollbar_policy, Gtk::PolicyType vscrollbar_policy)
Sets the scrolling policy.
std::vector< crn::String > get_selected_views_ids()
Gets the selected views' ids.
void set_show_labels(bool s)
Shall the views show a label.
Glib::RefPtr< Gdk::Pixbuf > PixbufFromFile(const crn::Path &p)
Creates a Gdk::Pixbuf from a file.
Orientation
An enumeration of orientations.
Definition: CRNMath.h:152
Base class for a progress display.
Definition: CRNProgress.h:39
void set_subblocks_colors(const crn::pixel::RGB8 &col1, const crn::pixel::RGB8 &col2, const crn::pixel::RGB8 &textcol)
Sets the colors of the subblocks on the image.
void select_first()
If selection size is <= 1, then select the first view, else move last_selected to the first selected ...
void select_even()
Selects odd elements (2nd, 4th…)
OverlayConfig & get_overlay_config(const crn::String &id)
Gets the configuration of an overlay.
Definition: GtkCRNImage.h:232
crn::pixel::RGB8 CRNPixelRGBFromGdkColor(const Gdk::Color &color)
Creates a crn::PixelRGB from a Gdk::Color.
Gtk::Widget * get_last_selected() const
Returns the last widget that was selected.
#define _(String)
Definition: CRNi18n.h:51
Unintialized object error.
Definition: CRNException.h:155
void invert_selection()
Inverts the view selection.
WBlock GetParent()
Gets a reference to the parent of the block.
Definition: CRNBlock.h:80
std::vector< StringUTF8 > Split(const StringUTF8 &sep) const
Splits the string in multiple strings delimited by a set of separators.
const crn::Rect & get_selection_as_rect() const
Gets the mouse selection as a rectangle.
void select_all()
Selects all views.
void select_even()
Selects even views.
sigc::signal< void, int, crn::StringUTF8 > signal_droppedin()
Signals when something was dropped from another application. Connect to void on_droppedin(int positio...
void delete_selection()
Removes all selected views from the document.
bool is_toggle_action_active(const Glib::RefPtr< Gtk::ActionGroup > &grp, const Glib::ustring &action)
void select_odd()
Selects odd views.
static std::mutex & GetMutex(const Path &fname)
Gets the mutex associated to a file.
void Advance()
Progresses of one step.
Definition: CRNProgress.cpp:34
A UTF32 character string class.
Definition: CRNString.h:61
crn::Progress * get_crn_progress(size_t id)
Gets an existing progress bar.
void enable_action_group(const Glib::RefPtr< Gtk::ActionGroup > &grp)
void enable_action(const Glib::RefPtr< Gtk::ActionGroup > &grp, const Glib::ustring &action)
void clear_overlay(const crn::String &id)
Clears an overlay.
void thread_safe_reload_image(const crn::String &view_id)
Refreshes the thumbnail of a view and the Image if needed (thread safe)
void SetType(Type typ) noexcept
Sets the type of progress bar.
Definition: CRNProgress.h:61
A block.
Definition: CRNBlock.h:52
const char * CStr() const noexcept
Conversion to UTF8 cstring.
Splash window with progress bars.
crn::String get_selected_view_id()
Gets the displayed views's id.
void set_enable_action(const Glib::RefPtr< Gtk::ActionGroup > &grp, const Glib::ustring &action, bool enabled)
A convenience class for file paths.
Definition: CRNPath.h:39
void refresh_views()
Redraws the view list.
void select_odd()
Selects even elements (1st, 3rd…)
void set_document(const crn::SDocument &doc)
Sets the document to display.
void select_next()
If selection size is 0, the select the first element, if selection size is 1, then select the next vi...
OverlayConfig & get_selection_config()
Gets the mouse selection configuration.
Definition: GtkCRNImage.h:267
void select_first()
If selection size is <= 1, then select the first item, else move last_selected to the first selected ...
void pack_start(Gtk::Widget &child, Gtk::PackOptions options=Gtk::PACK_EXPAND_WIDGET, guint padding=0)
Left/top side insert a widget to a box.
void append_views(const std::vector< crn::Path > &filenames)
Appends new views at the end of the document.
sigc::signal< void, std::vector< size_t >, std::vector< size_t > > signal_moved()
Signals when a widget was moved. Connect to void on_moved(moved_to, moved_from).
bool has_selection() const
Is there a mouse selection?
void select_last()
If selection size is <= 1, then select the last view, else move last_selected to the last selected el...
#define true
Definition: ConvertUTF.cpp:57
void clear()
Erase all elements.
void invert_selection()
Inverts the view selection.
void set_show_subblock_labels(bool s)
Shows or hides subblocks labels on the image.
std::vector< Gtk::Widget * > get_selection() const
Returns the list of selected widgets.
void add_overlay_item(const crn::String &overlay_id, const crn::String &item_id, const crn::Rect &r, const crn::StringUTF8 &label="")
Adds a rectangle to an overlay.
sigc::signal< void, Gtk::Widget *, const std::vector< Gtk::Widget * > > signal_selection_changed()
Signal when the selection has changed. Connect to void on_selection_changed(Gtk::Widget last_selected...
void select_last()
If selection size is <= 1, then select the last item, else move last_selected to the last selected el...
static const crn::String & selection_overlay()
Returns the name of the mouse selection overlay.
void reload_image(const crn::String &view_id)
Refreshes the thumbnail of a view and the Image if needed.
void set_show_thumbnails(bool s)
Shall the views show a thumbnail.
void run(sigc::slot< void > func)
Executes a processing.
static void show_message(const Glib::ustring &message, Gtk::MessageType mtype)
Displays a message.
Definition: GtkCRNApp.cpp:149
MouseMode
State of the mouse activity.
Definition: GtkCRNImage.h:116
void set_pixbuf(Glib::RefPtr< Gdk::Pixbuf > pb)
Sets the new image to display.
Configuration widget for crn::PDFAttributes.
void disable_action_group(const Glib::RefPtr< Gtk::ActionGroup > &grp)
void select_previous()
If selection size is 0, the select the first element, if selection size is 1, then select the previou...
Document(bool show_views=true, bool show_tree=true)
Constructor.
void deselect_all()
Selects all views.
A character string class.
Definition: CRNStringUTF8.h:49
void select_all()
Selects all elements.
sigc::signal< void, crn::String, crn::String, MouseMode > signal_overlay_changed()
Returns the signal associated to changes in selections. Binds to void on_overlay_changed(crn::String ...
Definition: GtkCRNImage.h:118
void set_selected_view(const crn::String &view_id)
Sets the one selected view.
Gdk::Color ColorFromCRNPixel(const crn::pixel::RGB8 &p)
Creates a Gdk::Color from a crn::Pixel.
void deselect_all()
Deselects all elements.
#define TRUE
Definition: CRNProp3.cpp:28
void set_selection_colors(const crn::pixel::RGB8 &col1, const crn::pixel::RGB8 &col2)
Sets the colors of the user selection on the image.
bool IsNotEmpty() const noexcept
Checks if the string is not empty.
Definition: CRNString.h:168
const crn::PDF::Attributes & get_attributes() const
Gets attributes.
size_t add_progress_bar(const crn::String &name, size_t maxcount=100)
Adds a progress bar to the window.
void set_homogeneous(bool homogeneous=true)
Sets the Gtk::Box:homogeneous property of box, controlling whether or not all children of box are giv...
void select_previous()
If selection size is 0, the select the first element, if selection size is 1, then select the previou...
A rectangle class.
Definition: CRNRect.h:46