summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--mg_incremental_search.c78
-rw-r--r--mg_incremental_search.h36
-rw-r--r--vdr_actions.c49
-rw-r--r--vdr_menu.c221
-rw-r--r--vdr_menu.h60
6 files changed, 369 insertions, 82 deletions
diff --git a/Makefile b/Makefile
index 0c51abc..b3d5d6f 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ CXXFLAGS ?= -fPIC -O0 -Wall -Woverloaded-virtual -Wno-deprecated -g
DVBDIR ?= ../../../../DVB
VDRDIR ?= ../../../
-LIBDIR ?= /../../lib
+LIBDIR ?= ../../lib
TMPDIR ?= /tmp
### Allow user defined options to overwrite defaults:
@@ -56,9 +56,10 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DMYSQLCLIENTVERSION='
### The object files (add further files here):
-OBJS = $(PLUGIN).o i18n.o mg_valmap.o mg_mysql.o mg_sync.o mg_thread_sync.o mg_order.o mg_content.o mg_selection.o vdr_actions.o vdr_menu.o mg_tools.o \
+OBJS = $(PLUGIN).o i18n.o mg_valmap.o mg_mysql.o mg_sync.o mg_thread_sync.o mg_order.o \
+ mg_content.o mg_selection.o vdr_actions.o vdr_menu.o mg_tools.o \
vdr_decoder_mp3.o vdr_stream.o vdr_decoder.o vdr_player.o \
- vdr_setup.o mg_setup.o
+ vdr_setup.o mg_setup.o mg_incremental_search.o
LIBS = -lmad $(shell taglib-config --libs)
MILIBS = $(shell taglib-config --libs)
diff --git a/mg_incremental_search.c b/mg_incremental_search.c
new file mode 100644
index 0000000..58b2147
--- /dev/null
+++ b/mg_incremental_search.c
@@ -0,0 +1,78 @@
+/*! \file mg_incremental_search.c
+ * \ingroup muggle
+ * \brief A class that encapsulates incremental search
+ *
+ * \version $Revision: $
+ * \date $Date: $
+ * \author Lars von Wedel
+ * \author file owner: $Author: $
+ *
+ */
+
+#include "mg_incremental_search.h"
+#include <iostream>
+
+using namespace std;
+
+static char* keys[] = { " 0",
+ ".-_1",
+ "abc2",
+ "def3",
+ "ghi4",
+ "jkl5",
+ "mno6",
+ "pqrs7",
+ "tuv8",
+ "wxyz9" };
+
+mgIncrementalSearch::mgIncrementalSearch()
+ : m_position(-1), m_repeats(0), m_last_key(100), m_last_keypress(0.0)
+{ }
+
+string mgIncrementalSearch::KeyStroke( unsigned key )
+{
+ struct timeval now ;
+ gettimeofday( &now, NULL );
+
+ double current_t = now.tv_sec + (double)now.tv_usec / 1000000.0;
+ double delta_t = current_t - m_last_keypress;
+ m_last_keypress = current_t;
+
+ const double IS_TIMEOUT = 1.0; // 1 second
+ if( delta_t > IS_TIMEOUT || key != m_last_key )
+ {
+ m_position ++;
+
+ char tmp[2];
+ tmp[0] = (keys[key])[0];
+ tmp[1] = '\0';
+
+ m_buffer += string( tmp );
+
+ m_repeats = 0;
+ m_last_key = key;
+ }
+ else
+ {
+ // within timeout and have the same key
+ // position remains
+ m_repeats ++;
+
+ if( (unsigned) m_repeats > strlen( keys[m_position] ) )
+ {
+ // wrap around to first char
+ m_repeats = 0;
+ }
+ m_buffer[m_position] = (keys[key])[m_repeats];
+ }
+ return m_buffer;
+}
+
+string mgIncrementalSearch::Backspace()
+{
+ if( !m_buffer.empty() )
+ {
+ m_buffer.erase( m_buffer.size()-1, 1 );
+ }
+ return m_buffer;
+}
diff --git a/mg_incremental_search.h b/mg_incremental_search.h
new file mode 100644
index 0000000..e125577
--- /dev/null
+++ b/mg_incremental_search.h
@@ -0,0 +1,36 @@
+/*! \file mg_incremental_search.h
+ * \ingroup muggle
+ * \brief A class that encapsulates incremental search
+ *
+ * \version $Revision: $
+ * \date $Date: $
+ * \author Lars von Wedel
+ * \author file owner: $Author: $
+ *
+ */
+
+/* makes sure we don't use the same declarations twice */
+#ifndef _MUGGLE_INCSEARCH_H
+#define _MUGGLE_INCSEARCH_H
+
+#include <string>
+#include <sys/time.h>
+
+class mgIncrementalSearch
+{
+ public:
+ mgIncrementalSearch();
+
+ std::string KeyStroke( unsigned key );
+
+ std::string Backspace();
+
+ private:
+ std::string m_buffer;
+ int m_position;
+ unsigned m_repeats, m_last_key;
+
+ double m_last_keypress;
+};
+
+#endif
diff --git a/vdr_actions.c b/vdr_actions.c
index 1d7a0c5..2bb958d 100644
--- a/vdr_actions.c
+++ b/vdr_actions.c
@@ -2,7 +2,8 @@
* \file vdr_actions.c
* \brief Implements all actions for browsing media libraries within VDR
*
- * \version $Revision: 1.27 $ * \date $Date: 2004-12-25 16:52:35 +0100 (Sat, 25 Dec 2004) $
+ * \version $Revision: 1.27 $
+ * \date $Date: 2004-12-25 16:52:35 +0100 (Sat, 25 Dec 2004) $
* \author Wolfgang Rohdewald
* \author Responsible author: $Author: wr61 $
*
@@ -367,18 +368,48 @@ mgEntry::Execute()
eOSState
mgEntry::Process(eKeys key)
{
- switch (key) {
+ eOSState result = osUnknown;
+
+ mgTree *menu = dynamic_cast<mgTree*>(m); // und 0 abfangen
+ if( m )
+ {
+ switch (key)
+ {
case kOk:
- Execute();
- return osContinue;
- case k0:
- osd()->RefreshTitle();
- return osContinue;
+ {
+ menu->TerminateIncrementalSearch( true );
+ Execute();
+
+ result = osContinue;
+ } break;
+ case k0...k9:
+ {
+ menu->UpdateIncrementalSearch( key );
+ result = osContinue;
+ } break;
case kBack:
- return Back();
+ {
+ if( menu->UpdateIncrementalSearch( key ) )
+ { // search is continued
+ result = osContinue;
+ }
+ else
+ { // search is not active at all
+ result = Back();
+ }
+ } break;
default:
- return osUnknown;
+ {
+ if( key != kNone )
+ {
+ menu->TerminateIncrementalSearch( true );
+ }
+ result = osUnknown;
+ }
}
+ }
+
+ return result;
}
diff --git a/vdr_menu.c b/vdr_menu.c
index f462277..674cfe0 100644
--- a/vdr_menu.c
+++ b/vdr_menu.c
@@ -29,6 +29,7 @@
#include "vdr_setup.h"
#include "vdr_menu.h"
#include "vdr_player.h"
+#include "mg_incremental_search.h"
#include "i18n.h"
#define DEBUG
@@ -678,8 +679,10 @@ mgMenu::ExecuteButton(eKeys key)
mgTree::mgTree()
{
- TreeBlueAction = actShowCommands;
- CollBlueAction = actShowCommands;
+ TreeBlueAction = actShowCommands;
+ CollBlueAction = actShowCommands;
+ m_incsearch = NULL;
+ m_start_position = 0;
}
eOSState
@@ -688,10 +691,130 @@ mgMenu::Process (eKeys key)
return ExecuteButton(key);
}
+void
+mgTree::UpdateSearchPosition()
+{
+ int position = -1;
+ if( !m_incsearch || m_filter.empty() )
+ {
+ position = m_start_position;
+ }
+ else
+ {
+ // find the first item starting with m_filter
+ int counter = 0;
+ cOsdItem *item = osd()->First();
+ while( item && position < 0 )
+ {
+ if( !strncasecmp( item->Text(), m_filter.c_str(), m_filter.size() ) )
+ {
+ position = counter;
+ }
+ else
+ {
+ counter ++;
+ item = (cOsdItem *) item->Next();
+ }
+ }
+ }
+
+ // Set the title accordingly
+ osd()->RefreshTitle();
+
+ // Jump to the current item and refresh
+ osd()->newposition = position;
+ osd()->DisplayGoto();
+}
+
+bool
+mgTree::UpdateIncrementalSearch( eKeys key )
+{
+ bool result; // false if no search active and keystroke was not used
+
+ if( !m_incsearch )
+ {
+ switch( key )
+ {
+ case k0...k9:
+ { // create a new search object as this is the first keystroke
+ m_incsearch = new mgIncrementalSearch();
+
+ // remember the position where we started to search
+ m_start_position = osd()->Current();
+
+ // interprete this keystroke
+ m_filter = m_incsearch->KeyStroke( key - k0 );
+ result = true;
+ UpdateSearchPosition();
+ } break;
+ default:
+ {
+ result = false;
+ }
+ }
+ }
+ else
+ { // an incremental search is already active
+ switch( key )
+ {
+ case kBack:
+ {
+ m_filter = m_incsearch->Backspace();
+
+ if( m_filter.empty() )
+ { // search should be terminated, returning to the previous item
+ TerminateIncrementalSearch( false );
+ }
+ else
+ { // just find the first item for the current search string
+ UpdateSearchPosition();
+ }
+ result = true;
+ } break;
+ case k0...k9:
+ {
+ // evaluate the keystroke
+ m_filter = m_incsearch->KeyStroke( key - k0 );
+ result = true;
+ UpdateSearchPosition();
+ } break;
+ default:
+ {
+ result = false;
+ }
+ }
+ }
+ return result;
+}
+
+void mgTree::TerminateIncrementalSearch( bool remain_on_current )
+{
+ if( m_incsearch )
+ {
+ m_filter = "";
+ delete m_incsearch;
+ m_incsearch = NULL;
+
+ if( remain_on_current )
+ {
+ m_start_position = osd()->Current();
+ }
+
+ UpdateSearchPosition();
+ }
+}
+
string
mgTree::Title () const
{
- return selection ()->getListname ();
+ string title = selection ()->getListname ();
+
+ if( !m_filter.empty() )
+ {
+ title += " (" + m_filter + ")";
+ }
+
+ return title;
}
void
@@ -732,63 +855,65 @@ eOSState mgMainMenu::ProcessKey (eKeys key)
}
else
{
- switch (key)
- {
- case kPause:
- c->Pause ();
- break;
- case kStop:
- if (instant_playing && queue_playing) {
- PlayQueue();
- }
- else
- {
- queue_playing = false;
- c->Stop ();
- }
- break;
- case kChanUp:
- c->Forward ();
- break;
- case kChanDn:
- c->Backward ();
- break;
- default:
- goto otherkeys;
+ switch (key)
+ {
+ case kPause:
+ c->Pause ();
+ break;
+ case kStop:
+ if (instant_playing && queue_playing)
+ {
+ PlayQueue();
+ }
+ else
+ {
+ queue_playing = false;
+ c->Stop ();
+ }
+ break;
+ case kChanUp:
+ c->Forward ();
+ break;
+ case kChanDn:
+ c->Backward ();
+ break;
+ default:
+ goto otherkeys;
}
goto pr_exit;
}
}
else
- if (key==kPlay) {
- PlayQueue();
- goto pr_exit;
- }
+ if (key==kPlay)
+ {
+ PlayQueue();
+ goto pr_exit;
+ }
otherkeys:
newmenu = Menus.back(); // Default: Stay in current menu
newposition = -1;
-
+
{
- mgMenu * oldmenu = newmenu;
-
-// item specific key logic:
- result = cOsdMenu::ProcessKey (key);
-
-// mgMenu specific key logic:
- if (result == osUnknown)
- result = oldmenu->Process (key);
+ mgMenu * oldmenu = newmenu;
+
+ // item specific key logic:
+ result = cOsdMenu::ProcessKey (key);
+
+ // mgMenu specific key logic:
+ if (result == osUnknown)
+ result = oldmenu->Process (key);
}
-// catch osBack for empty OSD lists . This should only happen for playlistitems
-// (because if the list was empty, no mgActions::ProcessKey was ever called)
+ // catch osBack for empty OSD lists . This should only happen for playlistitems
+ // (because if the list was empty, no mgActions::ProcessKey was ever called)
if (result == osBack)
{
- // do as if there was an entry
- mgAction *a = Menus.back()->GenerateAction(actEntry,actEntry);
- if (a)
- {
- result = a->Back();
- delete a;
- }
+ // do as if there was an entry
+ mgAction *a = Menus.back()->GenerateAction(actEntry,actEntry);
+ if (a)
+ {
+ result = a->Back();
+ delete a;
+ }
}
// do nothing for unknown keys:
diff --git a/vdr_menu.h b/vdr_menu.h
index ec24ca1..a46b4b8 100644
--- a/vdr_menu.h
+++ b/vdr_menu.h
@@ -14,7 +14,7 @@
#define _VDR_MENU_H
#include <string>
-#include <list>
+// #include <list>
#include <vector>
#include <osd.h>
@@ -24,8 +24,6 @@
#include "vdr_player.h"
-using namespace std;
-
//! \brief play a selection, aborting what is currently played
//! \param select if true, play only what the current position selects
void Play(mgSelection *sel,const bool select=false);
@@ -38,6 +36,7 @@ class cCommands;
class mgSelection;
class mgMenu;
class mgMainMenu;
+class mgIncrementalSearch;
//! \brief if a player is running, return it
mgPlayerControl * PlayerControl ();
@@ -145,7 +144,7 @@ class mgMainMenu:public cOsdMenu
}
//! \brief this is the collection things will be added to
- string default_collection;
+ std::string default_collection;
/*! \brief this is the "now playing" collection translated in
* the current language. When changing the OSD language, this
@@ -154,7 +153,7 @@ class mgMainMenu:public cOsdMenu
* previous language will stay, so the user can copy from the
* old one to the new one.
*/
- string play_collection;
+ std::string play_collection;
/*! \brief selects a certain line on the OSD and displays the OSD
*/
@@ -177,13 +176,13 @@ class mgMainMenu:public cOsdMenu
// because that might do forcerefresh which overwrites the message
void Message (const char *msg) { m_message = strdup(msg); }
void Message1 (const char *msg, const char *arg1);
- void Message1 (const char *msg, string arg1) { Message1(msg,arg1.c_str()); }
+ void Message1 (const char *msg, std::string arg1) { Message1(msg,arg1.c_str()); }
//! \brief Actions can request a new position. -1 means none wanted
int newposition;
//! \brief clears the screen, sets a title and the hotkey flag
- void InitOsd (string title,const bool hashotkeys);
+ void InitOsd (std::string title,const bool hashotkeys);
#if VDRVERSNUM >= 10307
//! \brief expose the protected DisplayMenu() from cOsdMenu
@@ -227,11 +226,11 @@ class mgMainMenu:public cOsdMenu
bool DefaultCollectionSelected();
//! \brief true if the cursor is placed in the default collection
- bool CollectionEntered(string name);
+ bool CollectionEntered(std::string name);
void AddItem(mgAction *a);
- void CollectionChanged(string name);
+ void CollectionChanged(std::string name);
void CloseMenu();
@@ -261,7 +260,7 @@ class mgMenu
void AddSelectionItems (mgSelection *sel,mgActions act = actEntry);
//! \brief the name of the blue button depends of where we are
int m_parent_index;
- string m_parent_name;
+ std::string m_parent_name;
public:
/*! sets the correct help keys.
* \todo without data from mysql, no key is shown,
@@ -279,8 +278,8 @@ class mgMenu
void setParentIndex(int idx) { m_parent_index = idx; }
int getParentIndex() { return m_parent_index; }
- void setParentName(string name) { m_parent_name = name; }
- string getParentName() { return m_parent_name; }
+ void setParentName(std::string name) { m_parent_name = name; }
+ std::string getParentName() { return m_parent_name; }
//! \brief the pointer to the owning mgMainMenu
mgMainMenu* osd () const
@@ -306,7 +305,7 @@ class mgMenu
}
//! \brief computes the title
- virtual string Title() const = 0;
+ virtual std::string Title() const = 0;
//! \brief clears the screen, sets a title and the hotkey flag
void InitOsd (const bool hashotkeys=true);
@@ -348,11 +347,28 @@ class mgMenu
class mgTree:public mgMenu
{
public:
+
mgTree();
-//! \brief computes the title
- string Title() const;
+
+ //! \brief computes the title
+ std::string Title() const;
+
+ bool UpdateIncrementalSearch( eKeys key );
+
+ void TerminateIncrementalSearch( bool remain_on_current );
+
protected:
void BuildOsd ();
+
+ private:
+
+ void UpdateSearchPosition();
+
+ mgIncrementalSearch *m_incsearch;
+
+ std::string m_filter;
+
+ int m_start_position;
};
//! \brief an mgMenu class for submenus
@@ -361,7 +377,7 @@ class mgSubmenu:public mgMenu
public:
mgSubmenu::mgSubmenu();
//! \brief computes the title
- string Title() const;
+ std::string Title() const;
protected:
void BuildOsd ();
};
@@ -371,7 +387,7 @@ class mgMenuOrders:public mgMenu
{
public:
//! \brief computes the title
- string Title() const;
+ std::string Title() const;
protected:
void BuildOsd ();
};
@@ -382,7 +398,7 @@ class mgMenuOrder : public mgMenu
mgMenuOrder();
~mgMenuOrder();
//! \brief computes the title
- string Title() const;
+ std::string Title() const;
bool ChangeOrder(eKeys key);
void SaveOrder();
protected:
@@ -402,18 +418,18 @@ class mgTreeCollSelector:public mgMenu
mgTreeCollSelector();
~mgTreeCollSelector();
//! \brief computes the title
- string Title() const;
+ std::string Title() const;
protected:
void BuildOsd ();
virtual mgActions coll_action() = 0;
- string m_title;
+ std::string m_title;
};
class mgTreeAddToCollSelector:public mgTreeCollSelector
{
public:
//! \brief computes the title
- mgTreeAddToCollSelector(string title);
+ mgTreeAddToCollSelector(std::string title);
protected:
virtual mgActions coll_action() { return actAddCollEntry; }
};
@@ -423,7 +439,7 @@ class mgTreeRemoveFromCollSelector:public mgTreeCollSelector
{
public:
//! \brief computes the title
- mgTreeRemoveFromCollSelector(string title);
+ mgTreeRemoveFromCollSelector(std::string title);
protected:
virtual mgActions coll_action() { return actRemoveCollEntry; }
};