From 88ab82cee9073b0cc7abcfef172433b7dccb6f48 Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sat, 28 Nov 2015 23:21:17 +0100 Subject: [PATCH 1/2] Factor out the three thumbnail browser selection modes without changing their behaviour. --- rtgui/threadutils.h | 16 +++ rtgui/thumbbrowserbase.cc | 202 +++++++++++++++++--------------------- rtgui/thumbbrowserbase.h | 6 ++ 3 files changed, 114 insertions(+), 110 deletions(-) diff --git a/rtgui/threadutils.h b/rtgui/threadutils.h index b7231d5de..e8ef2f29e 100644 --- a/rtgui/threadutils.h +++ b/rtgui/threadutils.h @@ -704,4 +704,20 @@ public: #define MYWRITERLOCK_RELEASE(ln) ln.release(); #endif +#ifdef PROTECT_VECTORS +#define IFPV_MYREADERLOCK(l, e) MYREADERLOCK(l, e) +#define IFPV_MYWRITERLOCK(l, e) MYWRITERLOCK(l, e) +#define IFPV_MYREADERLOCK_ACQUIRE(l) MYREADERLOCK_ACQUIRE(l) +#define IFPV_MYWRITERLOCK_ACQUIRE(l) MYWRITERLOCK_ACQUIRE(l) +#define IFPV_MYREADERLOCK_RELEASE(l) MYREADERLOCK_RELEASE(l) +#define IFPV_MYWRITERLOCK_RELEASE(l) MYWRITERLOCK_RELEASE(l) +#else +#define IFPV_MYREADERLOCK(l, e) +#define IFPV_MYWRITERLOCK(l, e) +#define IFPV_MYREADERLOCK_ACQUIRE(l) +#define IFPV_MYWRITERLOCK_ACQUIRE(l) +#define IFPV_MYREADERLOCK_RELEASE(l) +#define IFPV_MYWRITERLOCK_RELEASE(l) +#endif + #endif /* _THREADUTILS_ */ diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index c2ed480f2..ed6366266 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -98,6 +98,84 @@ void ThumbBrowserBase::scrollPage (int direction) } } +void ThumbBrowserBase::selectSingle (ThumbBrowserEntryBase* fileDescr) +{ + for (size_t i = 0; i < selected.size(); i++) { + selected[i]->selected = false; + } + + selected.clear (); + + if (fileDescr) { + selected.push_back (fileDescr); + fileDescr->selected = true; + } +} + +void ThumbBrowserBase::selectRange (ThumbBrowserEntryBase* fileDescr) +{ + if (selected.empty()) { + selected.push_back (fileDescr); + fileDescr->selected = true; + } else { + // find the start and the end of the selection interval + size_t startx = fd.size() - 1; + + if (lastClicked) { + for (; startx > 0; startx--) + if (fd[startx] == lastClicked) { + break; + } + } else { + for (; startx > 0; startx--) + if (fd[startx] == selected[0]) { + break; + } + } + + size_t endx = 0; + + for (; endx < fd.size(); endx++) + if (fd[endx] == fileDescr) { + break; + } + + if (endx < startx) { + int tmp = endx; + endx = startx; + startx = tmp; + } + + // clear current selection + for (size_t i = 0; i < selected.size(); i++) { + selected[i]->selected = false; + } + + selected.clear (); + + // select thumbnails in the interval + for (size_t i = startx; i <= endx; i++) { + if (!fd[i]->filtered) { + fd[i]->selected = true; + selected.push_back (fd[i]); + } + } + } +} + +void ThumbBrowserBase::selectSet (ThumbBrowserEntryBase* fileDescr) +{ + std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); + + if (i != selected.end()) { + (*i)->selected = false; + selected.erase (i); + } else { + selected.push_back (fileDescr); + fileDescr->selected = true; + } +} + static void scrollToEntry (double& h, double& v, int iw, int ih, ThumbBrowserEntryBase* entry) { const int hmin = entry->getX (); @@ -726,9 +804,7 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ bool handled = false; { -#if PROTECT_VECTORS - MYREADERLOCK(l, entryRW); -#endif + IFPV_MYREADERLOCK(l, entryRW); for (size_t i = 0; i < fd.size(); i++) if (fd[i]->drawable) { @@ -746,125 +822,31 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ } { -#if PROTECT_VECTORS - MYWRITERLOCK(l, entryRW); -#endif + IFPV_MYWRITERLOCK(l, entryRW); if (selected.size() == 1 && type == GDK_2BUTTON_PRESS && button == 1) { doubleClicked (selected[0]); } else if (button == 1 && type == GDK_BUTTON_PRESS) { - if (fileDescr && (state & GDK_SHIFT_MASK)) { - if (selected.empty()) { - selected.push_back (fileDescr); - fileDescr->selected = true; - lastClicked = fileDescr; -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif - selectionChanged (); - } else { - // find the start and the end of the selection interval - size_t startx = fd.size() - 1; + if (fileDescr && (state & GDK_SHIFT_MASK)) + selectRange (fileDescr); + else if (fileDescr && (state & GDK_CONTROL_MASK)) + selectSet (fileDescr); + else + selectSingle (fileDescr); - if (lastClicked) { - for (; startx > 0; startx--) - if (fd[startx] == lastClicked) { - break; - } - } else { - for (; startx > 0; startx--) - if (fd[startx] == selected[0]) { - break; - } - } - - size_t endx = 0; - - for (; endx < fd.size(); endx++) - if (fd[endx] == fileDescr) { - break; - } - - if (endx < startx) { - int tmp = endx; - endx = startx; - startx = tmp; - } - - // clear current selection - for (size_t i = 0; i < selected.size(); i++) { - selected[i]->selected = false; - } - - selected.clear (); - - // select thumbnails in the interval - for (size_t i = startx; i <= endx; i++) { - if (!fd[i]->filtered) { - fd[i]->selected = true; - selected.push_back (fd[i]); - } - } - - lastClicked = fileDescr; -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif - selectionChanged (); - } - } else if (fileDescr && (state & GDK_CONTROL_MASK)) { - std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); - - if (i != selected.end()) { - (*i)->selected = false; - selected.erase (i); - } else { - selected.push_back (fileDescr); - fileDescr->selected = true; - } - - lastClicked = fileDescr; -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif - selectionChanged (); - } else { - for (size_t i = 0; i < selected.size(); i++) { - selected[i]->selected = false; - } - - selected.clear (); - - if (fileDescr) { - selected.push_back (fileDescr); - fileDescr->selected = true; - } - - lastClicked = fileDescr; -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif - selectionChanged (); - } + lastClicked = fileDescr; + IFPV_MYWRITERLOCK_RELEASE(l); + selectionChanged (); } else if (fileDescr && button == 3 && type == GDK_BUTTON_PRESS) { if (!fileDescr->selected) { - for (size_t i = 0; i < selected.size(); i++) { - selected[i]->selected = false; - } + selectSingle (fileDescr); - selected.clear (); - fileDescr->selected = true; - selected.push_back (fileDescr); lastClicked = fileDescr; -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif + IFPV_MYWRITERLOCK_RELEASE(l); selectionChanged (); } -#if PROTECT_VECTORS - MYWRITERLOCK_RELEASE(l); -#endif + IFPV_MYWRITERLOCK_RELEASE(l); rightClicked (fileDescr); } } // end of MYWRITERLOCK(l, entryRW); diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index bd410292d..ee11f550e 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -110,6 +110,12 @@ public: void scroll (int direction); void scrollPage (int direction); +private: + void selectSingle (ThumbBrowserEntryBase* fileDescr); + void selectRange (ThumbBrowserEntryBase* fileDescr); + void selectSet (ThumbBrowserEntryBase* fileDescr); + +public: void selectPrev (int distance, bool enlarge); void selectNext (int distance, bool enlarge); void selectFirst (bool enlarge); From df70d03e1398d9d1394405b7123fd0d1a2c188ac Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sun, 29 Nov 2015 00:07:21 +0100 Subject: [PATCH 2/2] Try to refactor the behaviour of the thumb browser selection modes adding support for shift-and-control range-selection to select several independent ranges. --- rtgui/thumbbrowserbase.cc | 138 ++++++++++++++++++++------------------ rtgui/thumbbrowserbase.h | 6 +- 2 files changed, 74 insertions(+), 70 deletions(-) diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index ed6366266..3536cc9b7 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -98,81 +98,85 @@ void ThumbBrowserBase::scrollPage (int direction) } } -void ThumbBrowserBase::selectSingle (ThumbBrowserEntryBase* fileDescr) +namespace { - for (size_t i = 0; i < selected.size(); i++) { - selected[i]->selected = false; - } + +typedef std::vector ThumbVector; +typedef ThumbVector::iterator ThumbIterator; + +inline void clearSelection (ThumbVector& selected) +{ + for (ThumbIterator thumb = selected.begin (); thumb != selected.end (); ++thumb) + (*thumb)->selected = false; selected.clear (); +} - if (fileDescr) { - selected.push_back (fileDescr); - fileDescr->selected = true; +inline void addToSelection (ThumbBrowserEntryBase* entry, ThumbVector& selected) +{ + if (entry->selected || entry->filtered) + return; + + entry->selected = true; + selected.push_back (entry); +} + +inline void removeFromSelection (const ThumbIterator& iterator, ThumbVector& selected) +{ + (*iterator)->selected = false; + selected.erase (iterator); +} + +} + +void ThumbBrowserBase::selectSingle (ThumbBrowserEntryBase* clicked) +{ + clearSelection (selected); + + if (clicked) + addToSelection (clicked, selected); +} + +void ThumbBrowserBase::selectRange (ThumbBrowserEntryBase* clicked, bool additional) +{ + if (selected.empty ()) { + addToSelection (clicked, selected); + return; + } + + if (!additional || !lastClicked) { + // Extend the current range w.r.t to first selected entry. + ThumbIterator front = std::find (fd.begin (), fd.end (), selected.front ()); + ThumbIterator current = std::find (fd.begin (), fd.end (), clicked); + + if (front > current) + std::swap (front, current); + + clearSelection (selected); + + for (; front <= current; ++front) + addToSelection (*front, selected); + } else { + // Add an additional range w.r.t. the last clicked entry. + ThumbIterator last = std::find (fd.begin (), fd.end (), lastClicked); + ThumbIterator current = std::find (fd.begin (), fd.end (), clicked); + + if (last > current) + std::swap (last, current); + + for (; last <= current; ++last) + addToSelection (*last, selected); } } -void ThumbBrowserBase::selectRange (ThumbBrowserEntryBase* fileDescr) +void ThumbBrowserBase::selectSet (ThumbBrowserEntryBase* clicked) { - if (selected.empty()) { - selected.push_back (fileDescr); - fileDescr->selected = true; + const ThumbIterator iterator = std::find (selected.begin (), selected.end (), clicked); + + if (iterator != selected.end ()) { + removeFromSelection (iterator, selected); } else { - // find the start and the end of the selection interval - size_t startx = fd.size() - 1; - - if (lastClicked) { - for (; startx > 0; startx--) - if (fd[startx] == lastClicked) { - break; - } - } else { - for (; startx > 0; startx--) - if (fd[startx] == selected[0]) { - break; - } - } - - size_t endx = 0; - - for (; endx < fd.size(); endx++) - if (fd[endx] == fileDescr) { - break; - } - - if (endx < startx) { - int tmp = endx; - endx = startx; - startx = tmp; - } - - // clear current selection - for (size_t i = 0; i < selected.size(); i++) { - selected[i]->selected = false; - } - - selected.clear (); - - // select thumbnails in the interval - for (size_t i = startx; i <= endx; i++) { - if (!fd[i]->filtered) { - fd[i]->selected = true; - selected.push_back (fd[i]); - } - } - } -} - -void ThumbBrowserBase::selectSet (ThumbBrowserEntryBase* fileDescr) -{ - std::vector::iterator i = std::find (selected.begin(), selected.end(), fileDescr); - - if (i != selected.end()) { - (*i)->selected = false; - selected.erase (i); - } else { - selected.push_back (fileDescr); - fileDescr->selected = true; + addToSelection (clicked, selected); } } @@ -828,7 +832,7 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ doubleClicked (selected[0]); } else if (button == 1 && type == GDK_BUTTON_PRESS) { if (fileDescr && (state & GDK_SHIFT_MASK)) - selectRange (fileDescr); + selectRange (fileDescr, state & GDK_CONTROL_MASK); else if (fileDescr && (state & GDK_CONTROL_MASK)) selectSet (fileDescr); else diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index ee11f550e..a3ef08d80 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -111,9 +111,9 @@ public: void scrollPage (int direction); private: - void selectSingle (ThumbBrowserEntryBase* fileDescr); - void selectRange (ThumbBrowserEntryBase* fileDescr); - void selectSet (ThumbBrowserEntryBase* fileDescr); + void selectSingle (ThumbBrowserEntryBase* clicked); + void selectRange (ThumbBrowserEntryBase* clicked, bool additional); + void selectSet (ThumbBrowserEntryBase* clicked); public: void selectPrev (int distance, bool enlarge);