1 /*
2 * This file is part of RawTherapee.
3 *
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5 *
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
18 *
19 * Class created by Jean-Christophe FRISCH, aka 'Hombre'
20 */
21
22 #include <gtkmm.h>
23 #include "multilangmgr.h"
24 #include "popupcommon.h"
25 #include "rtimage.h"
26 #include "guiutils.h"
27
PopUpCommon(Gtk::Button * thisButton,const Glib::ustring & label)28 PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label)
29 : buttonImage (nullptr)
30 , menu (nullptr)
31 , selected (-1) // -1 means that the button is invalid
32 {
33 button = thisButton;
34 hasMenu = false;
35 imageContainer = Gtk::manage( new Gtk::Grid());
36 setExpandAlignProperties(imageContainer, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
37 button->set_relief (Gtk::RELIEF_NORMAL);
38 button->add(*imageContainer);
39
40 if (!label.empty()) {
41 Gtk::Label* buttonLabel = Gtk::manage ( new Gtk::Label(label + " ") );
42 setExpandAlignProperties(buttonLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
43 imageContainer->attach(*buttonLabel, 0, 0, 1, 1);
44 }
45
46 // Create the global container and put the button in it
47 buttonGroup = Gtk::manage( new Gtk::Grid());
48 setExpandAlignProperties(buttonGroup, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
49 buttonGroup->attach(*button, 0, 0, 1, 1);
50 buttonGroup->get_style_context()->add_class("image-combo");
51 }
52
~PopUpCommon()53 PopUpCommon::~PopUpCommon ()
54 {
55 delete menu;
56 delete buttonImage;
57 }
58
addEntry(const Glib::ustring & fileName,const Glib::ustring & label)59 bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label)
60 {
61 if (label.empty ())
62 return false;
63
64 // Create the menu item and image
65 MyImageMenuItem* newItem = Gtk::manage (new MyImageMenuItem (label, fileName));
66 imageFilenames.push_back (fileName);
67 images.push_back (newItem->getImage ());
68
69 if (selected == -1) {
70 // Create the menu on the first item
71 menu = new Gtk::Menu ();
72 // Create the image for the button
73 buttonImage = new RTImage(fileName);
74 setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
75 // Use the first image by default
76 imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1);
77 selected = 0;
78 }
79
80 // When there is at least 1 choice, we add the arrow button
81 if (images.size() == 1) {
82 Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() );
83 Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image());
84 arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON);
85 setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
86 arrowButton->add(*arrowImage); //menuSymbol);
87 buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1);
88 arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) );
89 button->get_style_context()->add_class("Left");
90 arrowButton->get_style_context()->add_class("Right");
91 arrowButton->get_style_context()->add_class("popupbutton-arrow");
92 hasMenu = true;
93 }
94
95 newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &PopUpCommon::entrySelected), images.size () - 1));
96 menu->append (*newItem);
97
98 return true;
99 }
100
101 // TODO: 'PopUpCommon::removeEntry' method to be created...
102
entrySelected(int i)103 void PopUpCommon::entrySelected (int i)
104 {
105 // Emit a signal if the selected item has changed
106 if (setSelected (posToIndex(i)))
107 messageChanged (posToIndex(selected));
108
109 // Emit a signal in all case (i.e. propagate the signal_activate event)
110 messageItemSelected (posToIndex(selected));
111 }
112
setItemSensitivity(int index,bool isSensitive)113 void PopUpCommon::setItemSensitivity (int index, bool isSensitive) {
114 const auto items = menu->get_children ();
115 size_t pos = indexToPos(index);
116 if (pos < items.size ()) {
117 items[pos]->set_sensitive (isSensitive);
118 }
119 }
120
121
122 /*
123 * Set the button image with the selected item
124 */
setSelected(int entryNum)125 bool PopUpCommon::setSelected (int entryNum)
126 {
127 entryNum = indexToPos(entryNum);
128
129 if (entryNum < 0 || entryNum > ((int)images.size() - 1) || (int)entryNum == selected) {
130 return false;
131 } else {
132 // Maybe we could do something better than loading the image file each time the selection is changed !?
133 buttonImage->changeImage(imageFilenames.at(entryNum));
134 selected = entryNum;
135 setButtonHint();
136 return true;
137 }
138 }
139
show()140 void PopUpCommon::show()
141 {
142 menu->reposition();
143 setButtonHint();
144 menu->show_all();
145 buttonGroup->show_all();
146 }
147
setButtonHint()148 void PopUpCommon::setButtonHint()
149 {
150 Glib::ustring hint;
151
152 if (!buttonHint.empty()) {
153 hint = buttonHint;
154
155 if (selected > -1) {
156 hint += " ";
157 }
158 }
159
160 if (selected > -1) {
161 auto widget = menu->get_children ()[selected];
162 auto item = dynamic_cast<MyImageMenuItem*>(widget);
163
164 if (item) {
165 hint += item->getLabel ()->get_text ();
166 }
167 }
168
169 button->set_tooltip_markup(hint);
170 }
171
showMenu(GdkEventButton * event)172 void PopUpCommon::showMenu(GdkEventButton* event)
173 {
174 if (event->button == 1) {
175 menu->popup(event->button, event->time);
176 }
177 }
178
set_tooltip_text(const Glib::ustring & text)179 void PopUpCommon::set_tooltip_text (const Glib::ustring &text)
180 {
181 buttonHint = text;
182 setButtonHint();
183 }
184