Proper check for rawzor libraries.
[rawtherapee-fixes.git] / rtgui / thumbbrowserbase.cc
blob4bf43c5564a1f6d3d169282dffc03051e52bd7eb
1 /*
2 * This file is part of RawTherapee.
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 #include <thumbbrowserbase.h>
20 #include <glibmm.h>
21 #include <multilangmgr.h>
22 #include <options.h>
23 #include <mytime.h>
25 ThumbBrowserBase::ThumbBrowserBase ()
26 : previewHeight(options.thumbSize), lastClicked(NULL) {
28 inW = -1; inH = -1;
30 Gtk::HBox* hb1 = new Gtk::HBox ();
31 Gtk::HBox* hb2 = new Gtk::HBox ();
32 Gtk::Frame* frame = new Gtk::Frame ();
33 frame->add (internal);
34 frame->set_shadow_type (Gtk::SHADOW_IN );
35 hb1->pack_start (*frame);
36 hb1->pack_end (vscroll, Gtk::PACK_SHRINK, 0);
38 pack_start (*hb1);
40 Gtk::HBox* tmp = new Gtk::HBox ();
41 hb2->pack_start (hscroll);
42 Gtk::Requisition vcr = vscroll.size_request ();
43 tmp->set_size_request (vcr.width, vcr.width);
44 hb2->pack_end (*tmp, Gtk::PACK_SHRINK, 0);
46 pack_start (*hb2,Gtk::PACK_SHRINK, 0);
48 internal.setParent (this);
50 show_all ();
52 hscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS);
53 vscroll.set_update_policy (Gtk::UPDATE_CONTINUOUS);
55 vscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) );
56 hscroll.signal_value_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::scrollChanged) );
58 internal.signal_size_allocate().connect( sigc::mem_fun(*this, &ThumbBrowserBase::internalAreaResized) );
59 signal_style_changed().connect( sigc::mem_fun(*this, &ThumbBrowserBase::styleChanged) );
62 void ThumbBrowserBase::scrollChanged () {
64 for (int i=0; i<fd.size(); i++)
65 fd[i]->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
67 internal.setPosition ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
69 if (!internal.isDirty()) {
70 internal.setDirty ();
71 internal.queue_draw ();
72 // gdk_window_process_updates (get_window()->gobj(), true);
76 void ThumbBrowserBase::scroll (int direction) {
78 if (arrangement==TB_Vertical)
79 vscroll.set_value (vscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * vscroll.get_adjustment()->get_step_increment());
80 else
81 hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_step_increment());
84 void ThumbBrowserBase::resizeThumbnailArea (int w, int h) {
86 inW = w;
87 inH = h;
89 if (hscroll.get_value() + internal.get_width() > inW)
90 hscroll.set_value (inW - internal.get_width());
91 if (vscroll.get_value() + internal.get_height() > inH)
92 vscroll.set_value (inH - internal.get_height());
94 configScrollBars ();
97 void ThumbBrowserBase::internalAreaResized (Gtk::Allocation& req) {
99 if (inW>0 && inH>0) {
100 configScrollBars ();
101 redraw ();
105 void ThumbBrowserBase::configScrollBars () {
107 if (inW>0 && inH>0) {
109 int iw = internal.get_width ();
110 int ih = internal.get_height ();
112 hscroll.get_adjustment()->set_upper (inW);
113 vscroll.get_adjustment()->set_upper (inH);
114 hscroll.get_adjustment()->set_lower (0);
115 vscroll.get_adjustment()->set_lower (0);
116 hscroll.get_adjustment()->set_step_increment (32);
117 vscroll.get_adjustment()->set_step_increment (32);
118 hscroll.get_adjustment()->set_page_increment (iw);
119 vscroll.get_adjustment()->set_page_increment (ih);
120 hscroll.get_adjustment()->set_page_size (iw);
121 vscroll.get_adjustment()->set_page_size (ih);
125 void ThumbBrowserBase::arrangeFiles () {
127 int N = fd.size ();
128 // apply filter
129 for (int i=0; i<N; i++)
130 fd[i]->filtered = !checkFilter (fd[i]);
132 int rowHeight = 0;
133 // compute size of the items
134 for (int i=0; i<N; i++)
135 if (!fd[i]->filtered && fd[i]->getMinimalHeight() > rowHeight)
136 rowHeight = fd[i]->getMinimalHeight ();
138 if (arrangement==TB_Horizontal) {
140 int numOfRows = 1;
141 if (rowHeight>0) {
142 numOfRows = (internal.get_height()+rowHeight/2)/rowHeight;
143 if (numOfRows<1)
144 numOfRows = 1;
147 int ct = 0;
148 int currx = 0; int curry = 0;
149 while (ct<N) {
150 // find widest item in the column
151 int maxw = 0;
152 for (int i=0; ct+i<N && i<numOfRows; i++)
153 if (fd[ct+i]->getMinimalWidth() > maxw)
154 maxw = fd[ct+i]->getMinimalWidth ();
156 // arrange items in the column
157 curry = 0;
158 for (int i=0; ct<N && i<numOfRows; i++, ct++) {
159 while (ct<N && fd[ct]->filtered)
160 fd[ct++]->drawable = false;
161 if (ct<N) {
162 fd[ct]->setPosition (currx, curry, maxw, rowHeight);
163 fd[ct]->drawable = true;
164 curry += rowHeight;
167 currx += maxw;
169 resizeThumbnailArea (currx, numOfRows*rowHeight);
171 else {
172 int availWidth = internal.get_width();
173 // initial number of columns
174 int numOfCols = 0;
175 int currColNum = 0;
176 int colsWidth = 0;
177 for (int i=0; i<N; i++)
178 if (!fd[i]->filtered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) {
179 colsWidth += fd[numOfCols]->getMinimalWidth ();
180 numOfCols++;
182 if (numOfCols<1)
183 numOfCols = 1;
184 std::vector<int> colWidths;
185 for (; numOfCols>0; numOfCols--) {
186 // compute column widths
187 colWidths.resize (numOfCols);
188 for (int i=0; i<numOfCols; i++)
189 colWidths[i] = 0;
190 for (int i=0, j=0; i<N; i++) {
191 if (!fd[i]->filtered && fd[i]->getMinimalWidth() > colWidths[j%numOfCols])
192 colWidths[j%numOfCols] = fd[i]->getMinimalWidth ();
193 if (!fd[i]->filtered)
194 j++;
196 // if not wider than the space available, arrange it and we are ready
197 colsWidth = 0;
198 for (int i=0; i<numOfCols; i++)
199 colsWidth += colWidths[i];
200 if (numOfCols==1 || colsWidth < availWidth)
201 break;
203 // arrange files
204 int ct = 0;
205 int currx = 0; int curry = 0;
206 while (ct<N) {
207 // arrange items in the row
208 currx = 0;
209 for (int i=0; ct<N && i<numOfCols; i++, ct++) {
210 while (ct<N && fd[ct]->filtered)
211 fd[ct++]->drawable = false;
212 if (ct<N) {
213 fd[ct]->setPosition (currx, curry, colWidths[i%numOfCols], rowHeight);
214 fd[ct]->drawable = true;
215 currx += colWidths[i%numOfCols];
218 if (currx>0) // there were thumbnails placed in the row
219 curry += rowHeight;
221 resizeThumbnailArea (colsWidth, curry);
226 void ThumbBrowserBase::Internal::on_realize()
228 Cairo::FontOptions cfo;
229 cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
230 get_pango_context()->set_cairo_font_options (cfo);
232 Gtk::DrawingArea::on_realize();
233 Glib::RefPtr<Gdk::Window> window = get_window();
234 set_flags (Gtk::CAN_FOCUS);
235 add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK);
236 gc_ = Gdk::GC::create(window);
237 set_has_tooltip (true);
238 signal_query_tooltip().connect( sigc::mem_fun(*this, &ThumbBrowserBase::Internal::on_query_tooltip) );
241 bool ThumbBrowserBase::Internal::on_query_tooltip (int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) {
243 Glib::ustring ttip = "";
244 for (int i=0; i<parent->fd.size(); i++)
245 if (parent->fd[i]->drawable && parent->fd[i]->inside (x, y)) {
246 ttip = parent->fd[i]->getToolTip (x, y);
247 break;
249 if (ttip!="") {
250 tooltip->set_text (ttip);
251 return true;
253 else
254 return false;
257 void ThumbBrowserBase::styleChanged (const Glib::RefPtr<Gtk::Style>& style) {
259 refreshThumbImages ();
262 ThumbBrowserBase::Internal::Internal () : parent(NULL), ofsX(0), ofsY(0), dirty(true) {
265 void ThumbBrowserBase::Internal::setParent (ThumbBrowserBase* p) {
267 parent = p;
270 void ThumbBrowserBase::Internal::setPosition (int x, int y) {
272 ofsX = x;
273 ofsY = y;
276 bool ThumbBrowserBase::Internal::on_key_press_event (GdkEventKey* event) {
278 return parent->keyPressed (event);
281 bool ThumbBrowserBase::Internal::on_button_press_event (GdkEventButton* event) {
283 grab_focus ();
285 parent->eventTime = event->time;
287 parent->buttonPressed ((int)event->x, (int)event->y, event->button, event->type, event->state, 0, 0, get_width(), get_height());
288 Glib::RefPtr<Gdk::Window> window = get_window();
290 GdkRectangle rect;
291 rect.x = 0;
292 rect.y = 0;
293 window->get_size (rect.width, rect.height);
295 gdk_window_invalidate_rect (window->gobj(), &rect, true);
296 gdk_window_process_updates (window->gobj(), true);
297 return true;
300 void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType type, int state, int clx, int cly, int clw, int clh) {
302 ThumbBrowserEntryBase* fileDescr = NULL;
303 bool handled = false;
304 for (int i=0; i<fd.size(); i++)
305 if (fd[i]->drawable) {
306 if (fd[i]->inside (x, y) && fd[i]->insideWindow (clx, cly, clw, clh))
307 fileDescr = fd[i];
308 bool b = fd[i]->pressNotify (button, type, state, x, y);
309 handled = handled || b;
312 if (handled || (fileDescr && fileDescr->processing))
313 return;
315 if (selected.size()==1 && type==GDK_2BUTTON_PRESS && button==1)
316 doubleClicked (selected[0]);
317 else if (button==1 && type==GDK_BUTTON_PRESS) {
318 if (fileDescr && state & GDK_SHIFT_MASK) {
319 if (selected.size()==0) {
320 selected.push_back (fileDescr);
321 fileDescr->selected = true;
322 lastClicked = fileDescr;
323 selectionChanged ();
325 else {
326 // find the start and the end of the selection interval
327 int startx = fd.size()-1;
328 if (lastClicked) {
329 for (; startx>=0; startx--)
330 if (fd[startx]==lastClicked)
331 break;
333 else {
334 for (; startx>=0; startx--)
335 if (fd[startx]==selected[0])
336 break;
338 int endx = 0;
339 for (; endx<fd.size(); endx++)
340 if (fd[endx]==fileDescr)
341 break;
342 if (endx < startx) {
343 int tmp = endx;
344 endx = startx;
345 startx = tmp;
347 // clear current selection
348 for (int i=0; i<selected.size(); i++)
349 selected[i]->selected = false;
350 selected.clear ();
351 // select thumbnails in the interval
352 for (int i=startx; i<=endx; i++) {
353 if (!fd[i]->filtered) {
354 fd[i]->selected = true;
355 selected.push_back (fd[i]);
358 selectionChanged ();
361 else if (fileDescr && state & GDK_CONTROL_MASK) {
362 std::vector<ThumbBrowserEntryBase*>::iterator i = std::find (selected.begin(), selected.end(), fileDescr);
363 if (i!=selected.end()) {
364 (*i)->selected = false;
365 selected.erase (i);
367 else {
368 selected.push_back (fileDescr);
369 fileDescr->selected = true;
371 lastClicked = fileDescr;
372 selectionChanged ();
374 else {
375 for (int i=0; i<selected.size(); i++)
376 selected[i]->selected = false;
377 selected.clear ();
378 if (fileDescr) {
379 selected.push_back (fileDescr);
380 fileDescr->selected = true;
382 lastClicked = fileDescr;
383 selectionChanged ();
386 else if (fileDescr && button==3 && type==GDK_BUTTON_PRESS) {
387 if (!fileDescr->selected) {
388 for (int i=0; i<selected.size(); i++)
389 selected[i]->selected = false;
390 selected.clear ();
391 fileDescr->selected = true;
392 selected.push_back (fileDescr);
393 lastClicked = fileDescr;
394 selectionChanged ();
396 rightClicked (fileDescr);
400 bool ThumbBrowserBase::Internal::on_expose_event(GdkEventExpose* event) {
402 dirty = false;
404 Glib::RefPtr<Gdk::Window> window = get_window();
406 int w = get_width();
407 int h = get_height();
409 window->clear();
410 // draw thumbnails
411 Glib::RefPtr<Pango::Context> context = get_pango_context ();
412 context->set_font_description (get_style()->get_font());
413 for (int i=0; i<parent->fd.size(); i++) {
414 if (!parent->fd[i]->drawable || !parent->fd[i]->insideWindow (0, 0, w, h))
415 parent->fd[i]->updatepriority = false;
416 else {
417 parent->fd[i]->updatepriority = true;
418 parent->fd[i]->draw ();
422 return true;
425 bool ThumbBrowserBase::Internal::on_button_release_event (GdkEventButton* event) {
427 int w = get_width();
428 int h = get_height();
430 for (int i=0; i<parent->fd.size(); i++)
431 if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h))
432 parent->fd[i]->releaseNotify (event->button, event->type, event->state, (int)event->x, (int)event->y);
433 return true;
436 bool ThumbBrowserBase::Internal::on_motion_notify_event (GdkEventMotion* event) {
438 int w = get_width();
439 int h = get_height();
441 for (int i=0; i<parent->fd.size(); i++)
442 if (parent->fd[i]->drawable && parent->fd[i]->insideWindow (0, 0, w, h))
443 parent->fd[i]->motionNotify ((int)event->x, (int)event->y);
444 return true;
447 bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) {
449 parent->scroll (event->direction);
450 return true;
454 void ThumbBrowserBase::redraw () {
456 arrangeFiles ();
457 queue_draw ();
460 void ThumbBrowserBase::zoomChanged (bool zoomIn) {
462 int newHeight;
463 int i=0;
464 if (zoomIn)
465 for (i=0; i<options.thumbnailZoomRatios.size(); i++) {
466 newHeight = (int)(options.thumbnailZoomRatios[i] * options.maxThumbnailHeight);
467 if (newHeight > options.thumbSize)
468 break;
470 else
471 for (i=options.thumbnailZoomRatios.size()-1; i>=0; i--) {
472 newHeight = (int)(options.thumbnailZoomRatios[i] * options.maxThumbnailHeight);
473 if (newHeight < options.thumbSize)
474 break;
476 previewHeight = options.thumbSize = newHeight;
477 for (int i=0; i<fd.size(); i++)
478 fd[i]->resize (previewHeight);
479 redraw ();
480 #ifdef _WIN32
481 gdk_window_process_updates (get_window()->gobj(), true);
482 #endif
484 void ThumbBrowserBase::refreshThumbImages () {
486 for (int i=0; i<fd.size(); i++)
487 fd[i]->refreshThumbnailImage ();
489 redraw ();
492 void ThumbBrowserBase::refreshEditedState (const std::set<Glib::ustring>& efiles) {
494 editedFiles = efiles;
495 for (int i=0; i<fd.size(); i++)
496 fd[i]->framed = editedFiles.find (fd[i]->filename)!=editedFiles.end();
497 queue_draw ();
500 void ThumbBrowserBase::setArrangement (Arrangement a) {
502 arrangement = a;
503 redraw ();
506 void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) {
508 entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value()));
510 void ThumbBrowserBase::getScrollPosition (double& h, double& v) {
512 h = hscroll.get_value ();
513 v = vscroll.get_value ();
516 void ThumbBrowserBase::setScrollPosition (double h, double v) {
518 hscroll.set_value (h>hscroll.get_adjustment()->get_upper() ? hscroll.get_adjustment()->get_upper() : h);
519 vscroll.set_value (v>vscroll.get_adjustment()->get_upper() ? vscroll.get_adjustment()->get_upper() : v);
522 /*void PreviewImgUpdater::processCustomOrder () {
524 // find first filtered entry, if any
525 std::list<ThumbBrowserEntryBase*>::iterator i;
526 for (i=jqueue.begin (); i!=jqueue.end(); i++)
527 if (!(*i)->filtered)
528 break;
529 if (i==jqueue.end())
530 i = jqueue.begin();
532 ThumbBrowserEntryBase* current = *i;
533 jqueue.erase (i);
535 current->updateImg ();
536 if (parent) {
537 gdk_threads_enter ();
538 parent->queue_draw ();
539 if (parent->get_window())
540 gdk_window_process_updates (parent->get_window()->gobj(), true);
541 gdk_threads_leave ();