Keyboard navigation in File Browser (issue 1919, on behalf of Adam Reichold)

Select a thumbnail using the arrow keys, select multiple with Shift
This commit is contained in:
michael 2013-07-02 13:33:46 -04:00
parent fbf5a98e1c
commit 01414d0550
4 changed files with 188 additions and 34 deletions

View File

@ -970,6 +970,22 @@ bool FileBrowser::keyPressed (GdkEventKey* event) {
FileBrowser::openNextImage ();
return true;
}
else if (event->keyval==GDK_Left) {
selectPrev (1, shift);
return true;
}
else if (event->keyval==GDK_Right) {
selectNext (1, shift);
return true;
}
else if (event->keyval==GDK_Up) {
selectPrev (numOfCols, shift);
return true;
}
else if (event->keyval==GDK_Down) {
selectNext (numOfCols, shift);
return true;
}
else if (event->keyval==GDK_F5) {
int dest = 1;

View File

@ -25,7 +25,7 @@
using namespace std;
ThumbBrowserBase::ThumbBrowserBase ()
: lastClicked(NULL), previewHeight(options.thumbSize) {
: lastClicked(NULL), previewHeight(options.thumbSize), numOfCols(1) {
inTabMode=false; // corresponding to take thumbSize
inW = -1; inH = -1;
@ -91,6 +91,137 @@ void ThumbBrowserBase::scrollPage (int direction) {
hscroll.set_value (hscroll.get_value() + (direction==GDK_SCROLL_DOWN ? +1 : -1) * hscroll.get_adjustment()->get_page_increment());
}
static void scrollToEntry (double& h, double& v, int iw, int ih, ThumbBrowserEntryBase* entry) {
const int hmin = entry->getX ();
const int hmax = hmin + entry->getEffectiveWidth () - iw;
const int vmin = entry->getY ();
const int vmax = vmin + entry->getEffectiveHeight () - ih;
if (hmin < 0)
h += hmin;
else if (hmax > 0)
h += hmax;
if(vmin < 0)
v += vmin;
else if (vmax > 0)
v += vmax;
}
void ThumbBrowserBase::selectPrev (int distance, bool enlarge) {
double h, v;
getScrollPosition (h, v);
{
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
if (!selected.empty ()) {
std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ());
std::vector<ThumbBrowserEntryBase*>::iterator back = std::find (fd.begin (), fd.end (), selected.back ());
if(front > back)
std::swap(front, back);
// find next thumbnail at filtered distance before 'front'
for (; front >= fd.begin (); --front) {
if(!(*front)->filtered) {
if (distance-- == 0) {
// clear current selection
for (size_t i=0; i<selected.size (); ++i) {
selected[i]->selected = false;
redrawNeeded (selected[i]);
}
selected.clear ();
// make sure the newly selected thumbnail is visible
scrollToEntry (h, v, internal.get_width (), internal.get_height (), *front);
// either enlarge current selection or set new selection
for(; front <= back; ++front) {
if(!(*front)->filtered) {
(*front)->selected = true;
redrawNeeded (*front);
selected.push_back (*front);
}
if(!enlarge)
break;
}
break;
}
}
}
}
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged ();
}
setScrollPosition (h, v);
}
void ThumbBrowserBase::selectNext (int distance, bool enlarge) {
double h, v;
getScrollPosition (h, v);
{
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
if (!selected.empty ()) {
std::vector<ThumbBrowserEntryBase*>::iterator front = std::find (fd.begin (), fd.end (), selected.front ());
std::vector<ThumbBrowserEntryBase*>::iterator back = std::find (fd.begin (), fd.end (), selected.back ());
if(front > back)
std::swap(front, back);
// find next thumbnail at filtered distance after 'back'
for (; back < fd.end (); ++back) {
if(!(*back)->filtered) {
if (distance-- == 0) {
// clear current selection
for (size_t i=0; i<selected.size (); ++i) {
selected[i]->selected = false;
redrawNeeded (selected[i]);
}
selected.clear ();
// make sure the newly selected thumbnail is visible
scrollToEntry (h, v, internal.get_width (), internal.get_height (), *back);
// either enlarge current selection or set new selection
for(; back >= front; --back) {
if(!(*back)->filtered) {
(*back)->selected = true;
redrawNeeded (*back);
selected.push_back (*back);
}
if(!enlarge)
break;
}
break;
}
}
}
}
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l);
#endif
selectionChanged ();
}
setScrollPosition (h, v);
}
void ThumbBrowserBase::resizeThumbnailArea (int w, int h) {
inW = w;
@ -167,7 +298,7 @@ void ThumbBrowserBase::arrangeFiles () {
rowHeight = fd[i]->getMinimalHeight ();
if (arrangement==TB_Horizontal) {
numOfCols = 1;
int numOfRows = 1;
// if (rowHeight>0) {
// numOfRows = (internal.get_height()+rowHeight/2)/rowHeight;
@ -206,7 +337,7 @@ void ThumbBrowserBase::arrangeFiles () {
else {
int availWidth = internal.get_width();
// initial number of columns
int numOfCols = 0;
numOfCols = 0;
int colsWidth = 0;
for (int i=0; i<N; i++)
if (!fd[i]->filtered && colsWidth + fd[i]->getMinimalWidth() <= availWidth) {

View File

@ -78,6 +78,9 @@ class ThumbBrowserBase : public Gtk::VBox {
void scroll (int direction);
void scrollPage (int direction);
void selectPrev(int distance, bool enlarge);
void selectNext(int distance, bool enlarge);
protected:
int eventTime;
@ -88,6 +91,7 @@ class ThumbBrowserBase : public Gtk::VBox {
ThumbBrowserEntryBase* lastClicked;
int previewHeight;
int numOfCols;
Arrangement arrangement;

View File

@ -110,10 +110,13 @@ protected:
int getMinimalHeight () { return height; }
int getMinimalWidth () { return width; }
int getEffectiveWidth () const { return exp_width; }
int getEffectiveHeight () const { return exp_height; }
int getPreviewHeight () const { return preh; }
int getStartX () const { return startx; }
int getStartY () const { return starty; }
int getX () const { return ofsX+startx; }
int getY () const { return ofsY+starty; }
bool inside (int x, int y);
bool insideWindow (int x, int y, int w, int h);