/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include "history.h" #include "eventmapper.h" #include "guiutils.h" #include "multilangmgr.h" #include "rtimage.h" #include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; History::History (bool bookmarkSupport) : historyVPaned (nullptr), blistener (nullptr), tpc (nullptr), bmnum (1) { set_orientation(Gtk::ORIENTATION_VERTICAL); blistenerLock = false; // sets default that the Before preview will not be locked /* // fill history event message array for (int i = 0; i < NUMOFEVENTS; i++) { eventDescrArray[i] = M (Glib::ustring::compose ("HISTORY_MSG_%1", i + 1)); } */ // History List // ~~~~~~~~~~~~ Gtk::ScrolledWindow* hscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); hscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); Gtk::Frame* histFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_LABEL"))); histFrame->set_name ("HistoryPanel"); histFrame->add (*hscrollw); hTreeView = Gtk::manage (new Gtk::TreeView ()); hscrollw->add (*hTreeView); historyModel = Gtk::ListStore::create (historyColumns); hTreeView->set_model (historyModel); hTreeView->set_headers_visible (false); hTreeView->set_hscroll_policy (Gtk::SCROLL_MINIMUM); hTreeView->set_vscroll_policy (Gtk::SCROLL_NATURAL); hTreeView->set_size_request (80, -1); Gtk::CellRendererText *changecrt = Gtk::manage (new Gtk::CellRendererText()); changecrt->property_ellipsize() = Pango::ELLIPSIZE_END; Gtk::CellRendererText *valuecrt = Gtk::manage (new Gtk::CellRendererText()); valuecrt->property_ellipsize() = Pango::ELLIPSIZE_END; Gtk::TreeView::Column *hviewcol = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol->pack_start (*changecrt, true); hviewcol->add_attribute (changecrt->property_markup (), historyColumns.text); hviewcol->set_expand (true); hviewcol->set_resizable (true); hviewcol->set_fixed_width (35); hviewcol->set_min_width (35); hviewcol->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); Gtk::TreeView::Column *hviewcol2 = Gtk::manage (new Gtk::TreeView::Column ("")); hviewcol2->pack_start (*valuecrt, true); hviewcol2->add_attribute (valuecrt->property_markup (), historyColumns.value); hviewcol2->set_expand (true); hviewcol2->set_resizable (true); hviewcol2->set_fixed_width (35); hviewcol2->set_min_width (35); hviewcol2->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE); valuecrt->set_alignment (1.f, 0.f); hTreeView->set_has_tooltip (true); hTreeView->signal_query_tooltip().connect ( sigc::mem_fun (*this, &History::on_query_tooltip) ); hTreeView->append_column (*hviewcol); hTreeView->append_column (*hviewcol2); selchangehist = hTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::historySelectionChanged)); // Bookmark List // ~~~~~~~~~~~~~ Gtk::Box* ahbox = Gtk::manage (new Gtk::Box ()); addBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_NEWSNAPSHOT") setExpandAlignProperties (addBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //addBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_RIGHT); addBookmark->get_style_context()->add_class ("Left"); addBookmark->set_tooltip_markup (M ("HISTORY_NEWSNAPSHOT_TOOLTIP")); Gtk::Image* addimg = Gtk::manage (new RTImage ("add-small.png")); addBookmark->set_image (*addimg); ahbox->pack_start (*addBookmark); delBookmark = Gtk::manage (new Gtk::Button ()); // M("HISTORY_DELSNAPSHOT") setExpandAlignProperties (delBookmark, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); //delBookmark->get_style_context()->set_junction_sides(Gtk::JUNCTION_LEFT); delBookmark->get_style_context()->add_class ("Right"); Gtk::Image* delimg = Gtk::manage (new RTImage ("remove-small.png")); delBookmark->set_image (*delimg); ahbox->pack_start (*delBookmark); bscrollw = Gtk::manage (new Gtk::ScrolledWindow ()); // bscrollw->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); bscrollw->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); bscrollw->set_size_request (-1, 45); Gtk::Frame* bmFrame = Gtk::manage (new Gtk::Frame (M ("HISTORY_SNAPSHOTS"))); bmFrame->set_name ("Snapshots"); Gtk::Box* bmBox = Gtk::manage (new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); bmFrame->add (*bmBox); bmBox->pack_start (*bscrollw, Gtk::PACK_EXPAND_WIDGET, 4); bmBox->pack_end (*ahbox, Gtk::PACK_SHRINK, 4); bmBox->set_size_request (-1, 60); if (bookmarkSupport) { historyVPaned = Gtk::manage ( new Gtk::Paned (Gtk::ORIENTATION_VERTICAL) ); historyVPaned->pack1 (*histFrame, true, false); historyVPaned->pack2 (*bmFrame, false, false); pack_start (*historyVPaned); } else { pack_start (*histFrame); } bTreeView = Gtk::manage (new Gtk::TreeView ()); bscrollw->add (*bTreeView); bookmarkModel = Gtk::ListStore::create (bookmarkColumns); bTreeView->set_model (bookmarkModel); bTreeView->set_headers_visible (false); bTreeView->append_column_editable (M ("HISTORY_SNAPSHOTS"), bookmarkColumns.text); selchangebm = bTreeView->get_selection()->signal_changed().connect (sigc::mem_fun (*this, &History::bookmarkSelectionChanged)); addBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::addBookmarkPressed) ); delBookmark->signal_clicked().connect ( sigc::mem_fun (*this, &History::delBookmarkPressed) ); //hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_HORIZONTAL); hTreeView->set_grid_lines (Gtk::TREE_VIEW_GRID_LINES_BOTH); //hTreeView->signal_size_allocate().connect( sigc::mem_fun(*this, &History::resized) ); hTreeView->set_enable_search (false); bTreeView->set_enable_search (false); show_all_children (); } void History::initHistory () { ConnectionBlocker selBlocker (selchangehist); historyModel->clear (); bookmarkModel->clear (); } void History::historySelectionChanged () { Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; if (row) { bTreeView->get_selection()->unselect_all (); } if (row && tpc) { ProcParams pparams = row[historyColumns.params]; ParamsEdited pe (true); pe.locallab.spots.resize(pparams.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; tpc->profileChange (&pp, EvHistoryBrowsed, row[historyColumns.text], ¶msEdited); } if (blistener && !blistenerLock) { Gtk::TreeModel::Path path = historyModel->get_path (iter); path.prev (); iter = historyModel->get_iter (path); if (blistener && iter) { blistener->historyBeforeLineChanged (iter->get_value (historyColumns.params)); } } } } void History::bookmarkSelectionChanged () { Glib::RefPtr selection = bTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; if (row) { hTreeView->get_selection()->unselect_all (); } if (row && tpc) { ProcParams pparams = row[bookmarkColumns.params]; ParamsEdited pe (true); pe.locallab.spots.resize(pparams.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited]; tpc->profileChange (&pp, EvBookmarkSelected, row[bookmarkColumns.text], ¶msEdited); } } } void History::procParamsChanged( const ProcParams* params, const ProcEvent& ev, const Glib::ustring& descr, const ParamsEdited* paramsEdited ) { // to prevent recursion, we filter out the events triggered by the history and events that should not be registered if (ev == EvHistoryBrowsed || ev == EvMonitorTransform || descr == "") { return; } selchangehist.block(true); selchangebm.block(true); if (ev == EvPhotoLoaded) { initHistory(); } // construct formatted list content Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); // remove all rows after the selection if (iter) { ++iter; while (iter) { iter = historyModel->erase(iter); } } // lookup the last remaining item in the list const int size = historyModel->children().size(); Gtk::TreeModel::Row row; if (size > 0) { row = historyModel->children()[size - 1]; } // if there is no last item or its chev!=ev, create a new one if (size == 0 || !row || row[historyColumns.chev] != ev || ev == EvProfileChanged || ev == EvLocallabSpotCreated || ev == EvLocallabSpotDeleted) { // Special cases: If Locallab spot is created , deleted or duplicated several times in a row, a new history row is used Gtk::TreeModel::Row newrow = * (historyModel->append()); newrow[historyColumns.text] = ProcEventMapper::getInstance()->getHistoryMsg(ev); newrow[historyColumns.value] = g_markup_escape_text (descr.c_str(), -1); newrow[historyColumns.chev] = ev; newrow[historyColumns.params] = *params; newrow[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; if (ev != EvBookmarkSelected) { selection->select(newrow); } if (blistener && row && !blistenerLock) { blistener->historyBeforeLineChanged(row[historyColumns.params]); } else if (blistener && size == 0 && !blistenerLock) { blistener->historyBeforeLineChanged(newrow[historyColumns.params]); } } else { // else just update it row[historyColumns.value] = g_markup_escape_text(descr.c_str(), -1); row[historyColumns.params] = *params; row[historyColumns.paramsEdited] = paramsEdited ? *paramsEdited : defParamsEdited; if (ev != EvBookmarkSelected) { selection->select(row); } } if (ev != EvBookmarkSelected) { bTreeView->get_selection()->unselect_all(); } if (!selection->get_selected_rows().empty()) { std::vector selp = selection->get_selected_rows(); hTreeView->scroll_to_row(*selp.begin()); } selchangehist.block(false); selchangebm.block(false); } void History::clearParamChanges () { initHistory (); } void History::addBookmarkWithText (Glib::ustring text) { // lookup the selected item in the history Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); Gtk::TreeModel::Row row = *iter; if (!row) { return; } // append new row to bookmarks Gtk::TreeModel::Row newrow = * (bookmarkModel->append()); newrow[bookmarkColumns.text] = text; ProcParams params = row[historyColumns.params]; newrow[bookmarkColumns.params] = params; ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; newrow[bookmarkColumns.paramsEdited] = paramsEdited; } void History::addBookmarkPressed () { if (hTreeView->get_selection()->get_selected()) { addBookmarkWithText (Glib::ustring::compose ("%1 %2", M ("HISTORY_SNAPSHOT"), bmnum++)); } } void History::delBookmarkPressed () { // lookup the selected item in the bookmark Glib::RefPtr selection = bTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); if (!iter) { return; } // remove selected bookmark bookmarkModel->erase (iter); // select last item in history int size = historyModel->children().size (); Gtk::TreeModel::Row row = historyModel->children()[size - 1]; hTreeView->get_selection()->select (row); } void History::undo () { Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); if (iter && iter != historyModel->children().begin()) { selection->select (--iter); } else if (!iter) { int size = historyModel->children().size (); if (size > 1) { selection->select (historyModel->children().operator [] (size - 2)); } } } void History::redo () { Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); if (iter) { ++iter; if (iter != historyModel->children().end()) { selection->select (iter); } } else { int size = historyModel->children().size (); if (size > 1) { selection->select (historyModel->children().operator [] (size - 2)); } } } /* void History::resized (Gtk::Allocation& req) { } */ bool History::getBeforeLineParams (rtengine::procparams::ProcParams& params) { int size = historyModel->children().size (); if (size == 0 || !blistener) { return false; } Gtk::TreeModel::Row row; row = historyModel->children()[size == 1 ? 0 : size - 2]; params = row[historyColumns.params]; return true; } bool History::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { bool displayTooltip = false; Gtk::TreeModel::Path path; int x2 = -1; int y2 = -1; hTreeView->convert_widget_to_bin_window_coords (x, y, x2, y2); bool hasPath = hTreeView->get_path_at_pos (x2, y2, path); if (hasPath) { if (path && !path.empty()) { Gtk::TreeModel::iterator iter = historyModel->get_iter (path); if (iter) { // Glib::ustring param, val; // iter->get_value (1, param); // iter->get_value (2, val); Glib::ustring text, val; iter->get_value (0, text); iter->get_value (1, val); /* * * * Why this doesn't work ??? * * * Gtk::Label *left = Gtk::manage (new Gtk::Label(param+" :")); Gtk::Label *right = Gtk::manage (new Gtk::Label(val)); right->set_justify(Gtk::JUSTIFY_LEFT); Gtk::Box *hbox = Gtk::manage (new Gtk::Box()); hbox->set_spacing(5); hbox->pack_start(*left, Gtk::PACK_SHRINK, 0); hbox->pack_start(*right, Gtk::PACK_SHRINK, 0); tooltip->set_custom(*hbox); */ // tooltip->set_text (param + " : " + val); tooltip->set_text (text + " : " + val); displayTooltip = true; } } } return displayTooltip; }