diff options
| author | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:35:43 +0000 |
|---|---|---|
| committer | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:35:43 +0000 |
| commit | fc2f5b2cd655f1391f2abda1b39e37cdec98a951 (patch) | |
| tree | 312efcea86a319de407a7c314fb981fb1c71019a /lib/gui | |
| download | enigma2-fc2f5b2cd655f1391f2abda1b39e37cdec98a951.tar.gz enigma2-fc2f5b2cd655f1391f2abda1b39e37cdec98a951.zip | |
Initial revision
Diffstat (limited to 'lib/gui')
48 files changed, 7955 insertions, 0 deletions
diff --git a/lib/gui/.cvsignore b/lib/gui/.cvsignore new file mode 100644 index 00000000..316b06f5 --- /dev/null +++ b/lib/gui/.cvsignore @@ -0,0 +1,7 @@ +*.moc.* +Makefile +Makefile.in +.deps +.libs +*.lo +*.la diff --git a/lib/gui/Makefile.am b/lib/gui/Makefile.am new file mode 100644 index 00000000..634f85b6 --- /dev/null +++ b/lib/gui/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src + +noinst_LIBRARIES = libenigma_gui.a + +libenigma_gui_a_SOURCES = \ + ebutton.cpp echeckbox.cpp elabel.cpp emessage.cpp \ + enumber.cpp eprogress.cpp eskin.cpp listbox.cpp eskin_register.cpp \ + ewidget.cpp ewindow.cpp multipage.cpp actions.cpp guiactions.cpp \ + decoration.cpp statusbar.cpp combobox.cpp numberactions.cpp slider.cpp \ + textinput.cpp testpicture.cpp + diff --git a/lib/gui/actions.cpp b/lib/gui/actions.cpp new file mode 100644 index 00000000..b55c43df --- /dev/null +++ b/lib/gui/actions.cpp @@ -0,0 +1,378 @@ +#include <lib/gui/actions.h> + +#include <xmltree.h> +#include <lib/base/eerror.h> +#include <lib/base/econfig.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/base/nconfig.h> + +eAction::eAction(eActionMap &map, char *identifier, char *description, int priority) + : description(description), identifier(identifier), map(&map), priority(priority) +{ + map.add(this); +} + +eAction::~eAction() +{ + map->remove(this); +} + +/*eAction::keylist &eAction::getKeyList() +{ + std::map<eString, keylist>::iterator it=keys.find( eActionMapList::getInstance()->getCurrentStyle() ); + if ( it != keys.end() ) + return it->second; + it = keys.find("default); + return it->second; +}*/ + +int eAction::containsKey(const eRCKey &key, const eString &style ) const +{ + std::map<eString, keylist>::const_iterator it=keys.find( style ); + if ( it != keys.end() ) + { + if (it->second.find(key)!=it->second.end()) + return 1; + } + return 0; +} + +// --------------------------------------------------------------------------- + +void eActionMap::findAction(eActionPrioritySet &list, const eRCKey &key, void *context, const eString &style) const +{ + for (std::list<eAction*>::const_iterator i=actions.begin(); i!=actions.end(); ++i) + { + if ((*i)->containsKey(key, style)) + list.insert(eAction::directedAction(context, *i)); + } +} + +eAction *eActionMap::findAction(const char *id) const +{ + for (std::list<eAction*>::const_iterator i=actions.begin(); i!=actions.end(); ++i) + if (!strcmp((*i)->getIdentifier(), id)) + return *i; + return 0; +} + +eActionMap::eActionMap(const char *identifier, char *description): + identifier(identifier), description(description) +{ + eActionMapList::getInstance()->addActionMap(identifier, this); +} + +eActionMap::~eActionMap() +{ + eActionMapList::getInstance()->removeActionMap(identifier); +} + +void eActionMap::loadXML(eRCDevice *device, std::map<std::string,int> &keymap, const XMLTreeNode *node, const eString& style) +{ + for (XMLTreeNode *xaction=node->GetChild(); xaction; xaction=xaction->GetNext()) + { + if (strcmp(xaction->GetType(), "action")) + { + eFatal("illegal type %s, expected 'action'", xaction->GetType()); + continue; + } + const char *name=xaction->GetAttributeValue("name"); + eAction *action=0; + if (name) + action=findAction(name); + if (!action) + { + eWarning("please specify a valid action with name=. valid actions are:"); + for (actionList::iterator i(actions.begin()); i != actions.end(); ++i) + eWarning(" %s (%s)", (*i)->getIdentifier(), (*i)->getDescription()); + eFatal("but NOT %s", name); + continue; + } + const char *code=xaction->GetAttributeValue("code"); + int icode=-1; + if (!code) + { + const char *key=xaction->GetAttributeValue("key"); + if (!key) + { + eFatal("please specify a number as code= or a defined key with key=."); + continue; + } + std::map<std::string,int>::iterator i=keymap.find(std::string(key)); + if (i == keymap.end()) + { + eFatal("undefined key '%s' specified!", key); + continue; + } + icode=i->second; + } else + sscanf(code, "%x", &icode); + const char *flags=xaction->GetAttributeValue("flags"); + if (!flags || !*flags) + flags="b"; + if (strchr(flags, 'm')) + action->insertKey( style, eRCKey(device, icode, 0) ); + if (strchr(flags, 'b')) + action->insertKey( style, eRCKey(device, icode, eRCKey::flagBreak) ); + if (strchr(flags, 'r')) + action->insertKey( style, eRCKey(device, icode, eRCKey::flagRepeat) ); + } +} + +void eActionMap::reloadConfig() +{ +#if 0 + NConfig &nc=eDVB::getInstance()->config; + std::string path="/ezap/rc/keymaps/"; + path+=identifier; + path+="/"; + + for (actionList::iterator i(actions.begin()); i!=actions.end(); ++i) + { + std::string key=path+i->getIdentifier(); + qDebug("loading %s", key.c_str()); + char *value; + int len; + int err; + if (!(err=nc.getKey(value, len))) + { + qDebug("have data!"); + } else + qDebug("error %d", err); + } +#endif +} + +void eActionMap::saveConfig() +{ +#if 0 + NConfig &nc=eDVB::getInstance()->config; + std::string path="/ezap/rc/keymaps/"; + path+=identifier; + path+="/"; + + for (actionList::iterator i(actions.begin()); i!=actions.end(); ++i) + { + std::string key=path+i->second.getIdentifier(); + qDebug("saving %s", key.c_str()); + std::string value; + + eAction::keyList &kl=i->second.getKeyList(); + + for (eAction::keylist::iterator kli(kl.begin()); kli!=kl.end(); ++kli) + { + eRCKey &key=kli->second; + qDebug("%s, %x, %x", key.producer->getIdentifier(), key.code, key.flags); + value+=key.producer->getIdentifier(); + value+=0; + + value+=(key.code>>24)&0xFF; + value+=(key.code>>16)&0xFF; + value+=(key.code>>8)&0xFF; + value+=key.code&0xFF; + + value+=(key.flags>>24)&0xFF; + value+=(key.flags>>16)&0xFF; + value+=(key.flags>>8)&0xFF; + value+=key.flags&0xFF; + } + nc.setKey(key.c_str(), value.data(), value.size()); + } +#endif +} + +// --------------------------------------------------------------------------- + +eActionMapList *eActionMapList::instance; + +eActionMapList::eActionMapList() +{ + if (!instance) + instance=this; + char * tmp; + if ( eConfig::getInstance()->getKey("/ezap/rc/style", tmp ) ) + currentStyle="default"; + else + { + currentStyle=tmp; + delete [] tmp; + } + eDebug("currentStyle=%s", currentStyle.c_str() ); + xmlfiles.setAutoDelete(1); +} + +eActionMapList::~eActionMapList() +{ + eConfig::getInstance()->setKey("/ezap/rc/style", currentStyle.c_str() ) ; + + if (instance==this) + instance=0; +} + +void eActionMapList::addActionMap(const char *id, eActionMap *am) +{ + actionmaps.insert(std::pair<const char*,eActionMap*>(id,am)); +} + +void eActionMapList::removeActionMap(const char *id) +{ + actionmaps.erase(id); +} + +int eActionMapList::loadXML(const char *filename) +{ + FILE *in=fopen(filename, "rt"); + if (!in) + { +// eDebug("cannot open %s", filename); + return -1; + } + + XMLTreeParser *parser=new XMLTreeParser("ISO-8859-1"); + char buf[2048]; + + int done; + do + { + unsigned int len=fread(buf, 1, sizeof(buf), in); + done=len<sizeof(buf); + if (!parser->Parse(buf, len, done)) + { + eFatal("parse error: %s at line %d", + parser->ErrorString(parser->GetErrorCode()), + parser->GetCurrentLineNumber()); + delete parser; + parser=0; + fclose(in); + return -1; + } + } while (!done); + fclose(in); + + XMLTreeNode *root=parser->RootNode(); + if (!root) + return -1; + if (strcmp(root->GetType(), "rcdefaults")) + { + eFatal("not a rcdefaults file."); + return -1; + } + + + xmlfiles.push_back(parser); + + return 0; +} + +XMLTreeNode *eActionMapList::searchDevice(const eString &id) +{ + for (ePtrList<XMLTreeParser>::iterator parser(xmlfiles.begin()); parser != xmlfiles.end(); ++parser) + { + XMLTreeNode *node=parser->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "device")) + { + const char *identifier=node->GetAttributeValue("identifier"); + if (!identifier) + { + eFatal("please specify an remote control identifier!"); + continue; + } + if (id == identifier) + return node; + } + } + return 0; +} + +int eActionMapList::loadDevice(eRCDevice *device) +{ + XMLTreeNode *node=searchDevice(device->getIdentifier()); + if (!node) + node=searchDevice("generic"); + if (!node) + { + eFatal("couldn't load key bindings for device %s", device->getDescription()); + return -1; + } + + std::map<std::string,int> keymap; + + for (XMLTreeNode *xam=node->GetChild(); xam; xam=xam->GetNext()) + if (!strcmp(xam->GetType(), "actionmap")) + { + eActionMap *am=0; + const char *name=xam->GetAttributeValue("name"); + if (name) + am=findActionMap(name); + if (!am) + { + eWarning("please specify a valid actionmap name (with name=)"); + eWarning("valid actionmaps are:"); + for (actionMapList::iterator i(actionmaps.begin()); i != actionmaps.end(); ++i) + eWarning(" %s", i->first); + eWarning("end."); + eFatal("invalid actionmap: \"%s\"", name?name:""); + continue; + } + const char *style=xam->GetAttributeValue("style"); + if (style) + { + const char *descr=xam->GetAttributeValue("descr"); + std::map<eString,eString>::iterator it = existingStyles.find(style); + if ( it == existingStyles.end() ) // not in map.. + { + if (descr) + existingStyles[style]=descr; + else + existingStyles[style]=style; + } + else if ( descr && existingStyles[style] == style ) + existingStyles[style]=descr; + am->loadXML(device, keymap, xam, style ); + } + else + am->loadXML( device, keymap, xam ); + } else if (!strcmp(xam->GetType(), "keys")) + { + for (XMLTreeNode *k=xam->GetChild(); k; k=k->GetNext()) + { + if (!strcmp(k->GetType(), "key")) + { + const char *name=k->GetAttributeValue("name"); + if (name) + { + const char *acode=k->GetAttributeValue("code"); + int code=-1; + if (acode) + sscanf(acode, "%x", &code); + else + { + acode=k->GetAttributeValue("icode"); + sscanf(acode, "%d", &code); + } + + if (code != -1) + keymap.insert(std::pair<std::string,int>(name, code)); + else + eFatal("no code specified for key %s!", name); + } else + eFatal("no name specified in keys!"); + } + } + } + return 0; +} + +eActionMap *eActionMapList::findActionMap(const char *id) const +{ + std::map<const char *,eActionMap*>::const_iterator i; + i=(actionmaps.find(id)); + if (i==actionmaps.end()) + return 0; + return i->second; +} + +eAutoInitP0<eActionMapList> init_eActionMapList(eAutoInitNumbers::lowlevel, "eActionMapList"); diff --git a/lib/gui/actions.h b/lib/gui/actions.h new file mode 100644 index 00000000..8cda4bc0 --- /dev/null +++ b/lib/gui/actions.h @@ -0,0 +1,138 @@ +#ifndef __actions_h +#define __actions_h + +#include <string.h> +#include <list> +#include <string> +#include <functional> +#include <set> + +#include <libsig_comp.h> +#include <lib/base/i18n.h> +#include <lib/base/estring.h> +#include <lib/driver/rc.h> + +class eActionMap; +class eActionMapList; + +/** + * \brief An action + * + * An action is an action of the user. It might raise by a keypress or otherwise. bla. + */ +class eAction +{ + typedef std::set<eRCKey> keylist; + char *description, *identifier; + eActionMap *map; + friend struct priorityComperator; + std::map<eString, keylist> keys; + int priority; +public: + typedef std::pair<void*,eAction*> directedAction; + /** + * \brief Functor to compare by priority. + * + * This is useful in sorted priority lists. + */ + struct priorityComperator + { + bool operator()(const directedAction &a, const directedAction &b) + { + return a.second->priority > b.second->priority; + } + }; + + enum + { + prioGlobal=0, prioDialog=10, prioWidget=20, prioDialogHi=30 + }; + /** + * \param priority The priority of this action. 0 should be used for + * global actions, 10 for dialog-local actions, 20 for widget-local actions, + * 30 for dialog-hi-priority actions. + */ + eAction(eActionMap &map, char *identifier, char *description, int priority=0 ); + ~eAction(); + const char *getDescription() const { return description; } + const char *getIdentifier() const { return identifier; } + + void insertKey(const eString& style, const eRCKey& key ) + { + keys[style].insert(key); + } + + Signal0<void> handler; + +// keylist &getKeyList(); + int containsKey(const eRCKey &key, const eString& style ) const; +}; + +typedef std::multiset<eAction::directedAction,eAction::priorityComperator> eActionPrioritySet; + +class XMLTreeNode; +class XMLTreeParser; + +class eActionMap +{ + typedef std::list<eAction*> actionList; + actionList actions; + const char *identifier, *description; +public: + eActionMap(const char *identifier, char *description); + ~eActionMap(); + void add(eAction *action) + { + actions.push_back(action); + } + void remove(eAction *action) + { + actions.remove(action); + } + void findAction(eActionPrioritySet &list, const eRCKey &key, void *context, const eString &style) const; + eAction *findAction(const char *id) const; + const char *getDescription() const { return description; } + const char *getIdentifier() const { return identifier; } + void reloadConfig(); + void loadXML(eRCDevice *device, std::map<std::string,int> &keymap, const XMLTreeNode *node, const eString& s=""); + void saveConfig(); +}; + +class eActionMapList +{ + struct lstr + { + bool operator()(const char *a, const char *b) const + { + return strcmp(a, b)<0; + } + }; + typedef std::map<const char*,eActionMap*,lstr> actionMapList; + + actionMapList actionmaps; + + std::map<eString, eString> existingStyles; + eString currentStyle; + + ePtrList<XMLTreeParser> xmlfiles; + XMLTreeNode *searchDevice(const eString &id); + + static eActionMapList *instance; +public: + eActionMapList(); + ~eActionMapList(); + const eString &getCurrentStyle() const { return currentStyle; } + void setCurrentStyle( const eString& style ) { currentStyle = style; } + eString getStyleDescription(const eString &style) const { std::map<eString, eString>::const_iterator i=existingStyles.find(style); if (i==existingStyles.end()) return ""; else return i->second; } + const std::map<eString, eString> &getExistingStyles() const { return existingStyles; } + void addActionMap(const char *, eActionMap * ); + void removeActionMap(const char *); + int loadXML(const char *filename); + int loadDevice(eRCDevice *device); + eActionMap *findActionMap(const char *id) const; + actionMapList &getActionMapList() { return actionmaps; } + + static eActionMapList *getInstance() { return instance; } +}; + +#endif diff --git a/lib/gui/combobox.cpp b/lib/gui/combobox.cpp new file mode 100644 index 00000000..cb90687b --- /dev/null +++ b/lib/gui/combobox.cpp @@ -0,0 +1,298 @@ +#include <lib/gui/combobox.h> +#include <lib/gdi/font.h> + +eComboBox::eComboBox( eWidget* parent, int OpenEntries, eLabel* desc, int takefocus, const char *deco ) +:eButton(parent, desc, takefocus, deco), +listbox(0, 0, takefocus), +button( this, 0, 0, eSkin::getActive()->queryValue("eComboBox.smallButton.decoWidth",0)?"eButton":""), +pm(0), entries(OpenEntries), current(0) +{ + align=eTextPara::dirLeft; + if ( eSkin::getActive()->queryValue("eComboBox.smallButton.decoWidth",0) ) + button.loadDeco(); + button.setBlitFlags(BF_ALPHATEST); + + eSkin::getActive()->queryImage(pm, "eComboBox.arrow"); + button.setPixmap(pm); + listbox.hide(); + listbox.setDeco("eComboBox.listbox"); + listbox.loadDeco(); + CONNECT( selected, eComboBox::onOkPressed ); + CONNECT( listbox.selected, eComboBox::onEntrySelected ); + CONNECT( listbox.selchanged, eComboBox::onSelChanged ); + listbox.zOrderRaise(); + addActionMap(&i_cursorActions->map); +} + +eComboBox::~eComboBox() +{ + if ( listbox.isVisible() ) + { + eDebug("KILL COMBOBOX WITH OPEN LISTBOX"); + listbox.hide(); + setFocus(this); + eWindow::globalCancel( eWindow::ON ); + } +} + +void eComboBox::redrawWidget(gPainter *target, const eRect &rc) +{ +// target->clip( eRect( rc.left(), rc.top(), rc.width()-button.width(), rc.bottom() ) ); + eLabel::redrawWidget(target, rc); +// target->clippop(); +} + +void eComboBox::onOkPressed() +{ + if ( flags & flagShowEntryHelp) + { + oldHelpText=helptext; + setHelpText( listbox.getCurrent()->getHelpText() ); + } + if ( flags & flagSorted ) + listbox.sort(); + parent->setFocus( &listbox ); + ePoint pt = getAbsolutePosition(); + if ( pt.y() + getSize().height() + listbox.getSize().height() > 520) + listbox.move( ePoint( pt.x(), pt.y()-listbox.getSize().height() ) ); + else + listbox.move( ePoint( pt.x(), pt.y()+getSize().height() ) ); + + eWindow::globalCancel( eWindow::OFF ); + listbox.show(); +} + +int eComboBox::setProperty( const eString& prop, const eString& val ) +{ + if ( prop == "sorted" ) + flags |= flagSorted; + else if (prop == "openEntries" ) + entries = atoi( val.c_str() ); + else if (prop == "showEntryHelp" ) + flags |= flagShowEntryHelp; + else if (prop == "openWidth" ) + { + int width=listbox.getSize().width(); + width = atoi(val.c_str()); + setOpenWidth( width ); + } + else + return eButton::setProperty( prop, val); + return 0; +} + +int eComboBox::eventHandler( const eWidgetEvent& event ) +{ + switch (event.type) + { + case eWidgetEvent::evtShortcut: + onOkPressed(); + break; + case eWidgetEvent::changedPosition: + case eWidgetEvent::changedSize: + { + eListBoxEntryText* cur = listbox.getCount()?listbox.getCurrent():0; + listbox.resize( eSize( getSize().width(), eListBoxEntryText::getEntryHeight()*entries+listbox.getDeco().borderBottom+listbox.getDeco().borderTop ) ); + int smButtonDeco = eSkin::getActive()->queryValue("eComboBox.smallButton.decoWidth", pm?pm->x:0 ); + if (deco) + { + button.resize( eSize(smButtonDeco, crect.height()) ); + button.move( ePoint( crect.right()-smButtonDeco, crect.top() ) ); + } + else + { + button.resize( eSize(smButtonDeco, height()) ); + button.move( ePoint( position.x()+size.width()-smButtonDeco, 0 ) ); + } + if (pm) + button.pixmap_position = ePoint( (button.getSize().width() - pm->x) / 2, (button.getSize().height() - pm->y) / 2 ); + if (cur) + listbox.setCurrent(cur); + } + default: + return eButton::eventHandler( event ); + } + return 1; +} + +int eComboBox::moveSelection ( int dir, bool sendSelChanged ) +{ + int ret = listbox.moveSelection( dir, sendSelChanged ); + eListBoxEntryText *cur = listbox.getCurrent(); + if ( cur ) + { + setText( cur->getText() ); + current = cur; + } + return ret; +} + + +void eComboBox::onEntrySelected( eListBoxEntryText* e) +{ + listbox.hide(); + if (flags & flagShowEntryHelp) + setHelpText( oldHelpText ); + + if (e && button.getText() != e->getText() ) + { + setText(e->getText()); + setFocus( this ); +#ifndef DISABLE_LCD + if ( parent->LCDElement ) + parent->LCDElement->setText(""); +#endif + current = e; + /* emit */ selchanged_id(this, current); + /* emit */ selchanged(current); + } + else + setFocus( this ); + + eWindow::globalCancel( eWindow::ON ); +} + +void eComboBox::onSelChanged(eListBoxEntryText* le) +{ + if (flags & flagShowEntryHelp ) + setHelpText( le->getHelpText() ); +#ifndef DISABLE_LCD + if ( parent->getFocus() == &listbox ) + { + if ( LCDTmp ) + LCDTmp->setText( le->getText() ); + else if ( parent->LCDElement ) + parent->LCDElement->setText( le->getText() ); + } +#endif +} + +void eComboBox::removeEntry( eListBoxEntryText* le ) +{ + if (le) + { + listbox.remove(le); + if ( flags & flagSorted ) + listbox.sort(); + } +} + +void eComboBox::removeEntry( int num ) +{ + if ( listbox.getCount() >= num) + { + setCurrent( num ); + listbox.remove( listbox.getCurrent() ); + if ( flags & flagSorted ) + listbox.sort(); + } +} + +void eComboBox::removeEntry( void* key ) +{ + setCurrent(key); + if (listbox.getCurrent() && key == listbox.getCurrent()->getKey() ) + { + listbox.remove( listbox.getCurrent() ); + if ( flags & flagSorted ) + listbox.sort(); + } +} + +int eComboBox::setCurrent( eListBoxEntryText* le, bool sendSelChanged ) +{ + if (!le) + return E_INVALID_ENTRY; + + int err = listbox.setCurrent( le, sendSelChanged ); + if( err && err != E_ALLREADY_SELECTED ) + return err; + + setText( listbox.getCurrent()->getText() ); + current = listbox.getCurrent(); + + return OK; +} + +struct selectEntryByNum: public std::unary_function<const eListBoxEntryText&, void> +{ + int num; + eListBox<eListBoxEntryText>* lb; + bool sendSelChanged; + + selectEntryByNum(int num, eListBox<eListBoxEntryText> *lb, bool sendSelChanged=false): num(num), lb(lb), sendSelChanged(sendSelChanged) + { + } + + bool operator()(const eListBoxEntryText& le) + { + if (!num--) + { + lb->setCurrent(&le, sendSelChanged); + return 1; + } + return 0; + } +}; + +int eComboBox::setCurrent( int num, bool sendSelChanged ) +{ + if ( num > listbox.getCount() ) + return E_INVALID_ENTRY; + + int err = listbox.forEachEntry( selectEntryByNum(num, &listbox, sendSelChanged ) ); + if ( err ) + return E_COULDNT_FIND; + + setText( listbox.getCurrent()->getText() ); + current = listbox.getCurrent(); + + return OK; +} + +struct selectEntryByKey: public std::unary_function<const eListBoxEntryText&, void> +{ + void* key; + eListBox<eListBoxEntryText>* lb; + bool sendSelChanged; + + selectEntryByKey(void *key, eListBox<eListBoxEntryText> *lb, bool sendSelChanged=false):key(key), lb(lb), sendSelChanged(sendSelChanged) + { + } + + bool operator()(const eListBoxEntryText& le) + { + if ( le.getKey() == key ) + { + lb->setCurrent(&le, sendSelChanged ); + return 1; + } + return 0; + } +}; + +int eComboBox::setCurrent( void* key, bool sendSelChanged ) +{ + if (!listbox.getCount()) + return E_INVALID_ENTRY; + + eListBoxEntryText* cur = listbox.getCurrent(); + + if ( cur && cur->getKey() == key ) + goto ok; + + int err; + if ( (err=listbox.forEachEntry( selectEntryByKey(key, &listbox, sendSelChanged ) ) ) ) + return E_COULDNT_FIND; + +ok: + setText( listbox.getCurrent()->getText() ); + current = listbox.getCurrent(); + + return OK; +} + +eListBoxEntryText* eComboBox::getCurrent() +{ + return current; +} diff --git a/lib/gui/combobox.h b/lib/gui/combobox.h new file mode 100644 index 00000000..55c1d469 --- /dev/null +++ b/lib/gui/combobox.h @@ -0,0 +1,50 @@ +#ifndef __E_COMBOBOX__ +#define __E_COMBOBOX__ + +#include <lib/gui/listbox.h> +#include <lib/gui/ebutton.h> + +class eComboBox: public eButton +{ + eListBox<eListBoxEntryText> listbox; + eLabel button; // the small buttin with arrow png... + ePtr<gPixmap> pm; + int entries; + eListBoxEntryText *current; + void onOkPressed(); + void onEntrySelected( eListBoxEntryText* ); + void onSelChanged( eListBoxEntryText* ); // für setzen des HelpTextes ( Statusbar ) + int eventHandler( const eWidgetEvent& ); + eString oldHelpText; + int setProperty( const eString&, const eString& ); + void redrawWidget(gPainter *target, const eRect &rc); +public: + ~eComboBox(); + void setOpenWidth( int w ) { listbox.resize( eSize(w, listbox.getSize().height()) ); } + enum { OK = 0, ERROR=1, E_ALLREADY_SELECTED = 2, E_COULDNT_FIND = 4, E_INVALID_ENTRY = 8 }; + Signal1< void, eListBoxEntryText* > selchanged; + Signal2< void, eComboBox*, eListBoxEntryText* > selchanged_id; + enum { /*flagVCenter=64 in eLabel*/ flagSorted=128, flagShowEntryHelp=256 }; + eComboBox(eWidget* parent, int OpenEntries=5, eLabel* desc=0, int takefocus=1, const char *deco="eComboBox" ); + void removeEntry( eListBoxEntryText* ); + void removeEntry( int ); + void removeEntry( void* ); + void sort() { listbox.sort(); } + int setCurrent( eListBoxEntryText*, bool=false ); + int setCurrent( int, bool=false ); + int setCurrent( void*, bool=false ); + int getCount() { return listbox.getCount(); } + int moveSelection ( int dir, bool=false ); + void clear() { listbox.clearList(); } + eListBoxEntryText* getCurrent(); + operator eListBox<eListBoxEntryText>*() { return &listbox; } + + template <class Z> + int forEachEntry(Z ob) + { + return listbox.forEachEntry(ob); + } +}; + + +#endif // __E_COMBOBOX__ diff --git a/lib/gui/decoration.cpp b/lib/gui/decoration.cpp new file mode 100644 index 00000000..4debef98 --- /dev/null +++ b/lib/gui/decoration.cpp @@ -0,0 +1,181 @@ +#include <lib/gui/decoration.h> +#include <lib/gdi/gpixmap.h> +#include <lib/gdi/grc.h> +#include <lib/gui/eskin.h> +#include <lib/gui/ewidget.h> + +/* + + +-------+-----------------+--------+ + |TopLeft| Top |TopRight| + +------++-----------------+--+-----+ + | Left| client |Right| + +------+---+-----------+-----+-----+ + |BottomLeft| Bottom |BottomRight| + +----------+-----------+-----------+ + +*/ + +eDecoration::eDecoration() +{ + iTopLeft=iTop=iTopRight=iLeft=iRight=iBottomLeft=iBottom=iBottomRight=0; + borderLeft=borderTop=borderRight=borderBottom=0; +} + +bool eDecoration::load(const eString& base) +{ + if (basename != base) + { + basename=base; // all your + + eSkin::getActive()->queryImage(iTopLeft, basename + ".topLeft"); + eSkin::getActive()->queryImage(iTop, basename + ".top"); + eSkin::getActive()->queryImage(iTopRight, basename + ".topRight"); + eSkin::getActive()->queryImage(iLeft, basename + ".left"); + eSkin::getActive()->queryImage(iRight, basename + ".right"); + eSkin::getActive()->queryImage(iBottomLeft, basename + ".bottomLeft"); + eSkin::getActive()->queryImage(iBottom, basename + ".bottom"); + eSkin::getActive()->queryImage(iBottomRight, basename + ".bottomRight"); + + borderLeft=borderTop=borderRight=borderBottom=0; + + if (iTop) + borderTop = iTop->y; + if (iLeft) + borderLeft = iLeft->x; + if (iRight) + borderRight = iRight->x; + if (iBottom) + borderBottom = iBottom->y; + } + return operator bool(); +} + +void eDecoration::drawDecoration(gPainter *target, ePoint size) +{ + int x=0, xm=size.x(), y, ym; + + if (iBottomLeft) + { + target->blit(iBottomLeft, ePoint(0, size.y()-iBottomLeft->y)); + x+=iBottomLeft->x; + } + + if (iBottomRight) + { + xm-=iBottomRight->x; + target->blit(iBottomRight, ePoint(xm, size.y()-iBottomRight->y), eRect(x, size.y()-iBottomRight->y, size.x()-x, iBottomRight->y)); + } + + if (iBottom) + { + while (x<xm) + { + target->blit(iBottom, ePoint(x, size.y()-iBottom->y), eRect(x, size.y()-iBottom->y, xm-x, size.y())); + x+=iBottom->x; + } + } + + x=0; + xm=size.x(); + + if (iTopLeft) + { + target->blit(iTopLeft, ePoint(0, 0) ); + x+=iTopLeft->x; + } + + if (iTopRight) + { + xm-=iTopRight->x; + target->blit(iTopRight, ePoint(xm, 0), eRect(x, 0, size.x()-x, size.y())); + } + + if (iTop) + { + while (x<xm) + { + target->blit(iTop, ePoint(x, 0), eRect(x, 0, xm-x, size.y())); + x+=iTop->x; + } + } + + y=0; ym=size.y(); + + if (iTopLeft) + y=iTopLeft->y; + if (iBottomLeft) + ym=size.y()-iBottomLeft->y; + if (iLeft) + { + while (y<ym) + { + target->blit(iLeft, ePoint(0, y), eRect(0, y, iLeft->x, ym-y)); + y+=iLeft->y; + } + } + + if (iTopRight) + y=iTopRight->y; + if (iBottomRight) + ym=size.y()-iBottomRight->y; + if (iRight) + { + while (y<ym) + { + target->blit(iRight, ePoint(size.x()-iRight->x, y), eRect(size.x()-iRight->x, y, iRight->x, ym-y)); + y+=iRight->y; + } + } + + target->flush(); +} + +int eDecoWidget::setProperty( const eString &prop, const eString &value) +{ + if (prop == "loadDeco") + { + if ( value != "" ) + strDeco=value; + + loadDeco(); + } + else + return eWidget::setProperty( prop, value ); + + return 0; +} + +int eDecoWidget::eventFilter( const eWidgetEvent &evt ) +{ + if ( evt.type == eWidgetEvent::changedSize ) + { + if (deco) + { + crect.setLeft( deco.borderLeft ); + crect.setTop( deco.borderTop ); + crect.setWidth( width() - (deco.borderRight + deco.borderLeft) ); + crect.setHeight( height() - (deco.borderBottom + deco.borderTop ) ); + } + if (deco_selected) + { + crect_selected.setLeft( deco_selected.borderLeft ); + crect_selected.setTop( deco_selected.borderTop ); + crect_selected.setWidth( width() - (deco_selected.borderRight + deco_selected.borderLeft) ); + crect_selected.setHeight( height() - (deco_selected.borderBottom + deco_selected.borderTop ) ); + } + } + return 0; //always return 0... the eventHandler must been called... +} + +void eDecoWidget::loadDeco() +{ + int i = 0; + if ( deco.load( strDeco ) ) + i |= 1; + if ( deco_selected.load( strDeco+".selected" ) ) + i |= 1; + if (i) + event( eWidgetEvent::changedSize ); +} + diff --git a/lib/gui/decoration.h b/lib/gui/decoration.h new file mode 100644 index 00000000..4a5e4eec --- /dev/null +++ b/lib/gui/decoration.h @@ -0,0 +1,49 @@ +#ifndef __lib_gui_decoration_h +#define __lib_gui_decoration_h + +#include <lib/gdi/erect.h> +#include <lib/base/estring.h> +#include <lib/gui/ewidget.h> +class gPixmap; +class gPainter; + +class eDecoration +{ + ePtr<gPixmap> iTopLeft, iTop, + iTopRight, iLeft, iRight, + iBottomLeft, iBottom, iBottomRight; + + eString basename; +public: + operator bool() { return iTopLeft || iTop || iTopRight || iLeft || iRight || iBottomLeft || iBottom || iBottomRight; } + + eDecoration(); + + bool load(const eString& basename); + + void drawDecoration(gPainter *target, ePoint size ); + int borderTop, borderLeft, borderBottom, borderRight; +}; + +class eDecoWidget:public eWidget +{ +protected: + eString strDeco; + eRect crect, crect_selected; + eDecoration deco, deco_selected; + int setProperty( const eString &prop, const eString &value); + int eventFilter( const eWidgetEvent &evt); +public: + void setDeco( const char* deco ) + { + strDeco = deco; + } + void loadDeco(); + eDecoWidget( eWidget* parent=0, int takefocus=0, const char* deco="" ) + :eWidget(parent, takefocus), strDeco( deco ) + { } + const eDecoration& getDeco() { return deco; } + const eDecoration& getDecoSelected() { return deco_selected; } +}; + +#endif diff --git a/lib/gui/ebutton.cpp b/lib/gui/ebutton.cpp new file mode 100644 index 00000000..9e97d581 --- /dev/null +++ b/lib/gui/ebutton.cpp @@ -0,0 +1,134 @@ +#include <lib/gui/ebutton.h> +#include <lib/gui/eskin.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/gdi/font.h> +#include <lib/gui/guiactions.h> + +eButton::eButton(eWidget *parent, eLabel* desc, int takefocus, const char *deco) + :eLabel(parent, 0, takefocus, deco), +#ifndef DISABLE_LCD + tmpDescr(0), +#endif + focusB(eSkin::getActive()->queryScheme("global.selected.background")), + focusF(eSkin::getActive()->queryScheme("global.selected.foreground")), + normalB(eSkin::getActive()->queryScheme("button.normal.background")), + normalF(eSkin::getActive()->queryScheme("global.normal.foreground")), + descr(desc) +{ + align=eTextPara::dirCenter; + flags |= eLabel::flagVCenter; + addActionMap(&i_cursorActions->map); +} + +void eButton::gotFocus() +{ +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) + { + if (descr) + { + LCDTmp = new eLabel(parent->LCDElement); + LCDTmp->hide(); + eSize s = parent->LCDElement->getSize(); + LCDTmp->move(ePoint(0,s.height()/2)); + LCDTmp->resize(eSize(s.width(), s.height()/2)); + LCDTmp->setText(text); + LCDTmp->setBackgroundColor(255); + LCDTmp->show(); + tmpDescr = new eLabel(parent->LCDElement); + tmpDescr->hide(); + tmpDescr->move(ePoint(0,0)); + tmpDescr->resize(eSize(s.width(), s.height()/2)); + tmpDescr->setText(descr->getText()); + tmpDescr->show(); + } + else + parent->LCDElement->setText(text); + } +#endif + setForegroundColor(focusF,false); + setBackgroundColor(focusB); + +//invalidate(); +} + +void eButton::lostFocus() +{ +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) + { + if (LCDTmp) + { + delete LCDTmp; + LCDTmp = 0; + if (tmpDescr) + { + delete tmpDescr; + tmpDescr=0; + } + } + else + parent->LCDElement->setText(""); + } +#endif + setForegroundColor(normalF,false); + setBackgroundColor(normalB); + +// invalidate(); +} + +int eButton::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::evtAction: + if (event.action == &i_cursorActions->ok) + { + /*emit*/ selected(); + /*emit*/ selected_id(this); + +/*#ifndef DISABLE_LCD + if (parent && parent->LCDElement) + { + if (LCDTmp) + LCDTmp->setText(text); + else + parent->LCDElement->setText(text); + } +#endif*/ + } + else + return eLabel::eventHandler(event); + break; + case eWidgetEvent::evtShortcut: + /*emit*/ selected(); + /*emit*/ selected_id(this); + return 0; + break; + default: + return eLabel::eventHandler(event); + break; + } + return 1; +} + +static eWidget *create_eButton(eWidget *parent) +{ + return new eButton(parent); +} + +class eButtonSkinInit +{ +public: + eButtonSkinInit() + { + eSkin::addWidgetCreator("eButton", create_eButton); + } + ~eButtonSkinInit() + { + eSkin::removeWidgetCreator("eButton", create_eButton); + } +}; + +eAutoInitP0<eButtonSkinInit> init_eButtonSkinInit(eAutoInitNumbers::guiobject, "eButton"); diff --git a/lib/gui/ebutton.h b/lib/gui/ebutton.h new file mode 100644 index 00000000..6e9783eb --- /dev/null +++ b/lib/gui/ebutton.h @@ -0,0 +1,37 @@ +#ifndef __ebutton_h +#define __ebutton_h + +#include <lib/gui/elabel.h> +#include <lib/gdi/grc.h> + +/** + * \brief A widget which acts like a button. + */ +class eButton: public eLabel +{ +#ifndef DISABLE_LCD + eLabel* tmpDescr; // used for LCD with description +#endif +protected: + gColor focusB, focusF, normalB, normalF; + eLabel *descr; + int eventHandler(const eWidgetEvent &event); + void gotFocus(); + void lostFocus(); +public: + /** + * \brief Constructs a button. + * + * \param descr is for use with lcd + */ + eButton(eWidget *parent, eLabel* descr=0, int takefocus=1, const char *deco="eButton" ); + /** + * \brief the "selected" signal. + * + * This signals is emitted when OK is pressed. + */ + Signal0<void> selected; + Signal1<void, eButton*> selected_id; +}; + +#endif diff --git a/lib/gui/echeckbox.cpp b/lib/gui/echeckbox.cpp new file mode 100644 index 00000000..c41721ce --- /dev/null +++ b/lib/gui/echeckbox.cpp @@ -0,0 +1,138 @@ +#include <lib/gui/echeckbox.h> + +#include <lib/gdi/font.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/gui/eskin.h> + +eCheckbox::eCheckbox(eWidget *parent, int checked, int takefocus, bool swapTxtPixmap, const char *deco) + :eButton(parent, 0, takefocus, deco), swapTxtPixmap(swapTxtPixmap) +{ + align=eTextPara::dirLeft; + ischecked = -1; + setCheck(checked); + CONNECT(selected, eCheckbox::sel); +} + +eCheckbox::~eCheckbox() +{ +} + +void eCheckbox::sel() +{ + setCheck(ischecked?0:1); + /*emit*/ checked(ischecked); +} + +void eCheckbox::gotFocus() +{ +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) + { + LCDTmp = new eLabel(parent->LCDElement); + LCDTmp->hide(); + eSize s = parent->LCDElement->getSize(); + LCDTmp->move(ePoint(0,0)); + LCDTmp->resize(eSize(s.width(), s.height())); + ((eLabel*)LCDTmp)->setFlags(RS_WRAP); + ePtr<gPixmap> pm; + eSkin::getActive()->queryImage(pm, ischecked?"eCheckboxLCD.checked":"eCheckboxLCD.unchecked"); + LCDTmp->setPixmap(pm); + ((eLabel*)LCDTmp)->pixmap_position=ePoint(0, (size.height()-15)/2); + ((eLabel*)LCDTmp)->text_position=ePoint(21, 0); + LCDTmp->setText(text); + LCDTmp->show(); + } +#endif + setForegroundColor(focusF, false); + setBackgroundColor(focusB); +// invalidate(); +} + +void eCheckbox::lostFocus() +{ +#ifndef DISABLE_LCD + if (LCDTmp) + { + delete LCDTmp; + LCDTmp = 0; + } +#endif + eButton::lostFocus(); +} + + +void eCheckbox::setCheck(int c) +{ + if (ischecked != -1 && ischecked == c) + return; + + ischecked=c; + + ePtr<gPixmap> pixmap; + eSkin::getActive()->queryImage(pixmap, ischecked?"eCheckbox.checked":"eCheckbox.unchecked"); + setPixmap(pixmap); +#ifndef DISABLE_LCD + eSkin::getActive()->queryImage(pixmap, ischecked?"eCheckboxLCD.checked":"eCheckboxLCD.unchecked"); + if (LCDTmp) + LCDTmp->setPixmap(pixmap); +#endif +} + +int eCheckbox::setProperty(const eString &prop, const eString &value) +{ + if (prop=="swaptxtpixmap") + { + swapTxtPixmap = (value != "off"); + event( eWidgetEvent::changedSize ); + } + else + return eButton::setProperty(prop, value); + return 0; +} + +int eCheckbox::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::changedSize: + if (swapTxtPixmap) + { + text_position=ePoint(0,0); + eLabel::invalidate(); + validate(); + pixmap_position=ePoint( para->getBoundBox().right()+5, (size.height()-pixmap->y) / 2 ); + } + else + { + pixmap_position=ePoint(0, (size.height()-pixmap->y)/2); + text_position=ePoint((int)(pixmap->x*1.25), 0); + } + //return eButton::eventHandler(event); // changed Size must seen by eLabel... + break; + + default: + return eButton::eventHandler(event); + } + return 1; +} + +static eWidget *create_eCheckbox(eWidget *parent) +{ + return new eCheckbox(parent); +} + +class eCheckboxSkinInit +{ +public: + eCheckboxSkinInit() + { + eSkin::addWidgetCreator("eCheckbox", create_eCheckbox); + } + ~eCheckboxSkinInit() + { + eSkin::removeWidgetCreator("eCheckbox", create_eCheckbox); + } +}; + +eAutoInitP0<eCheckboxSkinInit> init_eCheckboxSkinInit(eAutoInitNumbers::guiobject, "eCheckbox"); diff --git a/lib/gui/echeckbox.h b/lib/gui/echeckbox.h new file mode 100644 index 00000000..92f6e4d5 --- /dev/null +++ b/lib/gui/echeckbox.h @@ -0,0 +1,25 @@ +#ifndef __echeckbox_h +#define __echeckbox_h + +#include <lib/gui/ebutton.h> + +class eCheckbox: public eButton +{ +protected: + int ischecked; +private: + void sel(); + int eventHandler(const eWidgetEvent &event); + int setProperty(const eString &prop, const eString &value); + void gotFocus(); + void lostFocus(); + bool swapTxtPixmap; +public: + Signal1<void, int> checked; + eCheckbox(eWidget *parent, int checked=0, int takefocus=1, bool swapTxtPixmap=false, const char *deco="eCheckBox" ); + ~eCheckbox(); + void setCheck(int c); + int isChecked() { return ischecked; } +}; + +#endif diff --git a/lib/gui/elabel.cpp b/lib/gui/elabel.cpp new file mode 100644 index 00000000..ae04eb46 --- /dev/null +++ b/lib/gui/elabel.cpp @@ -0,0 +1,253 @@ +#include <lib/gui/elabel.h> + +#include <lib/gdi/fb.h> +#include <lib/gdi/font.h> +#include <lib/gdi/lcd.h> +#include <lib/gui/eskin.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> + +eLabel::eLabel(eWidget *parent, int flags, int takefocus, const char *deco ): + eDecoWidget(parent, takefocus, deco), blitFlags(0), flags(flags), + para(0), align( eTextPara::dirLeft ), shortcutPixmap(0) +{ +} + +eLabel::~eLabel() +{ + if (para) + { + para->destroy(); + para=0; + } +} + +void eLabel::setPixmapPosition( const ePoint &p ) +{ + pixmap_position = p; + invalidate(); +} + +void eLabel::validate( const eSize* s ) +{ + if (!para) + { + if (s) + para=new eTextPara( eRect(text_position.x(), text_position.y(), s->width() - text_position.x(), s->height() - text_position.y())); + else + para=new eTextPara( eRect(text_position.x(), text_position.y(), size.width() - text_position.x(), size.height() - text_position.y())); + + para->setFont(font); + para->renderString(text, flags); + para->realign(align); + } +} + +void eLabel::invalidate() +{ + if (para) + { + para->destroy(); + para=0; + } + if (isVisible()) + eDecoWidget::invalidate(); // we must redraw... +} + +void eLabel::setFlags(int flag) +{ + flags|=flag; + if (flag) + invalidate(); +} + +void eLabel::setBlitFlags( int flags ) +{ + blitFlags |= flags; +} + +void eLabel::removeFlags(int flag) +{ + flags &= ~flag; + if (flag) + invalidate(); +} + +void eLabel::setAlign(int align) +{ + this->align = align; + invalidate(); +} + +void eLabel::redrawWidget(gPainter *target, const eRect &rc) +{ +/* eDebug("decoStr = %s, text=%s, name=%s, %p left = %d, top = %d, width=%d, height = %d", strDeco?strDeco.c_str():"no", text?text.c_str():"no" , name?name.c_str():"no", this, this->getPosition().x(), this->getPosition().y(), this->getSize().width(), this->getSize().height() ); + eDebug("renderContext left = %d, top = %d, width = %d, height = %d", rc.left(), rc.top(), rc.width(), rc.height() );*/ + + target->clip( rc ); + eRect area=eRect(ePoint(0, 0), ePoint(width(), height())); +/* eDebug("area left = %d, top = %d, width = %d, height = %d", + area.left(), area.top(), + area.width(), area.height() );*/ + + if (deco_selected && have_focus) + { + deco_selected.drawDecoration(target, ePoint(width(), height())); + area=crect_selected; + } else if (deco) + { + deco.drawDecoration(target, ePoint(width(), height())); + area=crect; + } +/* eDebug("area left = %d, top = %d, width = %d, height = %d", + area.left(), area.top(), + area.width(), area.height() );*/ + + if (shortcutPixmap) + { + //area.setWidth(area.width()-area.height()); + area.setX(area.height()); + } + + if (text.length()) + { + if ( area.size().height() < size.height() || + area.size().width() < size.width() ) + { + // then deco is drawed + eSize s=area.size(); + validate( &s ); + } else + validate(); + + if (flags & flagVCenter) + yOffs = ( (area.height() - para->getBoundBox().height() ) / 2 + 0) - para->getBoundBox().top(); + else + yOffs = 0; + + eWidget *w; + if ((blitFlags & BF_ALPHATEST) && (transparentBackgroundColor >= 0)) + { + w=this; + target->setBackgroundColor(transparentBackgroundColor); + } else + { + w=getNonTransparentBackground(); + target->setBackgroundColor(w->getBackgroundColor()); + } + target->setFont(font); + target->renderPara(*para, ePoint( area.left(), area.top()+yOffs) ); + } + if (pixmap) + { +// eDebug("blit pixmap area left=%d, top=%d, right=%d, bottom=%d", rc.left(), rc.top(), rc.right(), rc.bottom() ); +// eDebug("pixmap_pos x = %d, y = %d, xsize=%d, ysize=%d", pixmap_position.x(), pixmap_position.y(), pixmap->x, pixmap->y ); + target->blit(pixmap, shortcutPixmap?pixmap_position+ePoint( area.left(), 0):pixmap_position, area, (blitFlags & BF_ALPHATEST) ? gPixmap::blitAlphaTest : 0); + } + if (shortcutPixmap) + target->blit(shortcutPixmap, + ePoint((area.height()-shortcutPixmap->x)/2, area.top()+(area.height()-shortcutPixmap->y)/2), + eRect(), + gPixmap::blitAlphaTest); + target->clippop(); +} + +int eLabel::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::changedFont: + case eWidgetEvent::changedText: + if (para) + { + para->destroy(); + para=0; + } + if ( have_focus && deco_selected ) + eDecoWidget::invalidate( crect_selected ); + else if ( deco ) + eDecoWidget::invalidate( crect ); + else + eDecoWidget::invalidate(); + break; + + case eWidgetEvent::changedSize: + invalidate(); + break; + + default: + return eDecoWidget::eventHandler(event); + break; + } + return 1; +} + +eSize eLabel::getExtend() +{ + validate(); + return eSize(para->getBoundBox().width()+(shortcutPixmap?shortcutPixmap->x*2:0), para->getBoundBox().height()); +} + +ePoint eLabel::getLeftTop() +{ + validate(); + return ePoint(para->getBoundBox().left(), para->getBoundBox().top()); +} + +int eLabel::setProperty(const eString &prop, const eString &value) +{ + if (prop=="wrap" && value == "on") + setFlags(RS_WRAP); + else if (prop=="alphatest" && value == "on") + { + transparentBackgroundColor=getBackgroundColor(); + setBackgroundColor(-1); + blitFlags |= BF_ALPHATEST; + } else if (prop=="align") + { + if (value=="left") + setAlign(eTextPara::dirLeft); + else if (value=="center") + setAlign(eTextPara::dirCenter); + else if (value=="right") + setAlign(eTextPara::dirRight); + else if (value=="block") + setAlign(eTextPara::dirBlock); + else + setAlign(eTextPara::dirLeft); + } + else if (prop=="vcenter") + setFlags( flagVCenter ); + else if (prop == "shortcut") + { + setShortcutPixmap(value); + return eWidget::setProperty(prop, value); + } else + return eDecoWidget::setProperty(prop, value); + return 0; +} + +void eLabel::setShortcutPixmap(const eString &shortcut) +{ + eSkin::getActive()->queryImage(shortcutPixmap, "shortcut." + shortcut); +} + +static eWidget *create_eLabel(eWidget *parent) +{ + return new eLabel(parent); +} + +class eLabelSkinInit +{ +public: + eLabelSkinInit() + { + eSkin::addWidgetCreator("eLabel", create_eLabel); + } + ~eLabelSkinInit() + { + eSkin::removeWidgetCreator("eLabel", create_eLabel); + } +}; + +eAutoInitP0<eLabelSkinInit> init_eLabelSkinInit(eAutoInitNumbers::guiobject, "eLabel"); diff --git a/lib/gui/elabel.h b/lib/gui/elabel.h new file mode 100644 index 00000000..096ef0d8 --- /dev/null +++ b/lib/gui/elabel.h @@ -0,0 +1,44 @@ +#ifndef __elabel_h +#define __elabel_h + +#include <lib/gui/ewidget.h> +#include <lib/gdi/grc.h> +#include <lib/gui/decoration.h> + +// Definition Blit Flags +#define BF_ALPHATEST 1 + +class eLabel: public eDecoWidget +{ +protected: + int blitFlags; + int flags; + eTextPara *para; + gColor transparentBackgroundColor; + int align; + void validate( const eSize* s=0 ); + int eventHandler(const eWidgetEvent &event); + void redrawWidget(gPainter *target, const eRect &area); + int yOffs; + ePtr<gPixmap> shortcutPixmap; // shortcut pixmap to be displayed right after description +public: + void invalidate(); + enum { flagVCenter = 64 }; + eLabel(eWidget *parent, int flags=0 /* RS_WRAP */ , int takefocus=0, const char* deco="eLabel" ); + ~eLabel(); + + void setBlitFlags( int flags ); + void setFlags(int flags); + void removeFlags(int flags); + void setAlign(int align); + void setShortcutPixmap(const eString &shortcut); + int setProperty(const eString &prop, const eString &value); + void setPixmapPosition( const ePoint &p ); + + eSize getExtend(); + ePoint getLeftTop(); + + ePoint pixmap_position, text_position; +}; + +#endif diff --git a/lib/gui/emessage.cpp b/lib/gui/emessage.cpp new file mode 100644 index 00000000..388eb14a --- /dev/null +++ b/lib/gui/emessage.cpp @@ -0,0 +1,163 @@ +#include <lib/gui/emessage.h> + +#include <lib/gui/elabel.h> +#include <lib/gui/ebutton.h> +#include <lib/gui/eskin.h> +#include <lib/gdi/font.h> +#include <lib/base/i18n.h> + +eMessageBox::eMessageBox(eString message, eString caption, int flags, int def): eWindow(0), icon(0) +{ + setText(caption); + int fontsize=eSkin::getActive()->queryValue("fontsize", 20); + int posx = eSkin::getActive()->queryValue("eMessageBox.pos.x", 100); + int posy = eSkin::getActive()->queryValue("eMessageBox.pos.y", 70); + move(ePoint(posx, posy)); + resize(eSize(450, 430)); + + if ( flags > 15 ) // we have to draw an icon + { + ePtr<gPixmap> pm; + switch ( flags & ~15 ) + { + case iconInfo: + eSkin::getActive()->queryImage(pm, "icon_info" ); + break; + case iconQuestion: + eSkin::getActive()->queryImage(pm, "icon_question" ); + break; + case iconWarning: + eSkin::getActive()->queryImage(pm, "icon_warning" ); + break; + case iconError: + eSkin::getActive()->queryImage(pm, "icon_error" ); + break; + } + if (pm) + { + icon = new eLabel(this); + icon->setPixmap( pm ); + icon->pixmap_position=ePoint(0,0); + icon->resize( eSize(pm->x, pm->y) ); + icon->setBlitFlags( BF_ALPHATEST ); + } + } + + text=new eLabel(this); + text->setText(message); + text->resize( eSize( clientrect.width(), clientrect.height() )); + text->setFlags( RS_WRAP|eLabel::flagVCenter ); + eSize txtSize=text->getExtend(); + txtSize+=eSize(8,4); // the given Size of the Text is okay... but the renderer sucks... + text->resize(txtSize); + + // here the two labels ( icon, text) has the correct size.. now we calc the border + + eSize ext; + + if ( icon ) + { + if ( icon->getSize().height() > text->getSize().height() ) + { + eDebug("icon is higher"); + eSize s = icon->getSize(); + icon->move( ePoint( 20, 20 ) ); + text->move( ePoint( 20 + s.width() + 20, icon->getPosition().y() + s.height() / 2 - txtSize.height() / 2 ) ); + ext.setHeight( icon->getPosition().y() + icon->getSize().height() + 20 ); + } + else + { + eDebug("text is higher"); + text->move( ePoint( 20 + icon->getSize().width() + 20 , 20 ) ); + icon->move( ePoint( 20, text->getPosition().y() + text->getSize().height() / 2 - icon->getSize().height() / 2 ) ); + ext.setHeight( text->getPosition().y() + text->getSize().height() + 20 ); + } + ext.setWidth( text->getPosition().x() + text->getSize().width() + 20 ); + } + else + { + text->move( ePoint(20, 20) ); + ext.setWidth( text->getPosition().x() + text->getSize().width()+20 ); + ext.setHeight( text->getPosition().y() + text->getSize().height() + 20 ); + } + + if (ext.width()<150) + ext.setWidth(150); + + int xpos=20; + + if ( flags & 15) + { + for (int i=btOK; i<btMax; i<<=1) + if (flags & i) + { + eButton *b=new eButton(this); + b->resize(eSize(size.width(), fontsize+4)); + const char *t="", *shortcut=""; + switch (i) + { + case btOK: t=_("OK"); shortcut="green"; CONNECT(b->selected, eMessageBox::pressedOK); break; + case btCancel: t=_("Cancel"); shortcut="red"; CONNECT(b->selected, eMessageBox::pressedCancel); break; + case btYes: t=_("Yes"); shortcut="green"; CONNECT(b->selected, eMessageBox::pressedYes); break; + case btNo: t=_("No"); shortcut="red"; CONNECT(b->selected, eMessageBox::pressedNo); break; + } + b->setProperty("shortcut", shortcut); + b->setText(t); + eSize bSize=b->getExtend(); + bSize.setWidth( bSize.width() * 2 ); + bSize.setHeight( fontsize + 4 + 10 ); + b->resize(bSize); + b->move( ePoint( xpos, ext.height() ) ); + + b->loadDeco(); + + if (def == i) + setFocus(b); + + xpos += bSize.width()+20; + if ( xpos+20 > ext.width() ) + cresize( eSize( xpos+20, ext.height() + bSize.height() + 20 ) ); + else + cresize( eSize( ext.width(), ext.height() + bSize.height() + 20 ) ); + } + } + else + cresize( ext ); + zOrderRaise(); +} + +eMessageBox::~eMessageBox() +{ +} + +void eMessageBox::pressedOK() +{ + if ( in_loop ) + close(btOK); + else + hide(); +} + +void eMessageBox::pressedCancel() +{ + if ( in_loop ) + close(btCancel); + else + hide(); +} + +void eMessageBox::pressedYes() +{ + if ( in_loop ) + close(btYes); + else + hide(); +} + +void eMessageBox::pressedNo() +{ + if ( in_loop ) + close(btNo); + else + hide(); +} diff --git a/lib/gui/emessage.h b/lib/gui/emessage.h new file mode 100644 index 00000000..23e4b152 --- /dev/null +++ b/lib/gui/emessage.h @@ -0,0 +1,40 @@ +#ifndef __emessage_h +#define __emessage_h + +#include <lib/gui/ewindow.h> + +class eLabel; + +/** + * \brief A (modal) messagebox. + */ +class eMessageBox: public eWindow +{ + eLabel *text, *icon; +public: + void pressedOK(); + void pressedCancel(); + void pressedYes(); + void pressedNo(); +public: + enum { btOK=1, btCancel=2, btYes=4, btNo=8, btMax}; + enum { iconInfo=16, iconWarning=32, iconQuestion=64, iconError=128 }; + /** + * \brief Creates a messagebox. + * + * example: + * \code +{ + eMessageBox message("Your documentation sucks!\nPlease consider using Neutrino!", "Documentation"); + message.show(); + message.exec(); + message.hide(); +} \endcode + * \param string The string displayed inside the messagebox. + * \param caption The title of the messagebox. + */ + eMessageBox(eString string, eString caption, int flags=btOK, int def=btOK ); + ~eMessageBox(); +}; + +#endif diff --git a/lib/gui/enumber.cpp b/lib/gui/enumber.cpp new file mode 100644 index 00000000..c03ec8f7 --- /dev/null +++ b/lib/gui/enumber.cpp @@ -0,0 +1,447 @@ +#include <lib/gui/enumber.h> +#include <lib/driver/rc.h> +#include <lib/gui/eskin.h> +#include <lib/gui/elabel.h> +#include <lib/gdi/fb.h> +#include <lib/gdi/grc.h> +#include <lib/gdi/font.h> +#include <lib/gui/guiactions.h> + +void eNumber::unpack(__u32 l, int *t) +{ + for (int i=0; i<4; i++) + *t++=(l>>((3-i)*8))&0xFF; +} + +void eNumber::pack(__u32 &l, int *t) +{ + l=0; + for (int i=0; i<4; i++) + l|=(*t++)<<((3-i)*8); +} + +eRect eNumber::getNumberRect(int n) +{ + if (deco_selected && have_focus) + return eRect( deco_selected.borderLeft + n * space_selected, deco_selected.borderTop, dspace, crect_selected.height() ); + else if (deco) + return eRect( deco.borderLeft + n * dspace, deco.borderTop, dspace, crect.height() ); + else + return eRect( n * dspace, 0, dspace, height() ); +} + +void eNumber::redrawNumber(gPainter *p, int n, const eRect &area) +{ + eRect pos = getNumberRect(n); + + if (!area.contains(pos) ) + return; + + p->setForegroundColor((have_focus && n==active)?cursorB:normalB); + p->fill(pos); + p->setFont(font); + + eString t; + if (flags & flagFillWithZeros || ( (flags & flagFixedNum) && n )) + { + eString s = "%0"+eString().setNum(maxdigits)+(base==10?"d":"X"); + const char* p = s.c_str(); + char* tmp = new char[10]; + strcpy( tmp, p ); + t.sprintf(tmp, number[n]); + delete [] tmp; + } + else + { + if (flags&flagHideInput) + t="*"; + else if (base==10) + t.sprintf("%d", number[n]); + else if (base==0x10) + t.sprintf("%X", number[n]); + } + + if (!n && flags & flagPosNeg && neg) + t="-"+t; + + if (n && (flags & flagTime)) + t=":"+t; + + else if (n && ( (flags & flagDrawPoints) || (flags & flagFixedNum)) ) + t="."+t; + + p->setForegroundColor((have_focus && n==active)?cursorF:normalF); + p->setBackgroundColor((have_focus && n==active)?cursorB:normalB); + + p->clip( pos ); + if (!n && len==2 && ((flags & flagFixedNum) || (flags & flagTime)) ) // first element... + { + eTextPara *para = new eTextPara( pos ); + para->setFont( font ); + para->renderString( t ); + para->realign( eTextPara::dirRight ); + p->renderPara( *para ); + para->destroy(); + } + else + p->renderText(pos, t); + + p->clippop(); +} + +double eNumber::getFixedNum() +{ + if (flags & flagFixedNum) + { + if (flags&flagPosNeg && neg) + { + double d = -((double)number[0]+(double)number[1]/1000); + eDebug("getFixedNum %lf", d); + return d; + } + else + { + float d = (double)number[0]+(double)number[1]/1000; + eDebug("getFixedNum %lf", d); + return d; + } + } + else + return 0; +} + +void eNumber::setFixedNum(double d) +{ + eDebug("setFixedNum %lf", d); + if (flags & flagPosNeg) + neg=d<0; + else + neg=0; + + d=fabs(d); + + if (flags & flagFixedNum) + { + number[0]=(int)d; + number[1]=(int)round(( ( d - number[0] ) * 1000) ); + } + else + eDebug("eNumber bug... the Number %s is not a fixed Point number", name.c_str()); +} + +void eNumber::redrawWidget(gPainter *p, const eRect &area) +{ + for (int i=0; i<len; i++) + redrawNumber(p, i, area); + + if (deco_selected && have_focus) + deco_selected.drawDecoration(p, ePoint(width(), height())); + else if (deco) + deco.drawDecoration(p, ePoint(width(), height())); +} + +void eNumber::invalidateNum() +{ + if ( have_focus && deco_selected ) + invalidate( crect_selected ); + else if ( deco ) + invalidate( crect ); + else + invalidate(); +} + +int eNumber::eventHandler(const eWidgetEvent &event) +{ +#ifndef DISABLE_LCD + if (LCDTmp) + ((eNumber*) LCDTmp)->eventHandler(event); +#endif + switch (event.type) + { + case eWidgetEvent::changedSize: + if (deco) + dspace = (crect.width()) / len; + else + dspace = (size.width()) / len; + if (deco_selected) + space_selected = (crect_selected.width()) / len; + break; + case eWidgetEvent::evtAction: + if ( len > 1 && event.action == &i_cursorActions->left) + { + int oldac=active; + active--; + invalidate(getNumberRect(oldac)); + if (active<0) + active=len-1; + if (active!=oldac) + invalidate(getNumberRect(active)); + digit=0; + } else if ( len > 1 && (event.action == &i_cursorActions->right) || (event.action == &i_cursorActions->ok)) + { + int oldac=active; + active++; + invalidate(getNumberRect(oldac)); + if (active>=len) + { + if (event.action == &i_cursorActions->ok) + /*emit*/ selected(number); + active=0; + } + if (active!=oldac) + invalidate(getNumberRect(active)); + digit=0; + } else + break; + return 1; + default: + break; + } + return eDecoWidget::eventHandler(event); +} + +// isactive is the digit (always in the first field ) +// that ist active after get the first focus ! + +eNumber::eNumber(eWidget *parent, int _len, int _min, int _max, int _maxdigits, int *init, int isactive, eWidget* descr, int grabfocus, const char *deco) + :eDecoWidget(parent, grabfocus, deco ), + active(0), + cursorB(eSkin::getActive()->queryScheme("global.selected.background")), + cursorF(eSkin::getActive()->queryScheme("global.selected.foreground")), + normalB(eSkin::getActive()->queryScheme("global.normal.background")), + normalF(eSkin::getActive()->queryScheme("global.normal.foreground")), + have_focus(0), digit(isactive), isactive(isactive), flags(0), descr(descr), tmpDescr(0), + neg(false) +{ + setNumberOfFields(_len); + setLimits(_min, _max); + setMaximumDigits(_maxdigits); + setBase(10); + for (int i=0; init && i<len; i++) + number[i]=init[i]; + addActionMap(&i_cursorActions->map); +} + +eNumber::~eNumber() +{ +} + +int eNumber::keyDown(int key) +{ +#ifndef DISABLE_LCD + if (LCDTmp) + ((eNumber*) LCDTmp)->keyDown(key); +#endif + switch (key) + { + case eRCInput::RC_0 ... eRCInput::RC_9: + { + int nn=(digit!=0)?number[active]*10:0; + nn+=key-eRCInput::RC_0; + if (flags & flagTime) + { + if ( active ) + max = 59; + else + max = 23; + } + else if (flags & flagFixedNum) + { + if (active) + max=999; + else + max=oldmax; + } + if (nn>=min && nn<=max) + { + number[active]=nn; + invalidate(getNumberRect(active)); + digit++; + if ((digit>=maxdigits) || (nn==0)) + { + active++; + invalidate(getNumberRect(active-1)); + digit=0; + /*emit*/ numberChanged(); + if (active>=len) + { + /*emit*/ selected(number); + active=0; + } + else + invalidate(getNumberRect(active)); + } + } + break; + + break; + } + case eRCInput::RC_PLUS: + if (flags & flagPosNeg && neg ) + { + neg=false; + invalidate(getNumberRect(0)); + } + break; + + case eRCInput::RC_MINUS: + if (flags & flagPosNeg && !neg ) + { + neg=true; + invalidate(getNumberRect(0)); + } + default: + return 0; + } + return 1; +} + +void eNumber::gotFocus() +{ + have_focus++; + digit=isactive; + + if (deco && deco_selected) + invalidate(); + else + invalidate(getNumberRect(active)); + +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) // detect if LCD Avail + { + LCDTmp = new eNumber(parent->LCDElement, len, min, max, maxdigits, &(number[0]), isactive, 0, 0); + LCDTmp->hide(); + ((eNumber*)LCDTmp)->setFlags(flags); + eSize s = parent->LCDElement->getSize(); + + if (descr) + { + LCDTmp->move(ePoint(0,s.height()/2)); + LCDTmp->resize(eSize(s.width(), s.height()/2)); + tmpDescr = new eLabel(parent->LCDElement); + tmpDescr->hide(); + tmpDescr->move(ePoint(0,0)); + tmpDescr->resize(eSize(s.width(), s.height()/2)); + tmpDescr->setText(descr->getText()); + tmpDescr->show(); + } + else + { + LCDTmp->resize(s); + LCDTmp->move(ePoint(0,0)); + } + ((eNumber*)LCDTmp)->digit=digit; + ((eNumber*)LCDTmp)->active=active; + ((eNumber*)LCDTmp)->normalF=255; + ((eNumber*)LCDTmp)->normalB=0; + ((eNumber*)LCDTmp)->cursorF=0; + ((eNumber*)LCDTmp)->cursorB=255; + ((eNumber*)LCDTmp)->have_focus=1; + LCDTmp->show(); + } + #endif //DISABLE_LCD +} + +void eNumber::lostFocus() +{ +#ifndef DISABLE_LCD + if (LCDTmp) + { + delete LCDTmp; + LCDTmp=0; + if (tmpDescr) + { + delete tmpDescr; + tmpDescr=0; + } + } +#endif + have_focus--; + + if (deco && deco_selected) + invalidate(); + else + invalidate(getNumberRect(active)); + isactive=0; +} + +void eNumber::setNumber(int f, int n) +{ + if (flags & flagPosNeg) + { + if(!f && n<0) + neg=true; + else + neg=false; + } + else + neg=false; + + if ((f>=0) && (f<len)) + number[f]=abs(n); + + invalidate(getNumberRect(f)); +} + +void eNumber::setLimits(int _min, int _max) +{ + min=_min; + max=_max; + oldmax=max; +} + +void eNumber::setNumberOfFields(int n) +{ + len=n; +} + +void eNumber::setMaximumDigits(int n) +{ + if (n > 16) + n=16; + maxdigits=n; + if (digit >= maxdigits) + digit=0; +} + +void eNumber::setFlags(int _flags) +{ + if (flags&flagFixedNum) + len=2; + + flags=_flags; +} + +void eNumber::setBase(int _base) +{ + base=_base; +} + +void eNumber::setNumber(int n) +{ + if ( flags&flagPosNeg ) + neg = n < 0; + else + neg=0; + + if( len == 1 ) + number[0]=abs(n); + else + for (int i=len-1; i>=0; --i) + { + number[i]=n%base; + n/=base; + } + invalidateNum(); +} + +int eNumber::getNumber() +{ + int n=0; + for (int i=0; i<len; i++) + { + n*=base; + n+=number[i]; + } + return flags&flagPosNeg && neg ? -n : n; +} diff --git a/lib/gui/enumber.h b/lib/gui/enumber.h new file mode 100644 index 00000000..e1b2dcc3 --- /dev/null +++ b/lib/gui/enumber.h @@ -0,0 +1,69 @@ +#ifndef __enumber_h +#define __enumber_h + +#include <lib/gui/ewidget.h> +#include <lib/gui/decoration.h> + +class eLabel; +class gPainter; + +/** + * \brief A widget to enter a number. + */ +class eNumber: public eDecoWidget +{ +private: + void redrawNumber(gPainter *, int n, const eRect &rect); + void redrawWidget(gPainter *, const eRect &rect); + eRect getNumberRect(int n); + int eventHandler(const eWidgetEvent &event); + int number[24]; + int len, dspace, space_selected, active; + gColor cursorB, cursorF, normalB, normalF; + int oldmax; + int have_focus; + int min, max, digit, maxdigits, isactive; + int flags; + int base; + eWidget* descr; + eLabel* tmpDescr; // used for description Label in LCD + bool neg; +protected: + int getActive() { return active; } + int keyDown(int key); + void gotFocus(); + void lostFocus(); +public: + static void unpack(__u32 l, int *t); + static void pack(__u32 &l, int *t); + void invalidateNum(); + Signal1<void, int*> selected; + Signal0<void> numberChanged; + eNumber(eWidget *parent, int len, int min, int max, int maxdigits, int *init, int isactive=0, eWidget* descr=0, int grabfocus=1, const char* deco="eNumber" ); + ~eNumber(); + int getNumber(int f) { if ((f>=0) && (f<len)) return number[f]; return -1; } + double getFixedNum(); + void setFixedNum(double); + void setNumber(int f, int n); + void setLimits(int min, int max); + void setNumberOfFields(int n); + void setMaximumDigits(int n); + enum + { + flagDrawPoints=1, + flagDrawBoxes=2, + flagFillWithZeros=4, + flagTime=8, + flagPosNeg=16, + flagHideInput=32, + flagFixedNum=64 + }; + void setFlags(int flags); + void setBase(int base); + + void setNumber(int n); + int getNumber(); + void setDescr( eWidget *d ) { descr = d; } +}; + +#endif diff --git a/lib/gui/epixmap.cpp b/lib/gui/epixmap.cpp new file mode 100644 index 00000000..c544b007 --- /dev/null +++ b/lib/gui/epixmap.cpp @@ -0,0 +1,44 @@ +#include <lib/gui/epixmap.h> +#include <lib/gui/eskin.h> +#include <lib/gui/init.h> +#include <lib/gui/init_num.h> + +ePixmap::ePixmap(eWidget *parent): eWidget(parent) +{ + position=ePoint(0, 0); + setBackgroundColor(getForegroundColor()); +} + +ePixmap::~ePixmap() +{ +} + +void ePixmap::redrawWidget(gPainter *paint, const eRect &area) +{ + if (pixmap) + paint->blit(*pixmap, position); +} + +void ePixmap::eraseBackground(gPainter *target, const eRect &area) +{ +} + +static eWidget *create_ePixmap(eWidget *parent) +{ + return new ePixmap(parent); +} + +class ePixmapSkinInit +{ +public: + ePixmapSkinInit() + { + eSkin::addWidgetCreator("ePixmap", create_ePixmap); + } + ~ePixmapSkinInit() + { + eSkin::removeWidgetCreator("ePixmap", create_ePixmap); + } +}; + +eAutoInitP0<ePixmapSkinInit> init_ePixmapSkinInit(eAutoInitNumbers::guiobject, "ePixmap"); diff --git a/lib/gui/epixmap.h b/lib/gui/epixmap.h new file mode 100644 index 00000000..e03c76bf --- /dev/null +++ b/lib/gui/epixmap.h @@ -0,0 +1,18 @@ +#ifndef __epixmap_h +#define __epixmap_h + +#include "ewidget.h" +class gPixmap; + +class ePixmap: public eWidget +{ + ePoint position; +public: + ePixmap(eWidget *parent); + ~ePixmap(); + + void redrawWidget(gPainter *paint, const eRect &area); + void eraseBackground(gPainter *target, const eRect &area); +}; + +#endif diff --git a/lib/gui/eprogress.cpp b/lib/gui/eprogress.cpp new file mode 100644 index 00000000..3528929e --- /dev/null +++ b/lib/gui/eprogress.cpp @@ -0,0 +1,136 @@ +#include <lib/gui/eprogress.h> + +#include <stdlib.h> + +#include <lib/gdi/erect.h> +#include <lib/gdi/fb.h> +#include <lib/gdi/lcd.h> +#include <lib/gui/eskin.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> + +eProgress::eProgress(eWidget *parent, int takefocus) + : eWidget(parent, takefocus) +{ + left=eSkin::getActive()->queryScheme("eProgress.left"); + right=eSkin::getActive()->queryScheme("eProgress.right"); + perc=start=0; + border=2; + direction=0; + setForegroundColor(eSkin::getActive()->queryScheme("eProgress.border")); +} + +eProgress::~eProgress() +{ +} + +void eProgress::setPerc(int p) +{ + if (perc != p) + { + perc=p; + invalidate(); + } +} + +void eProgress::setStart(int p) +{ + if (start != p) + { + start=p; + invalidate(); + } +} + +void eProgress::redrawWidget(gPainter *target, const eRect &area) +{ + // border malen + target->setForegroundColor(getForegroundColor()); + target->fill(eRect(0, 0, size.width(), border)); + target->fill(eRect(0, border, border, size.height()-border)); + target->fill(eRect(border, size.height()-border, size.width()-border, border)); + target->fill(eRect(size.width()-border, border, border, size.height()-border)); + + switch (direction) + { + case 0: + { + int st=start*(size.width()-border*2)/100; + if (st<0) + st=0; + if (st>(size.width()-border*2)) + st=size.width()-border*2; + + int dh=perc*(size.width()-border*2)/100; + if (dh<0) + dh=0; + if ((dh+st)>(size.width()-border*2)) + dh=size.width()-border*2-st; + + target->setForegroundColor(left); + target->fill(eRect(border+start, border, dh, size.height()-border*2)); + target->setForegroundColor(right); + target->fill(eRect(border+dh+st, border, size.width()-border*2-dh-st, size.height()-border*2)); + if (st) + target->fill(eRect(border, border, st, size.height()-border*2)); + break; + } + case 1: + { + int st=start*(size.height()-border*2)/100; + if (st<0) + st=0; + if (st>(size.height()-border*2)) + st=size.height()-border*2; + + int dh=perc*(size.height()-border*2)/100; + if (dh<0) + dh=0; + if ((dh+st)>(size.height()-border*2)) + dh=size.height()-border*2-st; + + target->setForegroundColor(left); + target->fill(eRect(border, border+st, size.width()-border*2, dh)); + target->setForegroundColor(right); + target->fill(eRect(border, border+dh+st, size.width()-border*2, size.height()-border*2-dh-st)); + if (st) + target->fill(eRect(border, border, size.width()-border*2, st)); + break; + } + } +} + +int eProgress::setProperty(const eString &prop, const eString &value) +{ + if (prop=="leftColor") + left=eSkin::getActive()->queryColor(value); + else if (prop=="rightColor") + right=eSkin::getActive()->queryColor(value); + else if (prop=="border") + border=atoi(value.c_str()); + else if (prop=="direction") + direction=atoi(value.c_str()); + else + return eWidget::setProperty(prop, value); + return 0; +} + +static eWidget *create_eProgress(eWidget *parent) +{ + return new eProgress(parent); +} + +class eProgressSkinInit +{ +public: + eProgressSkinInit() + { + eSkin::addWidgetCreator("eProgress", create_eProgress); + } + ~eProgressSkinInit() + { + eSkin::removeWidgetCreator("eProgress", create_eProgress); + } +}; + +eAutoInitP0<eProgressSkinInit> init_eProgressSkinInit(eAutoInitNumbers::guiobject, "eProgress"); diff --git a/lib/gui/eprogress.h b/lib/gui/eprogress.h new file mode 100644 index 00000000..23fb40ca --- /dev/null +++ b/lib/gui/eprogress.h @@ -0,0 +1,49 @@ +#ifndef __eprogress_h +#define __eprogress_h + +#include <lib/gui/ewidget.h> +#include <lib/gdi/grc.h> + +/** + * \brief A progressbar. + * + * Useful for displaying a progress or stuff. + */ +class eProgress: public eWidget +{ +protected: + int perc, border, start; + int direction; + gColor left, right; +public: + eProgress(eWidget *parent, int takeFocus=0); + ~eProgress(); + + /** + * \brief Sets the value. + * + * \param perc The range is \c 0..100 + */ + void setPerc(int perc); + void setStart(int perc); + void redrawWidget(gPainter *target, const eRect &area); + + /** + * \brief Sets a property. + * + * Valid, eProgress specific properties are: + * \arg \c leftColor, the color of the left part + * \arg \c rightColor, the color of the right part + * \arg \c border, the size of the border (in pixels) + * \arg \c direction, direction (0 for horiz., 1 for vert.) + * \sa eWidget::setProperty + */ + int setProperty(const eString &prop, const eString &value); + + void setDirection(int d) { direction = d; } + void setBorder( int b ) { border = b; } + void setLeftColor( const gColor& c ) { left = c; } + void setRightColor( const gColor& c ) { right = c; } +}; + +#endif diff --git a/lib/gui/eservicegrid.cpp b/lib/gui/eservicegrid.cpp new file mode 100644 index 00000000..f80c6734 --- /dev/null +++ b/lib/gui/eservicegrid.cpp @@ -0,0 +1,74 @@ +#include <lib/gui/eservicegrid.h> + +eServiceGrid::eServiceGrid(eWidget *parent): eWidget(parent) +{ + para=0; + grid=0; + + elemsize=eSize(16, 16); +} + +void eServiceGrid::createGrid(eSize gs) +{ + gridsize=gs; + if (grid) + delete[] grid; + if (!(gridsize.x() && gridsize.y())) + return; + grid=new (eService*)[gridsize.x()*gridsize.y()]; +} + +eService **eServiceGrid::allocateGrid(eSize size) +{ + for (int y=0; y<gridsize.height(); y++) + for (int x=0; x<gridsize.width(); x++) + { + int ok=1; + for (int cy=0; ok && cy<size.height(); cy++) + for (int cx=0; ok && cx<size.width(); cx++) + if (grid[gridsize.width()*(y+cy)+x+cx]) + { + ok=0; + break; + } + if (ok) + return grid+gridsize.width()*(y+cy)+x+cx; + } + return 0; +} + +void eServiceGrid::setGridSize(int gx, int gy) +{ + createGrid(eSize(gx, gy)); +} + +void eServiceGrid::addService(eService *service) +{ + eTextPara temp; + temp.setFont(font); + temp.renderText(service->service_name); + eSize size=temp.getExtends(); + eSize gsize=eSize((size.width()+elemsize.width()-1)/elemsize.width(), (size.height()+elemsize.height()-1)/elemsize.height()); + eService **sp=allocateGrid(gsize); + if (!sp) + return; + for (int cy=0; ok && cy<gsize.height(); cy++) + for (int cx=0; ok && cx<gsize.width(); cx++) + sp[cy*gridsize.width()+cx]=service; +} + + +void eServiceGrid::validate() +{ + eService **gp=grid; + for (int y=0; y<gridsize.height(); y++) + for (int x=0; x<gridsize.width(); x++) + { + if (*gp) + { + para->setCursor(x*elemsize.width(), y*elemsize.height()); + para->renderString((*gp)->service_name); + } + *gp++; + } +} diff --git a/lib/gui/eservicegrid.h b/lib/gui/eservicegrid.h new file mode 100644 index 00000000..69d3fd9a --- /dev/null +++ b/lib/gui/eservicegrid.h @@ -0,0 +1,27 @@ +#ifndef __eservicegrid_h +#define __eservicegrid_h + +#include "ewidget.h" + +class eServiceGrid: public eWidget +{ + eService *(*grid); + eSize gridsize; + eSize elemsize; + + eTextPara *para; + + void validate(); + + void createGrid(eSize gridsize); + eService **allocateGrid(eSize size); + +public: + eServiceGrid(eWidget *parent); + + void setGridSize(int gx, int gy); + void addService(eService *service); + +}; + +#endif diff --git a/lib/gui/eskin.cpp b/lib/gui/eskin.cpp new file mode 100644 index 00000000..6cb98abd --- /dev/null +++ b/lib/gui/eskin.cpp @@ -0,0 +1,760 @@ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> + +#include <lib/gui/eskin.h> +#include <lib/gui/ewidget.h> +#include <lib/gdi/gfbdc.h> +#include <lib/gdi/glcddc.h> +#include <lib/gdi/epng.h> +#include <lib/base/eerror.h> +#include <lib/gdi/font.h> +#include <lib/base/eptrlist.h> + +std::map< eString,tWidgetCreator > eSkin::widget_creator; + +eSkin *eSkin::active; + +eNamedColor *eSkin::searchColor(const eString &name) +{ + for (std::list<eNamedColor>::iterator i(colors.begin()); i != colors.end(); ++i) + { + if (!i->name.compare(name)) + return &*i; + } + return 0; +} + +void eSkin::clear() +{ +} + +void eSkin::addWidgetCreator(const eString &name, tWidgetCreator creator) +{ + widget_creator[name] = creator; // add this tWidgetCreator to map... if exist.. overwrite +} + +void eSkin::removeWidgetCreator(const eString &name, tWidgetCreator creator) +{ + widget_creator.erase(name); +} + +int eSkin::parseColor(const eString &name, const char* color, gRGB &col) +{ + if (color[0]=='#') + { + unsigned long vcol=0; + if (sscanf(color+1, "%lx", &vcol)!=1) + { + eDebug("invalid color named \"%s\" (value: %s)", name.c_str(), color+1); + return -1; + } + col.r=(vcol>>16)&0xFF; + col.g=(vcol>>8)&0xFF; + col.b=vcol&0xFF; + col.a=(vcol>>24)&0xFF; + } else + { + eNamedColor *n=searchColor(color); + if (!n) + { + eDebug("invalid color named \"%s\" (alias to: \"%s\")", name.c_str(), color); + return -1; + } + col=n->value; + } + return 0; +} + +int eSkin::parseColors(XMLTreeNode *xcolors) +{ + XMLTreeNode *node; + + std::list<eNamedColor>::iterator newcolors=colors.end(); + + for (node=xcolors->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "color")) + { + eDebug("junk found in colorsection (%s)", node->GetType()); + continue; + } + + const char *name=node->GetAttributeValue("name"), *color=node->GetAttributeValue("color"), *end=node->GetAttributeValue("end"); + + if (!color || !name) + { + eDebug("no color/name specified"); + continue; + } + + eNamedColor col; + col.name=name; + + const char *size=node->GetAttributeValue("size"); + + if (size) + col.size=atoi(size); + else + col.size=0; + + if (!col.size) + col.size=1; + + if ((col.size>1) && (!end)) + { + eDebug("no end specified in \"%s\" but is gradient", name); + continue; + } + + if (parseColor(name, color, col.value)) + continue; + + if (end && parseColor(name, end, col.end)) + continue; + + colors.push_back(col); + if (newcolors == colors.end()) + --newcolors; + } + + for (std::list<eNamedColor>::iterator i(newcolors); i != colors.end(); ++i) + { + eNamedColor &col=*i; + int d; + for (d=0; d<maxcolors; d+=col.size) + { + int s; + for (s=0; s<col.size; s++) + if ((d+s>maxcolors) || colorused[d+s]) + break; + if (s==col.size) + break; + } + if (d==maxcolors) + continue; + col.index=gColor(d); + for (int s=0; s<col.size; s++, d++) + { + colorused[d]=1; + if (s) + { + int rdiff=-col.value.r+col.end.r; + int gdiff=-col.value.g+col.end.g; + int bdiff=-col.value.b+col.end.b; + int adiff=-col.value.a+col.end.a; + rdiff*=s; rdiff/=(col.size-1); + gdiff*=s; gdiff/=(col.size-1); + bdiff*=s; bdiff/=(col.size-1); + adiff*=s; adiff/=(col.size-1); + palette[d].r=col.value.r+rdiff; + palette[d].g=col.value.g+gdiff; + palette[d].b=col.value.b+bdiff; + palette[d].a=col.value.a+adiff; + } else + palette[d]=col.value; + } + } + return 0; +} + +int eSkin::parseScheme(XMLTreeNode *xscheme) +{ + XMLTreeNode *node; + for (node=xscheme->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "map")) + { + eDebug("illegal scheme entry found: %s", node->GetType()); + continue; + } + char *name=node->GetAttributeValue("name"), *color=node->GetAttributeValue("color"); + if (!name || !color) + { + eDebug("no name or color specified in colorscheme"); + continue; + } + eString base=color; + int offset=0, p; + if ((p=base.find('+'))!=-1) + { + offset=atoi(base.mid(p).c_str()); + base=base.left(p); + } + eNamedColor *n=searchColor(base); + if (!n) + { + eDebug("illegal color \"%s\" specified", base.c_str()); + continue; + } + scheme[name] = gColor(n->index+offset); + } + return 0; +} + +int eSkin::parseFontAlias(XMLTreeNode *xscheme) +{ + XMLTreeNode *node; + for (node=xscheme->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "map")) + { + eDebug("illegal fontalias entry found: %s", node->GetType()); + continue; + } + char *font=node->GetAttributeValue("font"), + *name=node->GetAttributeValue("name"), + *size=node->GetAttributeValue("size"); + + if (!name || !font || !size) + { + eDebug("no name, alias or size spezified in fontaliase"); + continue; + } + + std::map<eString, gFont>::iterator it = fontAlias.find(name); + if (it != fontAlias.end()) + continue; + + std::map<eString, eString>::iterator i = fonts.find(font); + if (i == fonts.end()) + { + eDebug("font %s not found, skip make alias %s", font, name); + continue; + } + fontAlias[name]=gFont(i->second, atoi(size)); + } + return 0; +} + +int eSkin::parseImages(XMLTreeNode *inode) +{ + char *abasepath=inode->GetAttributeValue("basepath"); + if (!abasepath) + abasepath=""; + eString basepath=eString("/enigma/pictures/"); + if (abasepath[0] == '/') // allow absolute paths + basepath=""; + basepath+=abasepath; + if (basepath[basepath.length()-1]!='/') + basepath+="/"; + + for (XMLTreeNode *node=inode->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "img")) + { + eDebug("illegal image entry found: %s", node->GetType()); + continue; + } + const char *name=node->GetAttributeValue("name"); + if (!name) + { + eDebug("illegal <img> entry: no name"); + continue; + } + const char *src=node->GetAttributeValue("src"); + if (!src) + { + eDebug("image/img=\"%s\" no src given", name); + continue; + } + std::map<eString, ePtr<gPixmap> >::iterator it = images.find(name); + if (it != images.end()) + { +// eDebug("Image with name %s already loaded, skip %s", name, src); + continue; + } + ePtr<gPixmap> image=0; + eString filename=basepath + eString(src); + if (abasepath[0] != '/') + { + // search first in CONFIGDIR + image=loadPNG((eString(CONFIGDIR)+filename).c_str()); + if (!image) + image=loadPNG((eString(DATADIR)+filename).c_str()); + } + else // abs path + image=loadPNG(filename.c_str()); + + if (!image) + { + eDebug("image/img=\"%s\" - %s: file not found", name, filename.c_str()); + continue; + } + + if (paldummy && !node->GetAttributeValue("nomerge")) + { + gPixmapDC mydc(image); + gPainter p(mydc); + p.mergePalette(paldummy); + } + images[name] = image; + } + return 0; +} + +int eSkin::parseImageAlias(XMLTreeNode *xvalues) +{ + for (XMLTreeNode *node=xvalues->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "map")) + { + eDebug("illegal values entry %s", node->GetType()); + continue; + } + const char *name=node->GetAttributeValue("name"), + *img=node->GetAttributeValue("img"); + if (!name || !img) + { + eDebug("map entry has no name or img"); + continue; + } + std::map<eString, eString>::iterator it = imageAlias.find(name); + if (it != imageAlias.end()) + { + eDebug("imagealias %s does exist, skip make alias for image %s", name, img); + continue; + } + std::map<eString, ePtr<gPixmap> >::iterator i = images.find(img); + if (i == images.end()) + { + eDebug("image %s not found, skip make alias %s", img , name); + continue; + } + imageAlias[name]=img; + } + return 0; +} + +int eSkin::parseFonts(XMLTreeNode *xfonts) +{ + const char *abasepath=xfonts->GetAttributeValue("basepath"); + eString basepath=abasepath?abasepath:FONTDIR; + + if (basepath.length()) + if (basepath[basepath.length()-1]!='/') + basepath+="/"; + + for (XMLTreeNode *node=xfonts->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "font")) + { + eDebug("illegal fonts entry %s", node->GetType()); + continue; + } + const char *file=node->GetAttributeValue("file"); + if (!file) + { + eDebug("fonts entry has no file"); + continue; + } + const char *name=node->GetAttributeValue("name"); + if (!name) + { + eDebug("fonts entry has no name use filename %s as name", file); + name = file; + } + std::map<eString, eString>::iterator it = fonts.find(name); + const char *ascale=node->GetAttributeValue("scale"); + int scale=0; + if (ascale) + scale=atoi(ascale); + if (!scale) + scale=100; + if (it != fonts.end()) + { + eDebug("Font with name %s already loaded, skip %s", name, file); + continue; + } + fonts[name]=fontRenderClass::getInstance()->AddFont(basepath+eString(file), name, scale); + if (node->GetAttributeValue("replacement")) + eTextPara::setReplacementFont(name); + } + return 0; +} + +int eSkin::parseValues(XMLTreeNode *xvalues) +{ + for (XMLTreeNode *node=xvalues->GetChild(); node; node=node->GetNext()) + { + if (strcmp(node->GetType(), "value")) + { + eDebug("illegal values entry %s", node->GetType()); + continue; + } + const char *name=node->GetAttributeValue("name"); + if (!name) + { + eDebug("values entry has no name"); + continue; + } + const char *value=node->GetAttributeValue("value"); + if (!value) + { + eDebug("values entry has no value"); + continue; + } + std::map<eString, int>::iterator it = values.find(name); + if (it != values.end()) + { + eDebug("value %s does exist, skip make value %s=%i", name, value); + continue; + } + values[name]=atoi(value); + } + return 0; +} + +gDC *eSkin::getDCbyName(const char *name) +{ + gPixmapDC *dc=0; + if (!strcmp(name, "fb")) + dc=gFBDC::getInstance(); +#ifndef DISABLE_LCD + else if (!strcmp(name, "lcd")) + dc=gLCDDC::getInstance(); +#endif + return dc; +} + +int eSkin::build(eWidget *widget, XMLTreeNode *node) +{ +// eDebug("building a %s", node->GetType()); +/* if (widget->getType() != node->GetType()) + return -1;*/ + + for (XMLAttribute *attrib=node->GetAttributes(); attrib; attrib=attrib->GetNext()) + { +// eDebug("setting %s := %s", attrib->GetName(), attrib->GetValue()); + if (widget->setProperty(attrib->GetName(), attrib->GetValue())) + { + eDebug("failed"); + return -1; + } + } + for (XMLTreeNode *c=node->GetChild(); c; c=c->GetNext()) + { + eWidget *w=0; + + const char *name=c->GetAttributeValue("name"); + + if (name) + w=widget->search(name); + + if (!w) + { + std::map< eString, tWidgetCreator >::iterator it = widget_creator.find(c->GetType()); + + if ( it == widget_creator.end() ) + { + eWarning("widget class %s does not exist", c->GetType()); + return -ENOENT; + } + w = (it->second)(widget); + } + if (!w) + { + // eDebug("failed."); + return -EINVAL; + } + w->zOrderRaise(); + int err; + if ((err=build(w, c))) + { + return err; + } + } + return 0; +} + +eSkin::eSkin() +{ + maxcolors=256; + + palette=new gRGB[maxcolors]; + + memset(palette, 0, sizeof(gRGB)*maxcolors); + paldummy=new gImage(eSize(1, 1), 8); + paldummy->clut.data=palette; + paldummy->clut.colors=maxcolors; + + colorused=new int[maxcolors]; + memset(colorused, 0, maxcolors*sizeof(int)); +} + +eSkin::~eSkin() +{ + if (active==this) + active=0; + + clear(); + + delete colorused; + + for (std::map<eString, ePtr<gPixmap> >::iterator it(images.begin()); it != images.end(); it++) + delete it->second; + + if (paldummy) + delete paldummy; +} + +int eSkin::load(const char *filename) +{ + eDebug("loading skin: %s", filename); + FILE *in=fopen(filename, "rt"); + if (!in) + return -1; + + parsers.push_front(new XMLTreeParser("ISO-8859-1")); + XMLTreeParser &parser=*parsers.first(); + char buf[2048]; + + int done; + do + { + unsigned int len=fread(buf, 1, sizeof(buf), in); + done=len<sizeof(buf); + if (!parser.Parse(buf, len, done)) + { + eDebug("parse error: %s at line %d", + parser.ErrorString(parser.GetErrorCode()), + parser.GetCurrentLineNumber()); + parsers.pop_front(); + fclose(in); + return -1; + } + } while (!done); + fclose(in); + + XMLTreeNode *root=parser.RootNode(); + if (!root) + return -1; + if (strcmp(root->GetType(), "eskin")) + { + eDebug("not an eskin"); + return -1; + } + + return 0; +} + +void eSkin::parseSkins() +{ + for (ePtrList<XMLTreeParser>::reverse_iterator it(parsers); it != parsers.rend(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "colors")) + parseColors(node); + } + + for (ePtrList<XMLTreeParser>::reverse_iterator it(parsers); it != parsers.rend(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "colorscheme")) + parseScheme(node); + } + + for (ePtrList<XMLTreeParser>::iterator it(parsers); it != parsers.end(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "fonts")) + parseFonts(node); + } + + for (ePtrList<XMLTreeParser>::iterator it(parsers); it != parsers.end(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "fontalias")) + parseFontAlias(node); + } + + for (ePtrList<XMLTreeParser>::iterator it(parsers); it != parsers.end(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "images")) + parseImages(node); + + } + + for (ePtrList<XMLTreeParser>::iterator it(parsers); it != parsers.end(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "imagealias")) + parseImageAlias(node); + + } + + for (ePtrList<XMLTreeParser>::iterator it(parsers); it != parsers.end(); it++) + { + XMLTreeNode *node=it->RootNode(); + + for (node=node->GetChild(); node; node=node->GetNext()) + if (!strcmp(node->GetType(), "values")) + parseValues(node); + } +} + + +int eSkin::build(eWidget *widget, const char *name) +{ + for (parserList::iterator i(parsers.begin()); i!=parsers.end(); ++i) + { + XMLTreeNode *node=i->RootNode(); + node=node->GetChild(); + while (node) + { + if (!strcmp(node->GetType(), "object")) + { + const char *oname=node->GetAttributeValue("name"); + if (!std::strcmp(name, oname)) + { + node=node->GetChild(); + return build(widget, node); + } + } + node=node->GetNext(); + } + } + eDebug("didn't found it"); + return -ENOENT; +} + +void eSkin::setPalette(gPixmapDC *pal) +{ + if (palette) + { + gPainter p(*pal); + p.setPalette(palette, 0, 256); + } +} + +eSkin *eSkin::getActive() +{ + if (!active) + eFatal("no active skin"); + return active; +} + +void eSkin::makeActive() +{ + active=this; +} + +gColor eSkin::queryScheme(const eString& name) const +{ + eString base=name; + int offset=0, p; + if ((p=base.find('+'))!=-1) + { + offset=atoi(base.mid(p).c_str()); + base=base.left(p); + } + + std::map<eString, gColor>::const_iterator it = scheme.find(base); + + if (it != scheme.end()) + return it->second + offset; + +// eWarning("%s does not exist", name.c_str()); + + return gColor(0); +} + +RESULT eSkin::queryImage(ePtr<gPixmap> &ptr, const eString& name) const +{ + eString img; + + std::map<eString, eString>::const_iterator i = imageAlias.find(name); + + if (i != imageAlias.end()) + img = i->second; + else + img = name; + + std::map<eString, ePtr<gPixmap> >::const_iterator it = images.find(img); + + if (it != images.end()) + ptr = it->second; + + return 0; +} + +int eSkin::queryValue(const eString& name, int d) const +{ + std::map<eString, int>::const_iterator it = values.find(name); + + if (it != values.end()) + return it->second; + + return d; +} + +gColor eSkin::queryColor(const eString& name) +{ + char *end; + + int numcol=strtol(name.c_str(), &end, 10); + + if (!*end) + return gColor(numcol); + + eString base=name; + int offset=0, p; + if ((p=base.find('+'))!=-1) + { + offset=atoi(base.mid(p).c_str()); + base=base.left(p); + } + + eNamedColor *col=searchColor(base); + + if (!col) + { + return queryScheme(name); + } else + return col->index + offset; +} + +gFont eSkin::queryFont(const eString& name) +{ + std::map<eString, gFont>::iterator it = fontAlias.find(name); // check if name is a font alias + + if ( it != fontAlias.end() ) // font alias found + return it->second; + + eString family; + int size=0; + + unsigned int sem = name.rfind(';'); // check if exist ';' in name + if (sem != eString::npos) // then exist + { + family=name.left(sem); + size = atoi( name.mid(sem+1).c_str() ); + if (size<=0) + size=16; + } + + std::map<eString, eString>::iterator i = fonts.find(family); // check if family is a font name + if ( i != fonts.end() ) // font exist + return gFont(i->second, size); + + for (i = fonts.begin() ; i != fonts.end(); i++) // as last check if family name is a complete font Face + if ( i->second == family) + return gFont(i->second, size); + + eFatal("Font %s does not exist", name.c_str() ); // halt Programm now... Font does not exist + + return gFont(); +} diff --git a/lib/gui/eskin.h b/lib/gui/eskin.h new file mode 100644 index 00000000..0a6bd352 --- /dev/null +++ b/lib/gui/eskin.h @@ -0,0 +1,87 @@ +#ifndef __eskin_h +#define __eskin_h + +#include <list> +#include <map> +#include <xmltree.h> + +#include <lib/base/estring.h> +#include <lib/base/eptrlist.h> +#include <lib/gdi/grc.h> + +class eWidget; +class gPixmap; +typedef eWidget *(*tWidgetCreator)(eWidget *parent); + +struct eNamedColor +{ + eString name; + gRGB value, end; + int index; + int size; +}; + +class eSkin +{ + typedef ePtrList<XMLTreeParser> parserList; + parserList parsers; + void clear(); + + int parseColor(const eString& name, const char *color, gRGB &col); + int parseColors(XMLTreeNode *colors); + int parseScheme(XMLTreeNode *scheme); + int parseImages(XMLTreeNode *images); + int parseImageAlias(XMLTreeNode *images); + int parseValues(XMLTreeNode *values); + int parseFonts(XMLTreeNode *fonts); + int parseFontAlias(XMLTreeNode *fonts); + + gDC *getDCbyName(const char *name); + + gRGB *palette; + int maxcolors; + gImage *paldummy; + int *colorused; + + static std::map< eString, tWidgetCreator > widget_creator; + int build(eWidget *widget, XMLTreeNode *rootwidget); + + std::list<eNamedColor> colors; + std::map<eString, gColor> scheme; + std::map<eString, ePtr<gPixmap> > images; + std::map<eString, int> values; + std::map<eString, eString> fonts; + std::map<eString, gFont> fontAlias; + std::map<eString, eString> imageAlias; + + eNamedColor *searchColor(const eString &name); + + static eSkin *active; +public: + eSkin(); + ~eSkin(); + + static void addWidgetCreator(const eString &name, tWidgetCreator creator); + static void removeWidgetCreator(const eString &name, tWidgetCreator creator); + + int load(const char *filename); + void parseSkins(); + + int build(eWidget *widget, const char *name); + void setPalette(gPixmapDC *pal); + + gColor queryColor(const eString &name); + gColor queryScheme(const eString &name) const; + RESULT queryImage(ePtr<gPixmap> &pixmap, const eString &name) const; + int queryValue(const eString &name, int d) const; + gFont queryFont(const eString &name); + + void makeActive(); + + static eSkin *getActive(); +}; + +#define ASSIGN(v, t, n) \ + v =(t*)search(n); if (! v ) { eWarning("skin has undefined element: %s", n); v=new t(this); } + +#endif diff --git a/lib/gui/eskin_register.cpp b/lib/gui/eskin_register.cpp new file mode 100644 index 00000000..a212449b --- /dev/null +++ b/lib/gui/eskin_register.cpp @@ -0,0 +1,44 @@ +#include <lib/gui/eskin_register.h> +#include <lib/gui/eskin.h> +#include <lib/gdi/gfbdc.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/base/econfig.h> + +#define DEFAULTSKIN "stone.esml" + +class eSkinInit +{ + eSkin default_skin; +public: + eSkinInit() + { + if (default_skin.load( CONFIGDIR "/enigma/skins/default.esml")) + if (default_skin.load( DATADIR "/enigma/skins/default.esml")) + eFatal("skin load failed (" DATADIR "/enigma/skins/default.esml)"); + + eString skinfile=DEFAULTSKIN; + + char *temp=0; + if (!eConfig::getInstance()->getKey("/ezap/ui/skin", temp)) + { + skinfile=temp; + free(temp); + } + + if (default_skin.load(skinfile.c_str())) + { + eWarning("failed to load user defined skin %s, falling back to " DEFAULTSKIN, skinfile.c_str()); + if (default_skin.load(CONFIGDIR "/enigma/skins/" DEFAULTSKIN)) + if (default_skin.load(DATADIR "/enigma/skins/" DEFAULTSKIN)) + eFatal("couldn't load fallback skin " DATADIR "/enigma/skins/" DEFAULTSKIN); + } + + default_skin.parseSkins(); + + default_skin.setPalette(gFBDC::getInstance()); + default_skin.makeActive(); + } +}; + +eAutoInitP0<eSkinInit> init_skin(eAutoInitNumbers::skin, "skin subsystem"); diff --git a/lib/gui/eskin_register.h b/lib/gui/eskin_register.h new file mode 100644 index 00000000..d9373c71 --- /dev/null +++ b/lib/gui/eskin_register.h @@ -0,0 +1,8 @@ +#ifndef __eskin_register +#define __eskin_register + +void eSkin_init(); +void eSkin_close(); + +#endif + diff --git a/lib/gui/ewidget.cpp b/lib/gui/ewidget.cpp new file mode 100644 index 00000000..72abcc43 --- /dev/null +++ b/lib/gui/ewidget.cpp @@ -0,0 +1,1137 @@ +#include <errno.h> + +#include <lib/base/eptrlist.h> +#include <lib/base/eerror.h> +#include <lib/gdi/gfbdc.h> +#include <lib/gdi/epng.h> +#include <lib/gui/actions.h> +#include <lib/gui/eskin.h> +#include <lib/gui/ewidget.h> +#include <lib/gui/guiactions.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> + +eWidget *eWidget::root; +Signal2< void, ePtrList<eAction>*, int >eWidget::showHelp; +eWidget::actionMapList eWidget::globalActions; + +eWidget::eWidget(eWidget *_parent, int takefocus) + :helpID(0), parent(_parent ? _parent : root), + shortcut(0), shortcutFocusWidget(0), + focus(0), TLW(0), takefocus(takefocus), + state( parent && !(parent->state&stateVisible) ? stateShow : 0 ), + target(0), in_loop(0), have_focus(0), just_showing(0), + font( parent ? parent->font : eSkin::getActive()->queryFont("global.normal") ), + backgroundColor(_parent?gColor(-1):gColor(eSkin::getActive()->queryScheme("global.normal.background"))), + foregroundColor(_parent?parent->foregroundColor:gColor(eSkin::getActive()->queryScheme("global.normal.foreground"))), + pixmap(0) +#ifndef DISABLE_LCD + ,LCDTitle(0) + ,LCDElement(0) + ,LCDTmp(0) +#endif +{ + if (takefocus) + getTLW()->focusList()->push_back(this); + + if (parent) + parent->childlist.push_back(this); + + addActionMap(&i_cursorActions->map); +} + +eWidget::~eWidget() +{ + hide(); + if (takefocus) + { + getTLW()->focusList()->remove(this); + if (getTLW()->focus == this) + eFatal("focus still held."); + } + + if (shortcut) + getTLW()->actionListener.remove(this); + + if (parent && !parent->childlist.empty()) + parent->childlist.remove(this); + + while (!childlist.empty()) + delete childlist.front(); +} + +void eWidget::takeFocus() +{ + // desktop shouldnt receive global focus + ASSERT (parent); + // childs shouldnt receive global focus + ASSERT (!parent->parent); +#warning fix me +#if 0 + if (!have_focus) + { + oldTLfocus=eZap::getInstance()->focus; + eZap::getInstance()->focus=this; +/* if (oldTLfocus) + { + eDebug("focus problem"); + eFatal("da hat %s den focus und %s will ihn haben", oldTLfocus->getText().c_str(), getText().c_str()); + } */ + addActionMap(&i_focusActions->map); + } +#endif + ++have_focus; +} + +void eWidget::releaseFocus() +{ + // desktop shouldnt receive global focus + ASSERT (parent); + // childs shouldnt receive global focus + ASSERT (!parent->parent); + ASSERT (have_focus); + + if (have_focus) + { + --have_focus; + if (!have_focus) + { + removeActionMap(&i_focusActions->map); +#warning fixme +#if 0 + if (eZap::getInstance()->focus==this) // if we don't have lost the focus, ... + eZap::getInstance()->focus=oldTLfocus; // give it back + else + eFatal("someone has stolen the focus"); +#endif + } + } +} + +void eWidget::_willShow() +{ + ASSERT(state&stateShow); + ASSERT(!(state&stateVisible)); + state|=stateVisible; + if (takefocus) + getTLW()->takeFocus(); + willShow(); +} + +void eWidget::_willHide() +{ + ASSERT(state&stateShow); + ASSERT(state&stateVisible); + state&=~stateVisible; + + willHide(); + if (takefocus) + getTLW()->releaseFocus(); +} + +void eWidget::willShow() +{ + event(eWidgetEvent(eWidgetEvent::willShow)); +} + +void eWidget::willHide() +{ + event(eWidgetEvent(eWidgetEvent::willHide)); +} + +void eWidget::setPalette() +{ +} + +void eWidget::resize(const eSize& nsize) +{ + size=nsize; + recalcClientRect(); + event(eWidgetEvent(eWidgetEvent::changedSize)); + recalcClip(); +} + +void eWidget::recalcAbsolutePosition() +{ + absPosition = (parent?(parent->getAbsolutePosition()+parent->clientrect.topLeft()+position):position); + for (ePtrList<eWidget>::iterator it( childlist ); it != childlist.end(); ++it ) + it->recalcAbsolutePosition(); +} + +void eWidget::move(const ePoint& nposition) +{ + position=nposition; + recalcClip(); + recalcAbsolutePosition(); + event(eWidgetEvent(eWidgetEvent::changedPosition)); +} + +void eWidget::cresize(const eSize& nsize) +{ + recalcClientRect(); + resize(eSize(nsize.width()+size.width()-clientrect.width(), nsize.height()+size.height()-clientrect.height())); +} + +void eWidget::cmove(const ePoint& nposition) +{ + recalcClientRect(); + move(ePoint(nposition.x()-clientrect.x(), nposition.y()-clientrect.y())); +} + +void eWidget::redraw(eRect area) // area bezieht sich nicht auf die clientarea +{ + if (getTLW()->just_showing) + return; + if (state & stateVisible ) + { + if (area.isNull()) + area=eRect(0, 0, size.width(), size.height()); + if (area.width()>0) + { + gPainter *p=getPainter(area); + if (p) + { + eraseBackground(p, area); + redrawWidget(p, area); + delete p; + } + } + if(!childlist.empty()) + { + area.moveBy(-clientrect.x(), -clientrect.y()); // ab hier jetzt schon. + + ePtrList<eWidget>::iterator It(childlist); + while (It != childlist.end()) + { + eRect cr=area&eRect((*It)->position, (*It)->size); + if (!cr.isEmpty()) + { + cr.moveBy(-It->position.x(), -It->position.y()); + It->redraw(cr); + } + ++It; + } + } + } +} + +void eWidget::invalidate(eRect area, int force) +{ + if ( (!(state & stateVisible)) && (!force)) + return; + + if (area.isNull()) + area=eRect(0, 0, size.width(), size.height()); + + eWidget *w=this; + + // problem: überlappende, nicht transparente fenster + + while (force || (((int)w->getBackgroundColor())==-1)) + // while (1) + { + force=0; + if (!w->parent) // spaetestens fuers TLW sollte backgroundcolor aber non-transparent sein + break; + area.moveBy(w->position.x(), w->position.y()); + w=w->parent; + area.moveBy(w->clientrect.x(), w->clientrect.y()); + area&=w->clientrect; + } + w->redraw(area); +} + +int eWidget::event(const eWidgetEvent &event) +{ + if (!eventFilter(event)) + { + eWidget *target=this; +/* if (have_focus && event.toFocus()) // bypassing focus handling for root-widget + target=focusList()->current(); */ + if (target) + { + while (target) + { + if (target->eventHandler(event)) + return 1; + if (target==this) + break; + target=target->parent; + } + } + } + return 0; +} + + /* das ist bestimmt ne einzige race hier :) */ +int eWidget::exec() +{ + if (in_loop) + eFatal("double exec"); + + in_loop=-1; // hey, exec hat angefangen aber noch nicht in der mainloop + + event(eWidgetEvent(eWidgetEvent::execBegin)); // hat jemand was dagegen einzuwenden? + + if (in_loop) // hatte wohl jemand. + { + in_loop=1; // wir betreten die mainloop + eApp->enter_loop(); // oder wir machen das halt selber. + in_loop=0; // nu sind wir jedenfalls draussen. + } + event(eWidgetEvent(eWidgetEvent::execDone)); + + return result; +} + +void eWidget::clear() +{ +#if 0 + eWidget *root=this; + while (root->parent) + root=root->parent; + eRect me(getRelativePosition(root), size); + root->invalidate(me); +#endif + invalidate(eRect(), 1); +} + +void eWidget::close(int res) +{ + if (in_loop==0) + eFatal("attempt to close non-execing widget"); + if (in_loop==1) // nur wenn das ne echte loop ist + eApp->exit_loop(); + result=res; +} + +void eWidget::show() +{ + if (state & stateShow) + return; + + ASSERT(!(state&stateVisible)); + + state|=stateShow; + + if (!parent || (parent->state&stateVisible)) + { + ++getTLW()->just_showing; + willShowChildren(); + + checkFocus(); + --getTLW()->just_showing; + redraw(); + } +} + + +void eWidget::accept() +{ + close(0); +} + +void eWidget::reject() +{ + close(-1); +} + +void eWidget::willShowChildren() +{ + if (!(state & stateShow)) + return; + _willShow(); + if (!childlist.empty()) + { + ePtrList<eWidget>::iterator It(childlist); + while(It != childlist.end()) + { + It->willShowChildren(); + ++It; + } + } +} + +void eWidget::hide() +{ + if (!(state&stateShow)) + return; + + if (state&stateVisible) + { + willHideChildren(); + clear(); // hide -> immer erasen. dieses Hide ist IMMER explizit. + } + state&=~stateShow; + checkFocus(); +} + +void eWidget::willHideChildren() +{ + if (!(state & stateShow)) + return; + _willHide(); + if (!childlist.empty()) + { + ePtrList<eWidget>::iterator It(childlist); + while(It != childlist.end()) + { + It->willHideChildren(); + ++It; + } + } +} + +void eWidget::findAction(eActionPrioritySet &prio, const eRCKey &key, eWidget *context) +{ +#if 0 + for (actionMapList::iterator i = actionmaps.begin(); i != actionmaps.end(); ++i) + { + const std::set<eString> &styles=eActionMapList::getInstance()->getCurrentStyles(); + for (std::set<eString>::const_iterator si(styles.begin()); si != styles.end(); ++si) + (*i)->findAction(prio, key, context, *si); + } +#endif + + for(ePtrList<eWidget>::iterator w(actionListener.begin()); w != actionListener.end(); ++w) + i_shortcutActions->map.findAction(prio, key, w, ""); + + if (focus && focus != this) + focus->findAction(prio, key, context); +} + +int eWidget::eventFilter(const eWidgetEvent &event) +{ + return 0; +} + +void eWidget::addActionToHelpList(eAction *action) +{ + actionHelpList.push_back( action ); +} + +void eWidget::clearHelpList() +{ + actionHelpList.clear(); +} + +void eWidget::setHelpID(int fHelpID) +{ + helpID=fHelpID; +} + +int eWidget::eventHandler(const eWidgetEvent &evt) +{ + switch (evt.type) + { + case eWidgetEvent::childChangedHelpText: + /* emit */ focusChanged(focus); // faked focusChanged Signal to the Statusbar + break; + case eWidgetEvent::evtAction: + if (evt.action == shortcut && isVisible()) + (shortcutFocusWidget?shortcutFocusWidget:this)-> + event(eWidgetEvent(eWidgetEvent::evtShortcut)); + else if (evt.action == &i_focusActions->up) + focusNext(focusDirPrev); + else if (evt.action == &i_focusActions->down) + focusNext(focusDirNext); + else if (evt.action == &i_focusActions->left) + focusNext(focusDirPrev); + else if (evt.action == &i_focusActions->right) + focusNext(focusDirNext); + else if (evt.action == &i_cursorActions->help) + { + int wasvisible=state&stateShow; + if (wasvisible) + hide(); + /* emit */ showHelp( &actionHelpList, helpID ); + if (wasvisible) + show(); + } else + return 0; + return 1; + case eWidgetEvent::evtKey: + { + eActionPrioritySet prio; + + findAction(prio, *evt.key, this); + + if (focus && (focus != this)) + focus->findAction(prio, *evt.key, focus); + +#if 0 + for (actionMapList::iterator i = globalActions.begin(); i != globalActions.end(); ++i) + { + const std::set<eString> &styles=eActionMapList::getInstance()->getCurrentStyles(); + for (std::set<eString>::const_iterator si(styles.begin()); si != styles.end(); ++si) + (*i)->findAction(prio, *evt.key, 0, *si); + } +#endif + + for (eActionPrioritySet::iterator i(prio.begin()); i != prio.end(); ++i) + { + if (i->first) + { + if (((eWidget*)i->first)->event(eWidgetEvent(eWidgetEvent::evtAction, i->second))) + break; + } else + { + (const_cast<eAction*>(i->second))->handler(); // only useful for global actions + break; + } + } + + if (focus) + { + /* Action not found, try to use old Keyhandle */ + int c = evt.key->producer->getKeyCompatibleCode(*evt.key); + if (c != -1) + { + if (evt.key->flags & eRCKey::flagBreak) + focus->keyUp(c); + else + focus->keyDown(c); + } + } + return 1; + break; + } + case eWidgetEvent::gotFocus: + gotFocus(); + break; + case eWidgetEvent::lostFocus: + lostFocus(); + break; + + case eWidgetEvent::changedSize: + case eWidgetEvent::changedFont: + case eWidgetEvent::changedPosition: + case eWidgetEvent::changedPixmap: + invalidate(); + break; + case eWidgetEvent::evtShortcut: + setFocus(this); + break; + default: + break; + } + return 0; +} + +int eWidget::keyDown(int rc) +{ + return 0; +} + +int eWidget::keyUp(int rc) +{ + return 0; +} + +void eWidget::gotFocus() +{ +} + +void eWidget::lostFocus() +{ +} + +void eWidget::recalcClientRect() +{ + clientrect=eRect(0, 0, size.width(), size.height()); +} + +void eWidget::recalcClip() +{ + eWidget *t=this; + eRect rect=eRect(0, 0, size.width(), size.height()); + while (t) + { + rect&=t->clientrect; + rect.moveBy(t->position.x(), t->position.y()); + t=t->parent; + if (t) + rect.moveBy(t->clientrect.x(), t->clientrect.y()); + } + clientclip=rect; +} + +void eWidget::checkFocus() +{ + ePtrList<eWidget> *l=getTLW()->focusList(); + if (!(getTLW()->focus && getTLW()->focus->state&stateVisible)) + { + l->first(); + + while (l->current() && !(l->current()->state&stateVisible)) + l->next(); + + setFocus(l->current()); + } +} + +void eWidget::addActionMap(eActionMap *map) +{ + actionmaps.push_back(map); +} + +void eWidget::removeActionMap(eActionMap *map) +{ + actionmaps.remove(map); +} + +void eWidget::addGlobalActionMap(eActionMap *map) +{ + globalActions.push_back(map); +} + +void eWidget::removeGlobalActionMap(eActionMap *map) +{ + globalActions.remove(map); +} + +void eWidget::redrawWidget(gPainter *target, const eRect &clip) +{ +} + +void eWidget::eraseBackground(gPainter *target, const eRect &clip) +{ + if (((int)getBackgroundColor()) >= 0) + target->clear(); +} + +void eWidget::focusNext(int dir) +{ + if (parent && parent->parent) + return getTLW()->focusNext(dir); + + if (!_focusList.current()) + _focusList.first(); + if (!_focusList.current()) + { + setFocus(0); + return; + } + + switch (dir) + { + case focusDirNext: + case focusDirPrev: + { + int tries=2; + while (tries) + { + if (dir == focusDirNext) + { + _focusList.next(); + if (!_focusList.current()) + { + _focusList.first(); + --tries; + } + } else if (dir == focusDirPrev) + { + if (_focusList.current() == _focusList.begin()) + { + _focusList.last(); + --tries; + } else + _focusList.prev(); + } + if (_focusList.current() && _focusList.current()->state&stateVisible) + break; + } + if (!tries) + { + setFocus(0); + return; + } + break; + } + case focusDirN: + case focusDirE: + case focusDirS: + case focusDirW: + { + eWidget *nearest=_focusList.current(); + int difference=1<<30; + for (ePtrList<eWidget>::iterator i(_focusList.begin()); i != _focusList.end(); ++i) + { + if (_focusList.current() == i) + continue; + if (!(i->state&stateVisible)) + continue; + ePoint m1=i->getAbsolutePosition(); + ePoint m2=_focusList.current()->getAbsolutePosition(); + switch (dir) + { + case focusDirN: // diff between our TOP and new BOTTOM + m1+=ePoint(i->getSize().width()/2, i->getSize().height()); + m2+=ePoint(_focusList.current()->getSize().width()/2, 0); + break; + case focusDirS: // diff between our BOTTOM and new TOP + m1+=ePoint(i->getSize().width()/2, 0); + m2+=ePoint(_focusList.current()->getSize().width()/2, _focusList.current()->getSize().height()); + break; + case focusDirE: // diff between our RIGHT and new LEFT border + m1+=ePoint(0, i->getSize().height()/2); + m2+=ePoint(_focusList.current()->getSize().width(), _focusList.current()->getSize().height()/2); + break; + case focusDirW: // diff between our LEFT and new RIGHT border + m1+=ePoint(i->getSize().width(), i->getSize().height()/2); + m2+=ePoint(0, _focusList.current()->getSize().height()/2); + break; + } + + int xd=m1.x()-m2.x(); + int yd=m1.y()-m2.y(); +#define METHOD 0 +#if METHOD == 0 + int dif=xd*xd+yd*yd; + int eff=0; + + switch (dir) + { + case focusDirN: + yd=-yd; + case focusDirS: + if (yd > 0) + eff=dif/yd; + else + eff=1<<30; + break; + case focusDirW: + xd=-xd; + case focusDirE: + if (xd > 0) + eff=dif/xd; + else + eff=1<<30; + break; + } + + if (eff < difference) + { + difference=eff; + nearest=*i; + } +#elif METHOD == 1 + int ldir=focusDirN; + int mydiff=0; + + if (xd > mydiff) // rechts + { + mydiff=xd; + ldir=focusDirE; + } + if ((-xd) > mydiff) // links + { + mydiff=-xd; + ldir=focusDirW; + } + if (yd > mydiff) // unten + { + mydiff=yd; + ldir=focusDirS; + } + if ((-yd) > mydiff) // oben + { + mydiff=-yd; + ldir=focusDirN; + } + if (dir == ldir) // nur elemente beruecksichtigen die in der richtung liegen... + { + int entf=xd*xd+yd*yd; + if (entf < difference) + { + difference=entf; + nearest=*i; + } + } +#elif METHOD == 2 + +#endif + + } + _focusList.setCurrent(nearest); + break; + } + } + + setFocus(_focusList.current()); +} + +void eWidget::setFocus(eWidget *newfocus) +{ + if (parent && parent->parent) + return getTLW()->setFocus(newfocus); + + if (focus == newfocus) + { +// eDebug("focus == newfocus"); +// /* emit */ focusChanged(focus); + return; + } + + if (focus) + focus->event(eWidgetEvent(eWidgetEvent::lostFocus)); + + focus=newfocus; + + if (focus) + focus->event(eWidgetEvent(eWidgetEvent::gotFocus)); + + _focusList.setCurrent(focus); + + /* emit */ focusChanged(focus); +} + +void eWidget::setHelpText( const eString& e) +{ + helptext=e; + if ( parent ) + parent->event( eWidgetEvent::childChangedHelpText ); +} + +void eWidget::setFont(const gFont &fnt) +{ + font=fnt; + event(eWidgetEvent(eWidgetEvent::changedFont)); +} + +void eWidget::setText(const eString &label) +{ + if (label != text) // ein compare ist immer weniger arbeit als ein unnoetiges redraw + { + text=label; + event(eWidgetEvent(eWidgetEvent::changedText)); + } +} + +void eWidget::setBackgroundColor(const gColor& color, bool inv) +{ + if (color!=backgroundColor) + { + backgroundColor=color; + event(eWidgetEvent(eWidgetEvent::changedBackgroundColor)); + if (inv) + invalidate(); + } +} + +void eWidget::setForegroundColor(const gColor& color, bool inv) +{ + if (color != foregroundColor) + { + foregroundColor=color; + event(eWidgetEvent(eWidgetEvent::changedForegroundColor)); + if (inv) + invalidate(); + } +} + +void eWidget::setPixmap(gPixmap *pmap) +{ + if ( pixmap != pmap ) + { + pixmap=pmap; + event(eWidgetEvent(eWidgetEvent::changedPixmap)); + } +} + +void eWidget::setTarget(gDC *newtarget) +{ + target=newtarget; +} + +#ifndef DISABLE_LCD +void eWidget::setLCD(eWidget *_lcdtitle, eWidget *_lcdelement) +{ + LCDTitle=_lcdtitle; + LCDElement=_lcdelement; +} +#endif + +void eWidget::setName(const char *_name) +{ + name=_name; +} + +gPainter *eWidget::getPainter(eRect area) +{ + eRect myclip=eRect(getAbsolutePosition(), size); + if (parent) + myclip&=parent->clientclip; + + eWidget *r=this; + while (r && r->parent && !r->target) + r = r->parent; + + ASSERT(r); +// ASSERT(r->target); + if (!r->target) // if target is 0, device is locked. + return 0; + + gPainter *p=new gPainter(*r->target, myclip); + p->setLogicalZero(getAbsolutePosition()); + if (!area.isNull()) + p->clip(area); + p->setForegroundColor(foregroundColor); + p->setBackgroundColor(backgroundColor); + return p; +} + +static int parse(const char* p, int *v, int *e, int max) +{ + int i=0; + + while ( (i<max) && (*p) ) + { + int ea=0; + + if (*p=='e') + { + ++p; + ea=1; + } + + char *x; + v[i]=strtol(p, &x, 10); + p=x; + + if (*p && *p!=':') + return -3; + + if (*p==':') + ++p; + + if (ea) + v[i]+=e[i]; + + ++i; + } + + if (*p) + return -1; + + if (i<max) + return -2; + + return 0; +} + +int eWidget::setProperty(const eString &prop, const eString &value) +{ + if (prop=="position") + { + int v[2], e[2]={0, 0}; + if (parent) + { + e[0]=parent->clientrect.width(); + e[1]=parent->clientrect.height(); + } + int err=parse(value.c_str(), v, e, 2); + if (err) + return err; + move(ePoint(v[0], v[1])); + } + else if (prop=="cposition") + { + int v[2], e[2]; + e[0]=e[1]=0; + if (parent) + { + e[0]=parent->clientrect.width(); + e[1]=parent->clientrect.height(); + } + int err=parse(value.c_str(), v, e, 2); + if (err) + return err; + + cmove(ePoint(v[0], v[1])); + } + else if (prop=="size") + { + int v[2], e[2]; + e[0]=e[1]=0; + if (parent) + { + e[0]=parent->clientrect.width()-position.x(); + e[1]=parent->clientrect.height()-position.y(); + } + int err=parse(value.c_str(), v, e, 2); + if (err) + return err; + resize(eSize(v[0], v[1])); + } + else if (prop=="csize") + { + int v[2], e[2]; + e[0]=e[1]=0; + if (parent) + { + e[0]=parent->clientrect.width()-position.x(); + e[1]=parent->clientrect.height()-position.y(); + } + int err=parse(value.c_str(), v, e, 2); + if (err) + return err; + cresize(eSize(v[0], v[1])); + } + else if (prop=="text") +/* { + eString text; + + std::string::const_iterator p(value.begin()); + + while(*p) + { + if (*p=='\\') + { + switch (*(++p)) + { + case 'n': + text+='\n'; + break; + case 'r': + text+='\r'; + break; + case 't': + text+='\t'; + break; + case 'b': + text+='\b'; + break; + case '\\': + text+='\\'; + break; + default: + text+='?'; + break; + } + } + else + text+=*p; + + p++; + } + setText(text); + }*/ + setText(::gettext(value.c_str())); + else if (prop=="helptext") + setHelpText(::gettext(value.c_str())); + else if (prop=="font") + setFont(eSkin::getActive()->queryFont(value)); + else if (prop=="name") + name=value; + else if (prop=="pixmap") + { + ePtr<gPixmap> pixmap; + eSkin::getActive()->queryImage(pixmap, value); + setPixmap(pixmap); + } else if (prop=="foregroundColor") + setForegroundColor(eSkin::getActive()->queryColor(value)); + else if (prop=="backgroundColor") + setBackgroundColor(eSkin::getActive()->queryColor(value)); + else if (prop=="shortcut") + setShortcut(value); + else if (prop=="shortcutFocus") + setShortcutFocus(parent ? parent->search(value) : 0); + else + { + eFatal("skin property %s does not exist", prop.c_str()); + return -ENOENT; + } + return 0; +} + +eWidget *eWidget::search(const eString &sname) +{ + if (name==sname) + return this; + + if (!childlist.empty()) + { + std::list<eWidget*>::iterator It = childlist.begin(); + while(It != childlist.end()) + { + eWidget* p = (*It)->search(sname); + if (p) + return p; + ++It; + } + } + return 0; +} + +void eWidget::makeRoot() +{ + root=this; +} + +void eWidget::zOrderLower() +{ + if (!parent) + return; + int isshown=0; + if (state & stateShow) + { + isshown=1; + hide(); + } + parent->childlist.remove(this); + parent->childlist.push_front(this); + if (isshown) + show(); +} + +void eWidget::zOrderRaise() +{ + if (!parent) + return; + int isshown=0; + if (state & stateShow) + { + isshown=1; + hide(); + } + parent->childlist.remove(this); + parent->childlist.push_back(this); + if (isshown) + show(); +} + +void eWidget::setShortcut(const eString &shortcutname) +{ + if (shortcut) + getTLW()->actionListener.remove(this); + shortcut=i_shortcutActions->map.findAction(shortcutname.c_str()); + if (shortcut) + getTLW()->actionListener.push_back(this); +} + +void eWidget::setShortcutFocus(eWidget *focus) +{ + shortcutFocusWidget=focus; + if (!focus) + eFatal("setShortcutFocus with unknown widget!"); +} + +static eWidget *create_eWidget(eWidget *parent) +{ + return new eWidget(parent); +} + +class eWidgetSkinInit +{ +public: + eWidgetSkinInit() + { + eSkin::addWidgetCreator("eWidget", create_eWidget); + } + ~eWidgetSkinInit() + { + eSkin::removeWidgetCreator("eWidget", create_eWidget); + } +}; +eAutoInitP0<eWidgetSkinInit> init_eWidgetSkinInit(eAutoInitNumbers::guiobject, "eWidget"); diff --git a/lib/gui/ewidget.h b/lib/gui/ewidget.h new file mode 100644 index 00000000..3a1199a0 --- /dev/null +++ b/lib/gui/ewidget.h @@ -0,0 +1,498 @@ +#ifndef __ewidget_h +#define __ewidget_h + +#include <lib/base/ebase.h> +#include <lib/base/estring.h> +#include <lib/gdi/epoint.h> +#include <lib/gdi/esize.h> +#include <lib/gdi/erect.h> +#include <lib/base/eptrlist.h> +#include <libsig_comp.h> +#include <lib/gdi/grc.h> +#include <lib/driver/rc.h> +#include <lib/gui/actions.h> + +class eWidgetEvent +{ +public: + enum eventType + { + evtKey, + willShow, willHide, + execBegin, execDone, + gotFocus, lostFocus, + + changedText, changedFont, changedForegroundColor, changedBackgroundColor, + changedSize, changedPosition, changedPixmap, childChangedHelpText, + + evtAction, evtShortcut + } type; + union + { + int parameter; + const eAction *action; + const eRCKey *key; + }; + eWidgetEvent(eventType type, int parameter=0): type(type), parameter(parameter) { } + eWidgetEvent(eventType type, const eAction *action): type(type), action(action) { } + eWidgetEvent(eventType type, const eRCKey &key): type(type), key(&key) { } + + /** + * \brief Event should be delivered to the focused widget. + * + * \return true if the event should be delivered to the focused widget instead of the widget itself. + */ + int toFocus() const + { + switch (type) + { + case evtKey: + return 1; + default: + return 0; + } + } +}; + +/** \brief The main widget class. All widgets inherit this class. + * eWidget handles focus management. + */ +class eWidget: public Object +{ + enum + { + /// Widget was shown with show() or implicit show() + stateShow=1, + /// Widget is visible on screen. Implies stateShow. + stateVisible=2 + }; + +public: + /** + * \brief Exits a (model) widget. + * + * Quit the local event loop, thus returning the control to the function which called \a exec. + * \sa eWidget::accept + * \sa eWidget::reject + */ + void close(int result); + + /** + * \brief Closes with a returncode of 0 (success). + * + * Synonym to \a close(0);. Useful to use as a slot. + * \sa eWidget::close + */ + void accept(); + + /** + * \brief Closes with a returncode of -1 (failure). + * + * Synonym to \a close(-1);. Useful to use as a slot. + * \sa eWidget::close + */ + void reject(); + /** + * \brief Signal is send, when the focus Changed + * + * used from a existing statusbar. + * \sa eWidget::focusChanged + */ + Signal1<void, const eWidget*> focusChanged; + static Signal2< void, ePtrList<eAction>*, int > showHelp; +protected: + ePtrList<eAction> actionHelpList; + int helpID; + ePtrList<eWidget> childlist; + static eWidget *root; + eWidget *parent; + eString name; + eString helptext; + ePoint position; + ePoint absPosition; + eSize size; + eRect clientrect; + eRect clientclip; + + eAction *shortcut; + eWidget *shortcutFocusWidget; + + ePtrList<eWidget> _focusList; + + ePtrList<eWidget> actionListener; + eWidget *focus, *TLW; + + /// old top-level focus + eWidget *oldTLfocus; + int takefocus; + int state; + + gDC *target; + + inline eWidget *getTLW() // pseudoTLW !! + { + return TLW ? TLW : (TLW = (parent && parent->parent) ? parent->getTLW() : this ); + } + int result, in_loop, have_focus, just_showing; + void takeFocus(); + void releaseFocus(); + + void _willShow(); + void _willHide(); + + virtual void willShow(); + virtual void willHide(); + + virtual void setPalette(); + + void willShowChildren(); + void willHideChildren(); + + /** + * \brief Hi priority event filter. + * + * This event filter is called before the event is delivered via \a event. + * \return 1 if the event should NOT be forwarded. + */ + virtual int eventFilter(const eWidgetEvent &event); + + /** + * \brief Handles an event. + * + * If re-implemented in a widget-sub-class, \c eWidget::event should be called whenever the event is + * not processed by the widget. + * \return 1 if the event was processed, 0 if ignored. it might be forwarded to other widgets then. + */ + + virtual int keyDown(int rc); + virtual int keyUp(int rc); + + virtual void gotFocus(); + virtual void lostFocus(); + + virtual void recalcClientRect(); + void recalcClip(); + void checkFocus(); + + typedef ePtrList<eActionMap> actionMapList; + + void findAction(eActionPrioritySet &prio, const eRCKey &key, eWidget *context); + void addActionMap(eActionMap *map); + void removeActionMap(eActionMap *map); + actionMapList actionmaps; + static actionMapList globalActions; + + // generic properties + gFont font; + eString text; + gColor backgroundColor, foregroundColor; + + ePtr<gPixmap> pixmap; + + eString descr; + +public: + virtual int eventHandler(const eWidgetEvent &event); + static void addGlobalActionMap(eActionMap *map); + static void removeGlobalActionMap(eActionMap *map); + inline eWidget *getNonTransparentBackground() + { + if (backgroundColor >= 0) + return this; + return parent?parent->getNonTransparentBackground():this; + } + +#ifndef DISABLE_LCD + eWidget *LCDTitle; + eWidget *LCDElement; + eWidget *LCDTmp; +#endif + + void recalcAbsolutePosition(); + + inline const ePoint &getAbsolutePosition() const + { + return absPosition; + } + + inline ePoint getRelativePosition(eWidget *e) const + { + ePoint pos=position; + if (this != e) + for (eWidget *a=parent; a && (a != e); a=a->parent) + pos+=a->clientrect.topLeft(); + return pos; + } + + virtual void redrawWidget(gPainter *target, const eRect &area); + + virtual void eraseBackground(gPainter *target, const eRect &area); + + /** + * \brief Constructs a new eWidget. + * \param parent The parent widget. The widget gets automatically removed when the parent gets removed. + * \param takefocus Specifies if the widget should be appended to the focus list of the TLW, i.e. if it can + receive keys. + */ + eWidget(eWidget *parent=0, int takefocus=0); + + /** + * \brief Destructs an eWidget and all its childs. + * + * hide() is called when the widget is shown. The set ePixmap is \e not + * freed. If the widget acquired focus, it will be removed from the focuslist. + * \sa eWidget::setPixmap + */ + virtual ~eWidget(); + + /** + * \brief Returns a pointer to the focus list. + * + * The focus list is the list of childs which have the \c takefocus flag set. + * This list is only maintained for TLWs. + */ + ePtrList<eWidget> *focusList() { return &_focusList; } + + /** + * \brief Resizes the widget. + * + * Sets the size of the widget to the given size. The event \c changedSize event will be generated. + * \param size The new size, relative to the position. + */ + void resize(const eSize& size); + + /** + * \brief Resizes clientrect (and the widget). + * + * Sets the clientrect of the widget to the given size. The real size of the widget will be set to met + * these requirement. The event \c changedSize event will be generated. + * \param size The new size of the clientrect, relative to the position. + */ + void cresize(const eSize& size); + + /** + * \brief Moves the widget. + * + * Set the new position of the widget to the given position. The \c changedPosition event will be generated. + * \param position The new position, relative to the parent's \c clientrect. + */ + void move(const ePoint& position); + + /** + * \brief Moves the clientrect (and the widget). + * + * Set the new position of the clientrect to the given position. The \c changedPosition event will be generated. + * \param position The new position, relative to the parent's \c clientrect. + */ + void cmove(const ePoint& position); + + /** + * \brief Returns the current size. + * + * \return Current size of the widget, relative to the position. + */ + const eSize& getSize() const { return size; } + + /** + * \brief Returns the current position. + * + * \return Current position, relative to the parent's \c clientrect. + */ + const ePoint& getPosition() const { return position; } + + /** + * \brief Returns the size of the clientrect. + * + * \return The usable size for the childwidgets. + */ + eSize getClientSize() const { return clientrect.size(); } + + /** + * \brief Returns the clientrect. + * + * \return The area usable for the childwidgets. + */ + const eRect& getClientRect() const { return clientrect; } + + /** + * \brief Recursive redraw of a widget. + * + * All client windows get repaint too, but no widgets above. Unless you have a good reason, you shouldn't + * use this function and use \c invalidate(). + * \param area The area which should be repaint. The default is to repaint the whole widget. + * \sa eWidget::invalidate + */ + void redraw(eRect area=eRect()); + + /** + * \brief Recursive (complete) redraw of a widget. + * + * Redraws the widget including background. This is the function to use if you want to manually redraw something! + * \param area The area which should be repaint. The default is to repaint the whole widget. + * \param force Forces a parent-invalidate even on non-visible widgets. Shouldn't be used outside eWidget. + * \sa eWidget::redraw + */ + void invalidate(eRect area=eRect(), int force=0); + + /** + * \brief Enters modal message loop. + * + * A new event loop will be launched. The function returns when \a close is called. + * \return The argument of \a close. + * \sa eWidget::close + */ + int exec(); + + /** + * \brief Visually clears the widget. + * + * Clears the widget. This is done on \a hide(). + * \sa eWidget::hide + */ + void clear(); + + /** + * \brief Delivers a widget-event. + * + * Internally calles \a eventFilter, then \a eventHandler() (in some cases of the focused widget) + * \param event The event to deliver. + */ + int event(const eWidgetEvent &event); + + /** + * \brief Shows the widget. + * + * If necessary, the widget will be linked into the TLW's active focus list. The widget will + * visually appear. + * \sa eWidget::hide + */ + void show(); + + /** + * \brief Hides the widget. + * + * The widget will be removed from the screen. All childs will be hidden too. + * \sa eWidget::show + */ + void hide(); + + /** + * \brief Returns if the widget is vissible. + * + * \return If the widget and all parents are visible, \c true is returned, else false. + */ + int isVisible() { return (state&stateVisible) && ( (!parent) || parent->isVisible() ); } + + /** + * \brief Possible focus directions. + */ + enum focusDirection + { + focusDirNext, focusDirPrev, focusDirN, focusDirE, focusDirS, focusDirW + }; + + /** + * \brief changes the focused widget. + * + * Focuses the next or previous widget of the \c focuslist. An \c gotFocus and \c lostFocus event will be + * generated. + * \param dir The direction, \c focusDirection. + */ + void focusNext(int dir=0); + + /** + * \brief Gives focus to a widget. + * + * Set the focus to the specified widget. The \c focuslist is updated, too. + * An \c gotFocus and \c lostFocus event will be generated. + * \param newfocus The new widget to focus. + */ + void setFocus(eWidget *newfocus); + + /** + * \brief Sets the widget font. + * + * The font is used for example by the \c eLabel. + * \sa eLabel + * \param font The new font used by widget-specific drawing code. + */ + void setFont(const gFont &font); + + /** + * \brief Sets the widget caption or text. + * + * \param label The text to assign to the widget. + */ + void setText(const eString &label); + + const eString& getText() const { return text; } + void setBackgroundColor(const gColor& color, bool inv=true); + void setForegroundColor(const gColor& color, bool inv=true); + void setPixmap(gPixmap *pmap); + void setTarget(gDC *target); + gDC *getTarget() { return target; } + +#ifndef DISABLE_LCD + void setLCD(eWidget *lcdtitle, eWidget *lcdelement); +#endif + + void setName(const char *name); + const eString& getName() const { return name; } + eWidget*& getParent() { return parent; } + const gFont& getFont() const { return font; } + + const gColor& getBackgroundColor() const { return backgroundColor; } + const gColor& getForegroundColor() const { return foregroundColor; } + + int width() { return getSize().width(); } + int height() { return getSize().height(); } + + gPainter *getPainter(eRect area); + + const eString& getHelpText() const { return helptext; } + + void setHelpText( const eString&); + /** + * \brief Sets a property. + * + * A property is a value/data pair which is used for serializing widgets (like in skinfiles). + * These properties are available to all \c "eWidget"-based classes. + * \arg \c position, the position of the widget, relative to the parent's childarea. Consider using csize for TLWs. + * Positions are specified in a "x:y" manner. + * \arg \c cposition, the position of the widget's clientrect (upper left). + * This is useful for specifing a position independant of a decoration which might be + * different sized. The real position will be calculated to match the requested position. + * \arg \c size, the size of the widget. Consider using csize for TLWs. Sizes are specified in a "width:height" manner. + * \arg \c csize, the size of the clientrect. The real size will be calculated to match the requested size. + * \arg \c text, the text/caption of the widget. + * \arg \c font, the primary font used in the widget. + * \arg \c name, the name of the widget for referring them. + * \arg \c pixmap, an already loaded, named pixmap to be used as the widget's pixmap. + * \arg \c foregroundColor, a named color, which will be used for the widget's foreground color. + * \arg \c backgroundColor + * \param prop The property to be set. + * \param value The value to be set. + */ + virtual int setProperty(const eString &prop, const eString &value); + + eWidget *search(const eString &name); + + eWidget* getFocus() { return focus; } + + void makeRoot(); + + void zOrderLower(); + void zOrderRaise(); + + /** + * \brief sets the shortcut (generate evtShortcut) + */ + void setShortcut(const eString &shortcut); + void setShortcutFocus(eWidget *focus); + + void addActionToHelpList(eAction *action); + void clearHelpList(); + void setHelpID(int fHelpID); +}; + +#endif diff --git a/lib/gui/ewindow.cpp b/lib/gui/ewindow.cpp new file mode 100644 index 00000000..de7fe3db --- /dev/null +++ b/lib/gui/ewindow.cpp @@ -0,0 +1,160 @@ +#include <lib/gui/ewindow.h> +#include <lib/gdi/grc.h> +#include <lib/gui/eskin.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/gdi/epng.h> +#include <lib/gui/elabel.h> +#include <lib/gui/guiactions.h> +#include <lib/gdi/font.h> + +int eWindow::globCancel = eWindow::ON; + +eWindow::eWindow(int takefocus) + :eWidget(0, takefocus) +{ + deco.load("eWindow"); + + titleBarColor=eSkin::getActive()->queryScheme("eWindow.titleBar"); + fontColor=eSkin::getActive()->queryScheme("eWindow.titleBarFont"); + + borderLeft=eSkin::getActive()->queryValue("eWindow.borderLeft", deco.borderLeft); + borderRight=eSkin::getActive()->queryValue("eWindow.borderRight", deco.borderRight); + borderBottom=eSkin::getActive()->queryValue("eWindow.borderBottom", deco.borderBottom); + borderTop=eSkin::getActive()->queryValue("eWindow.borderTop", deco.borderTop ); + + titleOffsetLeft=eSkin::getActive()->queryValue("eWindow.titleOffsetLeft", 0); + titleOffsetRight=eSkin::getActive()->queryValue("eWindow.titleOffsetRight", 0); + titleOffsetTop=eSkin::getActive()->queryValue("eWindow.titleOffsetTop", 0); + titleHeight=eSkin::getActive()->queryValue("eWindow.titleHeight", titleFontSize+10); + titleFontSize=eSkin::getActive()->queryValue("eWindow.titleFontSize", 20); + + font = eSkin::getActive()->queryFont("eWindow.Childs"); + + addActionMap(&i_cursorActions->map); +} + +eWindow::~eWindow() +{ +} + +eRect eWindow::getTitleBarRect() +{ + eRect rc; + rc.setLeft( deco.borderLeft > titleOffsetLeft ? deco.borderLeft : titleOffsetLeft ); + rc.setTop( titleOffsetTop ); + rc.setRight( width() - ( deco.borderRight > titleOffsetRight ? deco.borderRight : titleOffsetRight ) ); + rc.setBottom( rc.top() + (titleHeight?titleHeight:deco.borderTop) ); // deco.borderTop sucks... + return rc; +} + +void eWindow::redrawWidget(gPainter *target, const eRect &where) +{ + if ( deco ) // then draw Deco + deco.drawDecoration(target, ePoint(width(), height())); + else + { + gColor border = eSkin::getActive()->queryColor("eWindow.border"); + target->setForegroundColor(border); + target->line( ePoint(0,0), ePoint(0, height()) ); + target->line( ePoint(0,0), ePoint(width(), 0) ); + target->line( ePoint(width()-1,0), ePoint(width()-1, height()-1) ); + target->line( ePoint(0,height()-1), ePoint(width()-1, height()-1) ); + } + drawTitlebar(target); +} + +void eWindow::eraseBackground(gPainter *target, const eRect &clip) +{ + target->clip(getClientRect()); + target->clear(); + target->clippop(); +} + +void eWindow::drawTitlebar(gPainter *target) +{ + eRect rc = getTitleBarRect(); + target->clip( rc ); + if ( titleHeight ) + { + target->setForegroundColor(titleBarColor); + target->fill( rc ); + } + rc.setWidth(rc.width()-10); + eTextPara *p = new eTextPara( rc ); + p->setFont( eSkin::getActive()->queryFont("eWindow.TitleBar") ); + p->renderString( text ); + target->setBackgroundColor(titleBarColor); + target->setForegroundColor(fontColor); + target->renderPara( *p ); + p->destroy(); + target->clippop(); +} + +void eWindow::recalcClientRect() +{ + clientrect=eRect( borderLeft, borderTop, width() - (borderLeft+borderRight), height() - ( borderTop+borderBottom) ); +} + +int eWindow::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::willShow: + if (focus) + focusChanged( focus ); + break; + case eWidgetEvent::changedText: + { + redraw(getTitleBarRect()); + return 1; + } + + case eWidgetEvent::evtAction: + if (globCancel && (event.action == &i_cursorActions->cancel) && in_loop) // hack + { + close(-1); + return eWidget::eventHandler(event); + } + else + break; + return 1; + default: + break; + } + return eWidget::eventHandler(event); +} + +void eWindow::willShow() +{ +#ifndef DISABLE_LCD + if (LCDTitle) + LCDTitle->setText(text); +#endif + eWidget::willShow(); +} + +void eWindow::willHide() +{ + eWidget::willHide(); +} + +static eWidget *create_eWindow(eWidget *parent) +{ + return new eWindow(); +} + +class eWindowSkinInit +{ +public: + eWindowSkinInit() + { + eSkin::addWidgetCreator("eWindow", create_eWindow); + } + ~eWindowSkinInit() + { + eSkin::removeWidgetCreator("eWindow", create_eWindow); + } +}; + +eAutoInitP0<eWindowSkinInit> init_eWindowSkinInit(eAutoInitNumbers::guiobject, "eWindow"); diff --git a/lib/gui/ewindow.h b/lib/gui/ewindow.h new file mode 100644 index 00000000..34cef8c4 --- /dev/null +++ b/lib/gui/ewindow.h @@ -0,0 +1,48 @@ +#ifndef __ewindow_h +#define __ewindow_h + +#include <lib/gui/ewidget.h> +#include <lib/gui/decoration.h> + +/** + * \brief A (decorated) top level widget. + * + * An eWindow is whats actually seen as a window. It's top level (thus you cannot specify a parent), + * and may have a (skinned) decoration. It's clientrect is usually a bit smaller since it has a titlebar + * and a border. + * + */ +class eWindow: public eWidget +{ + eDecoration deco; + gColor fontColor, titleBarColor; + static int globCancel; +protected: + int borderTop, borderLeft, borderBottom, borderRight; + int titleOffsetLeft, titleOffsetRight, titleOffsetTop, titleFontSize, titleHeight; + void redrawWidget(gPainter *target, const eRect &where); + void eraseBackground(gPainter *target, const eRect &where); + void drawTitlebar(gPainter *target); + void recalcClientRect(); + int eventHandler(const eWidgetEvent &event); + void willShow(); + void willHide(); +public: + enum { OFF, ON }; + static void globalCancel(int mode) { globCancel=mode; } + eRect getTitleBarRect(); + /** + * \brief Constructs the window + * + * \arg takefocus the \c eWidget::eWidget takefocus parameter. You don't need to set it if just + * one widget \e inside the parent needs focus. That widget can apply for it by itself. + */ + eWindow(int takefocus=0); + + /** + * destructs the window. + */ + ~eWindow(); +}; + +#endif diff --git a/lib/gui/guiactions.cpp b/lib/gui/guiactions.cpp new file mode 100644 index 00000000..f31fa78c --- /dev/null +++ b/lib/gui/guiactions.cpp @@ -0,0 +1,8 @@ +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/gui/guiactions.h> + +eAutoInitP0<cursorActions> i_cursorActions(eAutoInitNumbers::actions, "cursor actions"); +eAutoInitP0<focusActions> i_focusActions(eAutoInitNumbers::actions, "focus actions"); +eAutoInitP0<listActions> i_listActions(eAutoInitNumbers::actions, "list actions"); +eAutoInitP0<shortcutActions> i_shortcutActions(eAutoInitNumbers::actions, "shortcut actions"); diff --git a/lib/gui/guiactions.h b/lib/gui/guiactions.h new file mode 100644 index 00000000..82967673 --- /dev/null +++ b/lib/gui/guiactions.h @@ -0,0 +1,90 @@ +#ifndef __src__lib__gui__guiactions_h__ +#define __src__lib__gui__guiactions_h__ + +#include <lib/base/init.h> +#include <lib/base/i18n.h> +#include <lib/gui/actions.h> + +struct cursorActions +{ + eActionMap map; + eAction up, down, left, right, insertchar, deletechar, capslock, ok, cancel, help; + cursorActions(): + map("cursor", "Cursor"), + up(map, "up", _("up"), eAction::prioWidget), + down(map, "down", _("down"), eAction::prioWidget), + left(map, "left", _("left"), eAction::prioWidget), + right(map, "right", _("right"), eAction::prioWidget), + insertchar(map, "insertchar", _("next char"), eAction::prioWidget), + deletechar(map, "deletechar", _("prev char"), eAction::prioWidget), + capslock(map, "capslock", _("CapsLock"), eAction::prioWidget), + ok(map, "ok", "OK", eAction::prioWidget), + cancel(map, "cancel", _("cancel"), eAction::prioDialog), + help(map, "help", _("show the help window"), eAction::prioGlobal) + { + } +}; + +extern eAutoInitP0<cursorActions> i_cursorActions; + +struct focusActions +{ + eActionMap map; + eAction up, down, left, right; + focusActions(): + map("focus", "Focus"), + up(map, "up", _("up"), eAction::prioGlobal), + down(map, "down", _("down"), eAction::prioGlobal), + left(map, "left", _("left"), eAction::prioGlobal), + right(map, "right", _("right"), eAction::prioGlobal) + { + } +}; + +extern eAutoInitP0<focusActions> i_focusActions; + +struct listActions +{ + eActionMap map; + eAction pageup, pagedown; + listActions(): + map("list", "Listen"), + pageup(map, "pageup", _("page up"), eAction::prioWidget+1), + pagedown(map, "pagedown", _("page down"), eAction::prioWidget+1) + { + } +}; + +extern eAutoInitP0<listActions> i_listActions; + +struct shortcutActions +{ + eActionMap map; + eAction number0, number1, number2, number3, number4, + number5, number6, number7, number8, number9, + red, green, yellow, blue, escape; + shortcutActions(): + map("shortcut", "Shortcuts"), + number0(map, "0", "0", eAction::prioGlobal), + number1(map, "1", "1", eAction::prioGlobal), + number2(map, "2", "2", eAction::prioGlobal), + number3(map, "3", "3", eAction::prioGlobal), + number4(map, "4", "4", eAction::prioGlobal), + number5(map, "5", "5", eAction::prioGlobal), + number6(map, "6", "6", eAction::prioGlobal), + number7(map, "7", "7", eAction::prioGlobal), + number8(map, "8", "8", eAction::prioGlobal), + number9(map, "9", "9", eAction::prioGlobal), + red(map, "red", _("red"), eAction::prioGlobal), + green(map, "green", _("green"), eAction::prioGlobal), + yellow(map, "yellow", _("yellow"), eAction::prioGlobal), + blue(map, "blue", _("blue"), eAction::prioGlobal), + escape(map, "escape", _("escape"), eAction::prioGlobal) + { + } +}; + +extern eAutoInitP0<shortcutActions> i_shortcutActions; + + +#endif diff --git a/lib/gui/listbox.cpp b/lib/gui/listbox.cpp new file mode 100644 index 00000000..823d8da1 --- /dev/null +++ b/lib/gui/listbox.cpp @@ -0,0 +1,894 @@ +#include <lib/gui/listbox.h> +#include <lib/gdi/font.h> + +gFont eListBoxEntryText::font; +gFont eListBoxEntryTextStream::font; + +eListBoxBase::eListBoxBase(eWidget* parent, const eWidget* descr, int takefocus, int item_height, const char *deco ) +: eDecoWidget(parent, takefocus, deco), + recalced(0), descr(descr), +#ifndef DISABLE_LCD + tmpDescr(0), +#endif + colorActiveB(eSkin::getActive()->queryScheme("global.selected.background")), + colorActiveF(eSkin::getActive()->queryScheme("global.selected.foreground")), + movemode(0), MaxEntries(0), flags(0), item_height(item_height), + columns(1), in_atomic(0), top(childs.end()), bottom(childs.end()), current(childs.end()) +{ + childs.setAutoDelete(false); // machen wir selber + addActionMap(&i_cursorActions->map); + addActionMap(&i_listActions->map); +} + +eListBoxBase::~eListBoxBase() +{ + while (childs.begin() != childs.end()) + delete childs.front(); +} + +void eListBoxBase::setFlags(int _flags) +{ + flags |= _flags; +} + +void eListBoxBase::removeFlags(int _flags) +{ + flags &= ~_flags; +} + +void eListBoxBase::recalcMaxEntries() +{ + // MaxEntries is PER COLUMN + if (deco_selected && have_focus) + MaxEntries = crect_selected.height(); + else if (deco) + MaxEntries = crect.height(); + else + MaxEntries = height(); + MaxEntries /= item_height; +} + +eRect eListBoxBase::getEntryRect(int pos) +{ + int lme=MaxEntries; + // in case we show partial last lines (which only works in single-column), + // we increase MaxEntries by one since we don't want the last line + // one the next (invisible) column + if ( (columns == 1) && (flags & flagShowPartial)) + ++lme; + if ( deco_selected && have_focus ) + return eRect( ePoint( deco_selected.borderLeft + ( ( pos / lme) * ( crect_selected.width() / columns ) ) , deco_selected.borderTop + ( pos % lme) * item_height ), eSize( crect_selected.width() / columns , item_height ) ); + else if (deco) + return eRect( ePoint( deco.borderLeft + ( ( pos / lme ) * ( crect.width() / columns ) ) , deco.borderTop + ( pos % lme) * item_height ), eSize( crect.width() / columns , item_height ) ); + else if ( deco_selected ) + return eRect( ePoint( deco_selected.borderLeft + ( ( pos / lme) * ( crect_selected.width() / columns ) ) , deco_selected.borderTop + ( pos % lme) * item_height ), eSize( crect_selected.width() / columns , item_height ) ); + else + return eRect( ePoint( ( ( pos / lme ) * ( size.width() / columns ) ) , ( pos % lme) * item_height ), eSize( size.width() / columns , item_height ) ); +} + +void eListBoxBase::setColumns(int col) +{ + if (col) + columns=col; +} + +int eListBoxBase::setProperty(const eString &prop, const eString &value) +{ + if (prop == "noPageMovement") + { + if (value == "off") + flags |= ~flagNoPageMovement; + else + flags |= flagNoPageMovement; + } + else if (prop == "noUpDownMovement") + { + if (value == "off") + flags |= ~flagNoUpDownMovement; + else + flags |= flagNoUpDownMovement; + } + else if (prop=="activeForegroundColor") + colorActiveF=eSkin::getActive()->queryScheme(value); + else if (prop=="activeBackgroundColor") + colorActiveB=eSkin::getActive()->queryScheme(value); + else if (prop=="showEntryHelp") + setFlags( flagShowEntryHelp ); + else if (prop=="columns") + setColumns( value?atoi(value.c_str()):1 ); + else + return eDecoWidget::setProperty(prop, value); + + return 0; +} + +void eListBoxBase::recalcClientRect() +{ + if (deco) + { + crect.setLeft( deco.borderLeft ); + crect.setTop( deco.borderTop ); + crect.setRight( width() - deco.borderRight ); + crect.setBottom( height() - deco.borderBottom ); + } + if (deco_selected) + { + crect_selected.setLeft( deco_selected.borderLeft ); + crect_selected.setTop( deco_selected.borderTop ); + crect_selected.setRight( width() - deco_selected.borderRight ); + crect_selected.setBottom( height() - deco_selected.borderBottom ); + } +} + +int eListBoxBase::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::changedSize: + recalcClientRect(); + recalcMaxEntries(); + init(); + break; + case eWidgetEvent::evtAction: + if ((event.action == &i_listActions->pageup) && !(flags & flagNoPageMovement)) + moveSelection(dirPageUp); + else if ((event.action == &i_listActions->pagedown) && !(flags & flagNoPageMovement)) + moveSelection(dirPageDown); + else if ((event.action == &i_cursorActions->up) && !(flags & flagNoUpDownMovement)) + moveSelection(dirUp); + else if ((event.action == &i_cursorActions->down) && !(flags & flagNoUpDownMovement)) + moveSelection(dirDown); + else if (event.action == &i_cursorActions->ok) + { + if ( current == childs.end() ) + /*emit*/ SendSelected(0); + else + /*emit*/ SendSelected(*current); + } + else if (event.action == &i_cursorActions->cancel && MaxEntries > 1 ) + /*emit*/ SendSelected(0); + else + break; + return 1; + default: + break; + } + return eWidget::eventHandler(event); +} + +void eListBoxBase::invalidateContent() +{ + if ( have_focus && deco_selected ) + invalidate( crect_selected ); + else if ( deco ) + invalidate( crect ); + else + invalidate(); +} + +int eListBoxBase::newFocus() +{ + if (deco && deco_selected) + { + recalcMaxEntries(); + + if (isVisible()) + invalidate(); + + return 1; + } + return 0; +} + +int eListBoxBase::setCurrent(const eListBoxEntry *c, bool sendSelected ) +{ +/* if (childs.empty() || ((current != childs.end()) && (*current == c))) // no entries or current is equal the entry to search + return E_ALLREADY_SELECTED; // do nothing*/ + + if ( childs.empty() ) + return E_COULDNT_FIND; + + ePtrList<eListBoxEntry>::iterator item(childs.begin()), it(childs.begin()); + + for ( ; item != childs.end(); ++item) + if ( *item == c ) + break; + + if ( item == childs.end() ) // entry not in listbox... do nothing + return E_COULDNT_FIND; + + int newCurPos=-1; + int oldCurPos=-1; + ePtrList<eListBoxEntry>::iterator oldCur(current); + + int i = 0; + + for (it=top; it != bottom; ++it, ++i) // check if entry to set between bottom and top + { + if (it == item) + { + newCurPos=i; + current = it; + } + if ( it == oldCur) + oldCurPos=i; + } + + if (newCurPos != -1) // found on current screen, so redraw only old and new + { + if (isVisible()) + { + if (in_atomic) + { + if (atomic_redraw == arNothing) + { + atomic_redraw = arCurrentOld; + atomic_old = oldCurPos; + } + if (atomic_redraw == arCurrentOld) + atomic_new = newCurPos; + } else + { + invalidateEntry(newCurPos); + if (oldCurPos != -1) + invalidateEntry(oldCurPos); + } + } + } else // the we start to search from begin + { + bottom = childs.begin(); + + while (newCurPos == -1 && MaxEntries ) // MaxEntries is already checked above... + { + if ( bottom != childs.end() ) + top = bottom; // nächster Durchlauf + + for ( i = 0; (i < (MaxEntries*columns) ) && (bottom != childs.end()); ++bottom, ++i) + { + if (bottom == item) + { + current = bottom; // we have found + ++newCurPos; + } + } + } + if (isVisible()) + { + if (!in_atomic) + invalidateContent(); // Draw all + else + atomic_redraw=arAll; + } + } + + if (!in_atomic) + { + /*emit*/ SendSelChanged(*current); + if ( sendSelected ) + /*emit*/ SendSelected(*current); + } + else + { + atomic_selchanged=1; + if ( sendSelected ) + atomic_selected=1; + } + + return OK; +} + +void eListBoxBase::append(eListBoxEntry* entry, bool holdCurrent, bool front) +{ + eListBoxEntry* cur = 0; + if (holdCurrent) + cur = current; + + if ( front ) + childs.push_front(entry); + else + childs.push_back(entry); + init(); + + if (cur) + setCurrent(cur); +} + +void eListBoxBase::remove(eListBoxEntry* entry, bool holdCurrent) +{ + eListBoxEntry* cur = 0; + + if (holdCurrent && current != entry) + cur = current; + + childs.take(entry); + init(); + + if (cur) + setCurrent(cur); +} + +void eListBoxBase::clearList() +{ + while (!childs.empty()) + delete childs.first(); + current = top = bottom = childs.end(); + if (!in_atomic) + { + /*emit*/ SendSelChanged(0); + invalidateContent(); + } else + { + atomic_selected=0; + atomic_selchanged=0; + atomic_redraw=arAll; + atomic_new=0; + atomic_old=0; + } +} + +eListBoxEntry *eListBoxBase::goNext() +{ + moveSelection(dirDown); + return current!=childs.end() ? *current : 0; +} + +eListBoxEntry* eListBoxBase::goPrev() +{ + moveSelection(dirUp); + return current!=childs.end() ? *current : 0; +} + +void eListBoxBase::redrawWidget(gPainter *target, const eRect &where) +{ + eRect rc; + + if (deco_selected && have_focus) + { + deco_selected.drawDecoration(target, ePoint(width(), height())); + rc = crect_selected; + } + else if (deco) + { + deco.drawDecoration(target, ePoint(width(), height())); + rc = crect; + } + else + rc = where; + + int i=0; + for (ePtrList<eListBoxEntry>::iterator entry(top); ((flags & flagShowPartial) || (entry != bottom)) && (entry != childs.end()); ++entry) + { + eRect rect = getEntryRect(i); + + eString s; + + if ( rc.intersects(rect) ) + { + target->clip(rect & rc); + if ( entry == current ) + { +#ifndef DISABLE_LCD + if ( LCDTmp ) // LCDTmp is only valid, when we have the focus + LCDTmp->setText( entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 1 ) ); + else if ( parent->LCDElement && have_focus ) + parent->LCDElement->setText( entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 1 ) ); + else +#endif + entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), ( have_focus ? 1 : ( MaxEntries > 1 ? 2 : 0 ) ) ); + } + else + entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 0 /*( have_focus ? 0 : ( MaxEntries > 1 ? 2 : 0 ) )*/ ); + target->clippop(); + } + // special case for "showPartial": as bottom is set to the + // last, half visible entry we want to redraw this, too. + if (flags & flagShowPartial) + if (entry == bottom) + break; + + ++i; + } +} + +void eListBoxBase::gotFocus() +{ +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) // detect if LCD Avail + if (descr) + { + parent->LCDElement->setText(""); + LCDTmp = new eLabel(parent->LCDElement); + LCDTmp->hide(); + eSize s = parent->LCDElement->getSize(); + LCDTmp->move(ePoint(0,s.height()/2)); + LCDTmp->resize(eSize(s.width(), s.height()/2)); + LCDTmp->show(); + tmpDescr = new eLabel(parent->LCDElement); + tmpDescr->hide(); + tmpDescr->move(ePoint(0,0)); + tmpDescr->resize(eSize(s.width(), s.height()/2)); + tmpDescr->setText( descr->getText() ); + tmpDescr->show(); + } +#endif + ++have_focus; + + if (!childs.empty()) + { + if ( newFocus() ) // recalced ? + { + ePtrList<eListBoxEntry>::iterator it = current; + init(); + setCurrent(it); + } + else if ( isVisible() ) + { + int i=0; + for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry) + if (entry == current) + invalidateEntry(i); + } + } + if (flags & flagShowEntryHelp) + setHelpText( current != childs.end() ? current->getHelpText(): eString(" ")); // eString(_("no description available"))); +} + +void eListBoxBase::lostFocus() +{ +#ifndef DISABLE_LCD + if ( descr ) + { + delete LCDTmp; + LCDTmp=0; + delete tmpDescr; + tmpDescr=0; + } +#endif + --have_focus; + + if (!childs.empty()) + if ( newFocus() ) //recalced ? + { + ePtrList<eListBoxEntry>::iterator it = current; + init(); + setCurrent(it); + } + else if ( isVisible() ) + { + int i = 0; + for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry) + if (entry == current) + invalidateEntry(i); + } +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) + parent->LCDElement->setText(""); +#endif +} + +void eListBoxBase::init() +{ + current = top = bottom = childs.begin(); + for (int i = 0; i < (MaxEntries*columns); ++i, ++bottom) + if (bottom == childs.end() ) + break; + if (!in_atomic) + { + invalidateContent(); + } + else + { + atomic_redraw=arAll; + } +} + +int eListBoxBase::moveSelection(int dir, bool sendSelected) +{ + int direction=0, forceredraw=0; + + if (childs.empty()) + return 0; + + ePtrList<eListBoxEntry>::iterator oldptr=current, oldtop=top; + + switch (dir) + { + case dirPageDown: + direction=+1; + for (int i = 0; i < MaxEntries; ++i) + { + if (++current == bottom) // unten (rechts) angekommen? page down + { + if (bottom == childs.end()) // einzige ausnahme: unten (rechts) angekommen + { + --current; + break; + } + for (int i = 0; i < MaxEntries * columns; ++i) + { + if (bottom != childs.end()) + { + ++bottom; + ++top; + } + } + } + } + break; + + case dirPageUp: + direction=-1; + for (int i = 0; i < MaxEntries; ++i) + { + if (current == childs.begin()) + break; + + if (current-- == top/* && current != childs.begin()*/ ) // oben (links) angekommen? page up + { + for (int i = 0; i < MaxEntries * columns; ++i) + { + if (--top == childs.begin()) // einzige ausnahme: oben (links) angekommen + break; + } + + // und einmal bottom neuberechnen :) + bottom=top; + for (int i = 0; i < MaxEntries*columns; ++i) + if (bottom != childs.end()) + ++bottom; + } + } + break; + + case dirUp: + if ( current == childs.begin() ) // wrap around? + { + direction=+1; + current = childs.end(); // select last + --current; + top = bottom = childs.end(); + for (int i = 0; i < MaxEntries*columns; ++i, --top) + if (top == childs.begin()) + break; + } else + { + direction=-1; + if (current-- == top) // new top must set + { + for (int i = 0; i < MaxEntries*columns; ++i, --top) + if (top == childs.begin()) + break; + bottom=top; + for (int i = 0; i < MaxEntries*columns; ++i, ++bottom) + if (bottom == childs.end()) + break; + } + } + break; + + case dirDown: + if ( current == --ePtrList<eListBoxEntry>::iterator(childs.end()) ) // wrap around? + { + direction=-1; + top = current = bottom = childs.begin(); // goto first + for (int i = 0; i < MaxEntries * columns; ++i, ++bottom) + if ( bottom == childs.end() ) + break; + } + else + { + direction=+1; + if (++current == bottom) // ++current ?? + { + for (int i = 0; i<MaxEntries * columns; ++i) + { + if (bottom != childs.end() ) + ++bottom; + if (top != childs.end() ) + ++top; + } + } + } + break; + case dirFirst: + direction=-1; + top = current = bottom = childs.begin(); // goto first; + for (int i = 0; i < MaxEntries * columns; ++i, ++bottom) + if ( bottom == childs.end() ) + break; + break; + case dirLast: + direction=1; + top=bottom=current=childs.end(); + if (current == childs.begin()) + break; // empty. + + for (int i = 0; i < MaxEntries * columns; ++i) + if (top != childs.begin()) + --top; + --current; + break; + default: + return 0; + } + + if (current != oldptr) // current has changed + { + if (movemode) + { + // feel free to rewrite using stl::copy[_backward], but i didn't succeed. + std::list<eListBoxEntry*>::iterator o=oldptr, + c=current, + curi=current, + oldi=oldptr; + int count=0; + + eListBoxEntry* old=*o; + + if (direction > 0) + { + ++o; + ++c; + while (o != c) + { + *oldi++=*o++; + ++count; + } + } else + { + while (o != curi) + { + *oldi--=*--o; + ++count; + } + } + + if (count > 1) + forceredraw=1; + + *curi=old; + } + } + + if (!in_atomic) + { + /*emit*/ SendSelChanged(*current); + if ( sendSelected ) + /*emit*/ SendSelected(*current); + } + else + { + atomic_selchanged=1; + if ( sendSelected ) + atomic_selected=1; + } + + if (flags & flagShowEntryHelp) + setHelpText( current != childs.end() ? current->getHelpText():eString(_("no description available"))); + + if (isVisible()) + { + if ((oldtop != top) || forceredraw) + { + if (in_atomic) + atomic_redraw=arAll; + else + invalidateContent(); + } else if ( current != oldptr) + { + int i=0; + int old=-1, cur=-1; + + for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry) + if ( entry == oldptr) + old=i; + else if ( entry == current ) + cur=i; + + if (in_atomic) + { + if (atomic_redraw == arNothing) + { + atomic_old=old; + atomic_redraw = arCurrentOld; + } + if (atomic_redraw == arCurrentOld) + atomic_new=cur; + } else + { + if (old != -1) + invalidateEntry(old); + if (cur != -1) + invalidateEntry(cur); + } + } + } + return 1; +} + +void eListBoxBase::setActiveColor(gColor back, gColor front) +{ + colorActiveB=back; + colorActiveF=front; + + if (current != childs.end()) + { + int i = 0; + for (ePtrList<eListBoxEntry>::iterator it(top); it != bottom; ++i, ++it) + { + if (it == current) + { + invalidateEntry(i); + break; + } + } + } +} + +void eListBoxBase::beginAtomic() +{ + if (!in_atomic++) + { + atomic_redraw=arNothing; + atomic_selchanged=0; + atomic_selected=0; + atomic_new=-1; + } +} + +void eListBoxBase::endAtomic() +{ + if (!--in_atomic) + { + if (atomic_redraw == arAll) + invalidateContent(); + else if (atomic_redraw == arCurrentOld) + { + if (atomic_new != -1) + invalidateEntry(atomic_new); + if (atomic_old != -1) + invalidateEntry(atomic_old); + } + if (atomic_selchanged) + if (childs.empty()) + /*emit*/ SendSelChanged(0); + else + /*emit*/ SendSelChanged(*current); + + if (atomic_selected) + if (childs.empty()) + /*emit*/ SendSelected(0); + else + /*emit*/ SendSelected(*current); + } +} + +void eListBoxBase::sort() +{ + eListBoxEntry* cur = current; + childs.sort(); + + init(); + + if (cur) + setCurrent(cur); +} + +void eListBoxEntry::drawEntryBorder(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF ) +{ + rc->setForegroundColor(coActiveB); + rc->line( ePoint(rect.left(), rect.bottom()-1), ePoint(rect.right()-1, rect.bottom()-1) ); + rc->line( ePoint(rect.left(), rect.top()), ePoint(rect.right()-1, rect.top()) ); + rc->line( ePoint(rect.left(), rect.top()), ePoint(rect.left(), rect.bottom()-1) ); + rc->line( ePoint(rect.right()-1, rect.top()), ePoint(rect.right()-1, rect.bottom()-1) ); + rc->line( ePoint(rect.left()+1, rect.bottom()-2), ePoint(rect.right()-2, rect.bottom()-2) ); + rc->line( ePoint(rect.left()+1, rect.top()+1), ePoint(rect.right()-2, rect.top()+1) ); + rc->line( ePoint(rect.left()+1, rect.top()+2), ePoint(rect.left()+1, rect.bottom()-3) ); + rc->line( ePoint(rect.right()-2, rect.top()+2), ePoint(rect.right()-2, rect.bottom()-3) ); + rc->line( ePoint(rect.left()+2, rect.bottom()-3), ePoint(rect.right()-3, rect.bottom()-3) ); + rc->line( ePoint(rect.left()+2, rect.top()+2), ePoint(rect.right()-3, rect.top()+2) ); + rc->line( ePoint(rect.left()+2, rect.top()+3), ePoint(rect.left()+2, rect.bottom()-4) ); + rc->line( ePoint(rect.right()-3, rect.top()+3), ePoint(rect.right()-3, rect.bottom()-4) ); +} + +void eListBoxEntry::drawEntryRect(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state ) +{ + if ( (coNormalB != -1 && !state) || (state && coActiveB != -1) ) + { + rc->setForegroundColor(state?coActiveB:coNormalB); + rc->fill(rect); + rc->setBackgroundColor(state?coActiveB:coNormalB); + } + else + { + eWidget *w=listbox->getNonTransparentBackground(); + rc->setForegroundColor(w->getBackgroundColor()); + rc->fill(rect); + rc->setBackgroundColor(w->getBackgroundColor()); + } + rc->setForegroundColor(state?coActiveF:coNormalF); +} + +eListBoxEntryText::~eListBoxEntryText() +{ + if (para) + { + para->destroy(); + para = 0; + } +} + +int eListBoxEntryText::getEntryHeight() +{ + if ( !font.pointSize) + font = eSkin::getActive()->queryFont("eListBox.EntryText.normal"); + + return calcFontHeight( font ) + 4; +} + +int eListBoxEntryTextStream::getEntryHeight() +{ + if ( !font.pointSize) + font = eSkin::getActive()->queryFont("eListBox.EntryText.normal"); + + return calcFontHeight( font ) + 4; +} + +int calcFontHeight( const gFont& font) +{ + eTextPara *test; + test = new eTextPara( eRect(0,0,100,50) ); + test->setFont( font ); + test->renderString("Mjdyl"); + int i = test->getBoundBox().height(); + test->destroy(); + return i; +} + +const eString& eListBoxEntryText::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state) +{ + bool b; + + if ( (b = (state == 2)) ) + state = 0; + + drawEntryRect( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF, state ); + + if (!para) + { + para = new eTextPara( eRect( 0, 0, rect.width(), rect.height() ) ); + para->setFont( font ); + para->renderString(text); + para->realign(align); +// yOffs = ((rect.height() - para->getBoundBox().height()) / 2 + 0) - para->getBoundBox().top() ; + yOffs=0; + } + rc->renderPara(*para, ePoint( rect.left(), rect.top()+yOffs ) ); + + if (b) + drawEntryBorder( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF ); + + return text; +} + +const eString &eListBoxEntryTextStream::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state) +{ + rc->setFont( font ); + + drawEntryRect( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF, state ); + + rc->setForegroundColor(state?coActiveF:coNormalF); + rc->renderText(rect, text.str()); + + static eString ret; + return ret = text.str(); +} + +void eListBoxEntryText::SetText(const eString& txt) +{ + if(para){ + para->destroy(); + para=0; + }; + text=txt; +} diff --git a/lib/gui/listbox.h b/lib/gui/listbox.h new file mode 100644 index 00000000..b4461b20 --- /dev/null +++ b/lib/gui/listbox.h @@ -0,0 +1,278 @@ +#ifndef __listbox_h +#define __listbox_h + +#include <sstream> + +#include <lib/driver/rc.h> +#include <lib/gdi/grc.h> +#include <lib/gdi/fb.h> +#include <lib/gui/ewidget.h> +#include <lib/gui/eskin.h> +#include <lib/gui/ewindow.h> +#include <lib/gui/guiactions.h> +#include <lib/gui/statusbar.h> + +int calcFontHeight( const gFont& font ); + +class eListBoxEntry; + +class eListBoxBase: public eDecoWidget +{ + int recalced; + const eWidget* descr; +#ifndef DISABLE_LCD + eLabel* tmpDescr; // used for description Label in LCD +#endif + gColor colorActiveB, colorActiveF; + eRect crect, crect_selected; + enum { arNothing, arCurrentOld, arAll}; + int movemode, MaxEntries, flags, item_height, columns, in_atomic, atomic_redraw, atomic_old, atomic_new; + bool atomic_selchanged; + bool atomic_selected; +protected: + ePtrList<eListBoxEntry>::iterator top, bottom, current; + eListBoxBase(eWidget* parent, const eWidget* descr=0, int takefocus=1, int item_height=0, const char *deco="eListBox" ); + ePtrList<eListBoxEntry> childs; + eListBoxEntry* getCurrent() { return current != childs.end() ? *current : 0; } + eListBoxEntry* getNext() { ePtrList<eListBoxEntry>::iterator c=current; ++c; return c != childs.end() ? *c : 0; } + eListBoxEntry* goNext(); + eListBoxEntry* goPrev(); + int setProperty(const eString &prop, const eString &value); +private: + eRect getEntryRect(int n); + int eventHandler(const eWidgetEvent &event); + void eraseBackground() {}; + void recalcMaxEntries(); + void recalcClientRect(); + int newFocus(); + void redrawWidget(gPainter *target, const eRect &area); + void lostFocus(); + void gotFocus(); + void init(); + virtual void SendSelected( eListBoxEntry* entry )=0; + virtual void SendSelChanged( eListBoxEntry* entry )=0; +public: + ~eListBoxBase(); + enum { dirPageDown, dirPageUp, dirDown, dirUp, dirFirst, dirLast }; + enum { flagNoUpDownMovement=1, flagNoPageMovement=2, flagShowEntryHelp=4, flagShowPartial=8 }; + enum { OK = 0, ERROR=1, E_ALLREADY_SELECTED = 2, E_COULDNT_FIND = 4, E_INVALID_ENTRY = 8, E_NOT_VISIBLE = 16 }; + void setFlags(int); + void removeFlags(int); + void invalidateEntry(int n){ invalidate(getEntryRect(n));} + void invalidateContent(); + void setColumns(int col); + int getColumns() { return columns; } + void setMoveMode(int move) { movemode=move; } + void append(eListBoxEntry* e, bool holdCurrent=false, bool front=false); + void remove(eListBoxEntry* e, bool holdCurrent=false); + void clearList(); + int getCount() { return childs.size(); } + int setCurrent(const eListBoxEntry *c, bool sendSelected=false); + void sort(); + int moveSelection(int dir, bool sendSelected=false); + void setActiveColor(gColor back, gColor front); + void beginAtomic(); + void endAtomic(); + void FakeFocus( int i ) { have_focus=i; } + void invalidateCurrent() + { + int n=0; + for (ePtrList<eListBoxEntry>::iterator i(top); i != bottom; ++i, ++n) + if ( i == current ) + invalidate(getEntryRect(n)); + } +}; + +template <class T> +class eListBox: public eListBoxBase +{ + void SendSelected( eListBoxEntry* entry ) + { + /*emit*/ selected((T*)entry); + } + void SendSelChanged( eListBoxEntry* entry ) + { + /*emit*/ selchanged((T*)entry); + } +public: + Signal1<void, T*> selected; + Signal1<void, T*> selchanged; + eListBox(eWidget *parent, const eWidget* descr=0, int takefocus=1 ) + :eListBoxBase( parent, descr, takefocus, T::getEntryHeight() ) + { + } + T* getCurrent() { return (T*)eListBoxBase::getCurrent(); } + T* getNext() { return (T*)eListBoxBase::getNext(); } + T* goNext() { return (T*)eListBoxBase::goNext(); } + T* goPrev() { return (T*)eListBoxBase::goPrev(); } + + template <class Z> + int forEachEntry(Z ob) + { + for (ePtrList<eListBoxEntry>::iterator i(childs.begin()); i!=childs.end(); ++i) + if ( ob((T&)(**i)) ) + return OK; + + return ERROR; + } + + template <class Z> + int forEachVisibleEntry(Z ob) + { + if (!isVisible()) + return E_NOT_VISIBLE; + + for (ePtrList<eListBoxEntry>::iterator i(top); i!=bottom; ++i) + if ( ob((T&)(**i)) ) + return OK; + + return ERROR; + } +}; + +class eListBoxEntry: public Object +{ + friend class eListBox<eListBoxEntry>; +protected: + eListBox<eListBoxEntry>* listbox; + eString helptext; +public: + eListBoxEntry(eListBox<eListBoxEntry>* parent, eString hlptxt=0) + :listbox(parent), helptext(hlptxt?hlptxt:eString(" ")) + { + if (listbox) + listbox->append(this); + } + virtual ~eListBoxEntry() + { + if (listbox) + listbox->remove(this); + } + virtual bool operator < ( const eListBoxEntry& e)const + { + return false; + } + virtual const eString& redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state )=0; + void drawEntryRect(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state); + void drawEntryBorder(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF); + const eString &getHelpText() const { return helptext; } +}; + +class eListBoxEntryText: public eListBoxEntry +{ + friend class eListBox<eListBoxEntryText>; +protected: + eString text; + void *key; + int align; + eTextPara *para; + int yOffs; + static gFont font; + int keytype; +public: + enum { value, ptr }; + static int getEntryHeight(); + + eListBoxEntryText(eListBox<eListBoxEntryText>* lb, const char* txt=0, void *key=0, int align=0, const eString &hlptxt="", int keytype = value ) + :eListBoxEntry( (eListBox<eListBoxEntry>*)lb, hlptxt ), text(txt), + key(key), align(align), para(0), keytype(keytype) + { + } + + eListBoxEntryText(eListBox<eListBoxEntryText>* lb, const eString& txt, void* key=0, int align=0, const eString &hlptxt="", int keytype = value ) + :eListBoxEntry( (eListBox<eListBoxEntry>*)lb, hlptxt ), text(txt), + key(key), align(align), para(0), keytype(keytype) + { + } + + ~eListBoxEntryText(); + + bool operator < ( const eListBoxEntry& e) const + { + if (key == ((eListBoxEntryText&)e).key || keytype == ptr) + return text < ((eListBoxEntryText&)e).text; + else + return key < ((eListBoxEntryText&)e).key; + } + + void *& getKey() { return key; } + const void* getKey() const { return key; } + const eString& getText() { return text; } + void SetText(const eString& txt); // not setText !!! +protected: + const eString& redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state ); +}; + +class eListBoxEntryTextStream: public eListBoxEntry +{ + friend class eListBox<eListBoxEntryTextStream>; +protected: + std::stringstream text; + static gFont font; +public: + static int getEntryHeight(); + + eListBoxEntryTextStream(eListBox<eListBoxEntryTextStream>* lb) + :eListBoxEntry((eListBox<eListBoxEntry>*)lb) + { + } + + bool operator < ( const eListBoxEntryTextStream& e) const + { + return text.str() < e.text.str(); + } + +protected: + const eString &redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state ); +}; + +class eListBoxEntryMenu: public eListBoxEntryText +{ + friend class eListBox<eListBoxEntryMenu>; +public: + Signal0<void> selected; + + eListBoxEntryMenu(eListBox<eListBoxEntryMenu>* lb, const char* txt, const eString &hlptxt="", int align=0 ) + :eListBoxEntryText((eListBox<eListBoxEntryText>*)lb, txt, 0, align, hlptxt) + { + if (listbox) + CONNECT(listbox->selected, eListBoxEntryMenu::LBSelected); + } + void LBSelected(eListBoxEntry* t) + { + if (t == this) + /* emit */ selected(); + } +}; + +template <class T> +class eListBoxWindow: public eWindow +{ +public: + int Entrys; + int width; + eListBox<T> list; + eStatusBar *statusbar; + eListBoxWindow(eString Title="", int Entrys=0, int width=400, bool sbar=0); +}; + +template <class T> +inline eListBoxWindow<T>::eListBoxWindow(eString Title, int Entrys, int width, bool sbar) + : eWindow(0), Entrys(Entrys), width(width), list(this), statusbar(sbar?new eStatusBar(this):0) +{ + list.setFlags( eListBoxBase::flagShowEntryHelp ); + setText(Title); + cresize( eSize(width, (sbar?40:10)+Entrys*T::getEntryHeight() ) ); + list.move(ePoint(10, 5)); + list.resize(eSize(getClientSize().width()-20, getClientSize().height()-(sbar?35:5) )); + if (sbar) + { + statusbar->setFlags(eStatusBar::flagVCenter); + statusbar->move( ePoint(0, getClientSize().height()-30) ); + statusbar->resize( eSize( getClientSize().width(), 30) ); + statusbar->loadDeco(); + statusbar->show(); + } +} + +#endif diff --git a/lib/gui/multipage.cpp b/lib/gui/multipage.cpp new file mode 100644 index 00000000..e494078d --- /dev/null +++ b/lib/gui/multipage.cpp @@ -0,0 +1,64 @@ +#include <errno.h> +#include <lib/gui/multipage.h> +#include <lib/gui/ewidget.h> + +eMultipage::eMultipage() +{ +} + +int eMultipage::prev() +{ + if (list.current() == list.begin()) + return -ENOENT; + if (list.current() != list.end()) + list.current()->hide(); + list.prev(); + list.current()->show(); + return 0; +} + +int eMultipage::next() +{ + if (list.current() == *--list.end()) + return -ENOENT; + list.current()->hide(); + list.next(); + if (list.current() == list.end()) + return 0; + list.current()->show(); + return 0; +} + +void eMultipage::set(eWidget *widget) +{ + if (list.current() == widget) + return; + if (list.current() != list.end()) + list.current()->hide(); + list.setCurrent(widget); + if (list.current() != list.end()) + list.current()->show(); +} + +void eMultipage::first() +{ + if (list.current() == list.begin()) + return; + if (list.current() != list.end()) + list.current()->hide(); + list.first(); + if (list.current() != list.end()) + list.current()->show(); +} + +int eMultipage::at() +{ + int num=0; + for (ePtrList<eWidget>::iterator i(list.begin()); (i != list.end()) && (i != list.current()); ++i, ++num) ; + return num; +} + +void eMultipage::addPage(eWidget *page) +{ + list.push_back(page); +} diff --git a/lib/gui/multipage.h b/lib/gui/multipage.h new file mode 100644 index 00000000..5c3cb4ed --- /dev/null +++ b/lib/gui/multipage.h @@ -0,0 +1,24 @@ +#ifndef __multipage_h_ +#define __multipage_h_ + +#include <lib/base/eptrlist.h> +class eWidget; + +class eMultipage +{ + ePtrList<eWidget> list; +public: + eMultipage(); + + int prev(); + int next(); + void set(eWidget *page); + void first(); + void addPage(eWidget *page); + eWidget *getCurrent() { return list.current(); } + + int count() { return list.size(); } + int at(); +}; + +#endif diff --git a/lib/gui/numberactions.cpp b/lib/gui/numberactions.cpp new file mode 100644 index 00000000..3503283d --- /dev/null +++ b/lib/gui/numberactions.cpp @@ -0,0 +1,5 @@ +#include <lib/gui/numberactions.h> +#include <lib/base/init_num.h> + +eAutoInitP0<numberActions> i_numberActions(eAutoInitNumbers::actions, "number actions"); + diff --git a/lib/gui/numberactions.h b/lib/gui/numberactions.h new file mode 100644 index 00000000..d12a620b --- /dev/null +++ b/lib/gui/numberactions.h @@ -0,0 +1,31 @@ +#ifndef __CORE_GUI_NUMBERACTIONS__ +#define __CORE_GUI_NUMBERACTIONS__ + +#include <lib/gui/actions.h> +#include <lib/base/i18n.h> +#include <lib/base/init.h> + +struct numberActions +{ + eActionMap map; + eAction key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, keyExt1, keyExt2; + numberActions(): + map("numbers", _("number actions")), + key0(map, "0", _("key 0"), eAction::prioDialog), + key1(map, "1", _("key 1"), eAction::prioDialog), + key2(map, "2", _("key 2"), eAction::prioDialog), + key3(map, "3", _("key 3"), eAction::prioDialog), + key4(map, "4", _("key 4"), eAction::prioDialog), + key5(map, "5", _("key 5"), eAction::prioDialog), + key6(map, "6", _("key 6"), eAction::prioDialog), + key7(map, "7", _("key 7"), eAction::prioDialog), + key8(map, "8", _("key 8"), eAction::prioDialog), + key9(map, "9", _("key 9"), eAction::prioDialog), + keyExt1(map, "ext1", _("extended key1"), eAction::prioDialog), + keyExt2(map, "ext2", _("extended key2"), eAction::prioDialog) + { + } +}; +extern eAutoInitP0<numberActions> i_numberActions; +#endif + diff --git a/lib/gui/slider.cpp b/lib/gui/slider.cpp new file mode 100644 index 00000000..dc4b9d72 --- /dev/null +++ b/lib/gui/slider.cpp @@ -0,0 +1,188 @@ +#include <lib/gui/slider.h> + +#include <lib/gui/eskin.h> +#include <lib/gui/elabel.h> +#include <lib/gui/guiactions.h> +#include <lib/base/init.h> +#include <lib/base/init_num.h> + +inline void swap( gColor& a, gColor& b ) +{ + gColor tmp = a; + a = b; + b = tmp; +} + +eSlider::eSlider( eWidget* parent, const eWidget *descr, int min, int max ) + :eProgress( parent, 1), descr(descr) +{ + activated_left = eSkin::getActive()->queryScheme( "eSlider.activated.left" ); + activated_right = eSkin::getActive()->queryScheme( "eSlider.activated.right" ); + setMin(min); + setMax(max); + incrementation = 4; // in Percent + addActionMap(&i_cursorActions->map); +} + +void eSlider::setMin( int i ) +{ + min = i; +} + +void eSlider::setMax( int i ) +{ + max = (i <= min) ? 99 : i; +} + +void eSlider::setValue( int i ) +{ + if ( i >= min && i <= max ) + setPerc( (int) round( i * (double)100/((max-min)+1) ) ); + else + setPerc( 0 ); +} + +int eSlider::getValue() +{ + int ret = (int) ( (double) perc / 100 * ( (max-min)+1)); + return (ret > max ? max : ret); +} + +void eSlider::setIncrement( int i ) +{ + if (!i) + incrementation = 4; + else + incrementation = i; +} + +int eSlider::setProperty( const eString &prop, const eString &val) +{ + if (prop == "leftColorActive") + activated_left=eSkin::getActive()->queryColor( prop ); + else if (prop == "rightColorActive") + activated_right=eSkin::getActive()->queryColor( prop ); + else if (prop == "incrementation") + setIncrement( atoi( val.c_str() ) ); + else if (prop == "min") + setMin( atoi(val.c_str()) ); + else if (prop == "max") + setMax( atoi(val.c_str()) ); + else + return eProgress::setProperty( prop, val ); + return 0; +} + +void eSlider::gotFocus() +{ + have_focus++; + swap( left, activated_left ); + swap( right, activated_right ); + +#ifndef DISABLE_LCD + if (parent && parent->LCDElement) // detect if LCD Avail + { + LCDTmp = new eProgress( parent->LCDElement ); + LCDTmp->hide(); + LCDTmp->setForegroundColor( 255 ); + ((eSlider*)LCDTmp)->left=255; + ((eSlider*)LCDTmp)->right=0; + ((eProgress*)LCDTmp)->setPerc( perc ); + eSize s = parent->LCDElement->getSize(); + + if (descr) + { + LCDTmp->move(ePoint(0, s.height()/2 + s.height()/4 - 6 )); + LCDTmp->resize( eSize(s.width(), 12) ); + tmpDescr = new eLabel(parent->LCDElement); + tmpDescr->hide(); + tmpDescr->move(ePoint(0,0)); + tmpDescr->resize(eSize(s.width(), s.height()/2)); + tmpDescr->setText(descr->getText()); + tmpDescr->show(); + } + else + { + LCDTmp->resize( eSize(s.width(), 8) ); + LCDTmp->move(ePoint(0, s.height() / 2 - 6)); + } + ((eProgress*)LCDTmp)->setPerc( perc ); + LCDTmp->show(); + } +#endif // DISABLE_LCD + redraw(); +} + +void eSlider::lostFocus() +{ +// swap back; + swap( left, activated_left ); + swap( right, activated_right ); + +#ifndef DISABLE_LCD + if (LCDTmp) + { + delete LCDTmp; + LCDTmp=0; + if (tmpDescr) + { + delete tmpDescr; + tmpDescr=0; + } + } +#endif + have_focus--; + invalidate(); +} + +int eSlider::eventHandler( const eWidgetEvent& event ) +{ + switch (event.type) + { + case eWidgetEvent::evtAction: + { + if(event.action == &i_cursorActions->right) + { + if ( (perc += incrementation) > 100 ) + perc = 100; + } + else if(event.action == &i_cursorActions->left) + { + if ( (perc-=incrementation) < 0 ) + perc = 0; + } + else + break; + redraw(); + /* emit */ changed( getValue() ); +#ifndef DISABLE_LCD + if (LCDTmp) + ((eProgress*)LCDTmp)->setPerc( perc ); +#endif + return 1; + } + default: + break; + } + return eProgress::eventHandler( event ); +} + +static eWidget *create_eSlider(eWidget *parent) +{ + return new eSlider(parent); +} + +class eSliderSkinInit +{ +public: + eSliderSkinInit() + { + eSkin::addWidgetCreator("eSlider", create_eSlider); + } + ~eSliderSkinInit() + { + eSkin::removeWidgetCreator("eSlider", create_eSlider); + } +}; + +eAutoInitP0<eSliderSkinInit> init_eSliderSkinInit(eAutoInitNumbers::guiobject, "eSlider"); diff --git a/lib/gui/slider.h b/lib/gui/slider.h new file mode 100644 index 00000000..81deee7c --- /dev/null +++ b/lib/gui/slider.h @@ -0,0 +1,27 @@ +#ifndef __SRC_CORE_GUI_SLIDER_ +#define __SRC_CORE_GUI_SLIDER_ + +#include <lib/gui/eprogress.h> + +class eSlider: public eProgress +{ + int incrementation, max, min; + gColor activated_left, activated_right; + const eWidget *descr; + int setProperty( const eString &prop, const eString &val); + void gotFocus(); + void lostFocus(); + int eventHandler( const eWidgetEvent& event ); + eWidget *tmpDescr; + void update(); +public: + void setMin( int i ); + void setMax( int i ); + void setIncrement( int i ); + void setValue( int i ); + int getValue(); + Signal1<void, int> changed; + eSlider( eWidget *parent, const eWidget *descr=0, int min=0, int max=99 ); +}; + +#endif // __SRC_CORE_GUI_SLIDER_ diff --git a/lib/gui/statusbar.cpp b/lib/gui/statusbar.cpp new file mode 100644 index 00000000..797c0a3b --- /dev/null +++ b/lib/gui/statusbar.cpp @@ -0,0 +1,83 @@ +#include <lib/gui/statusbar.h> + +#include <lib/base/init.h> +#include <lib/base/init_num.h> +#include <lib/gui/eskin.h> +#include <lib/gdi/font.h> + +eStatusBar::eStatusBar( eWidget* parent, const char *deco) + :eLabel(parent, 0, 0, deco), current(0) +{ + setFont( eSkin::getActive()->queryFont("eStatusBar") ); + setForegroundColor ( eSkin::getActive()->queryColor("eStatusBar.foreground") ); + setBackgroundColor ( eSkin::getActive()->queryColor("eStatusBar.background") ); + eLabel::setFlags( RS_FADE ); + initialize(); +} + + +void eStatusBar::initialize() +{ + if ( parent ) + { + if ( flags & flagOwnerDraw ) + { + if ( conn.connected() ) + conn.disconnect(); + } + else + conn = CONNECT( parent->focusChanged, eStatusBar::update ); + } +} + +void eStatusBar::update( const eWidget* p ) +{ + if (p) + { + current = p; + setText( current->getHelpText() ); + } +} + +void eStatusBar::setFlags( int fl ) +{ + if( fl == flagOwnerDraw ) + { + flags = fl; + initialize(); + } + else + eLabel::setFlags(fl); +} + +int eStatusBar::setProperty(const eString &prop, const eString &value) +{ + if (prop=="ownerDraw") + flags |= flagOwnerDraw; + else + return eLabel::setProperty(prop, value); + + initialize(); + + return 0; +} + +static eWidget *create_eStatusBar(eWidget *parent) +{ + return new eStatusBar(parent); +} + +class eStatusBarSkinInit +{ +public: + eStatusBarSkinInit() + { + eSkin::addWidgetCreator("eStatusBar", create_eStatusBar); + } + ~eStatusBarSkinInit() + { + eSkin::removeWidgetCreator("eStatusBar", create_eStatusBar); + } +}; + +eAutoInitP0<eStatusBarSkinInit> init_eStatusBarSkinInit(eAutoInitNumbers::guiobject, "eStatusBar"); diff --git a/lib/gui/statusbar.h b/lib/gui/statusbar.h new file mode 100644 index 00000000..f7f74940 --- /dev/null +++ b/lib/gui/statusbar.h @@ -0,0 +1,25 @@ +#ifndef __CORE_GUI_STATUSBAR__ +#define __CORE_GUI_STATUSBAR__ + +#include <lib/gui/ewidget.h> +#include <lib/gui/elabel.h> + +class eStatusBar : public eLabel +{ + void update( const eWidget *); + const eWidget* current; + + int setProperty(const eString &, const eString &); + void initialize(); + Connection conn; +public: + enum + { + flagOwnerDraw = 128, + }; + eStatusBar( eWidget*, const char* deco="eStatusBar" ); + void setFlags( int ); +}; + +#endif // __CORE_GUI_STATUSBAR__ + diff --git a/lib/gui/testpicture.cpp b/lib/gui/testpicture.cpp new file mode 100644 index 00000000..7afc904c --- /dev/null +++ b/lib/gui/testpicture.cpp @@ -0,0 +1,229 @@ +#include <lib/gui/testpicture.h> +#include <lib/gui/eskin.h> +#include <lib/gui/elabel.h> +#include <lib/gdi/font.h> +#include <lib/gui/guiactions.h> +#include <lib/gui/numberactions.h> + +void eTestPicture::hideDesc() +{ + if (testmode != testFUBK) + description->hide(); +} + +int eTestPicture::eventHandler(const eWidgetEvent &event) +{ + switch (event.type) + { + case eWidgetEvent::evtAction: + if (event.action == &i_cursorActions->ok) + close(-1); + else if (event.action == &i_cursorActions->cancel) + close(-1); + else if (event.action == &i_numberActions->key0) + close(0); + else if (event.action == &i_numberActions->key1) + close(1); + else if (event.action == &i_numberActions->key2) + close(2); + else if (event.action == &i_numberActions->key3) + close(3); + else if (event.action == &i_numberActions->key4) + close(4); + else if (event.action == &i_numberActions->key5) + close(5); + else if (event.action == &i_numberActions->key6) + close(6); + else if (event.action == &i_numberActions->key7) + close(7); + else if (event.action == &i_numberActions->key8) + close(8); + else if (event.action == &i_numberActions->key9) + close(9); + else + break; + return 0; + case eWidgetEvent::willShow: + desctimer.start(1000); + break; + default: + break; + } + return eWidget::eventHandler(event); +} + +void eTestPicture::redrawWidget(gPainter *target, const eRect &area) +{ + switch (testmode) + { + case testColorbar: + { + for (int i=0; i<8; ++i) + { + gColor c=basic[i]; + + target->setForegroundColor(c); + target->fill(eRect(720/8*i, 0, 720/8, 576)); + } + break; + } + case testGray: + { + for (int i=0; i<8; ++i) + { + gColor c=gray+i; + + target->setForegroundColor(c); + target->fill(eRect(720/8*i, 0, 720/8, 576)); + } + break; + } + case testFUBK: + { + // background + target->setBackgroundColor(gray+2); + target->clear(); + + // white lines + target->setForegroundColor(white); + for (int x=6; x<720; x+=44) + target->fill(eRect(x, 0, 3, 576)); + for (int y=34; y<576; y+=44) + target->fill(eRect(0, y, 720, 3)); + + for (int i=0; i<8; ++i) + { + target->setForegroundColor(basic[i]); + target->fill(eRect(140+i*55, 80, 55, 80)); + target->setForegroundColor(gray+i); + target->fill(eRect(140+i*55, 160, 55, 80)); + } +#if 1 + int freq; + int phase=0; + for (int x=0; x<440; x+=freq) + { + freq=(440-x)/44 + 1; + target->setForegroundColor(phase ? white : black); + target->fill(eRect(140+x, 320, freq, 160)); + phase = !phase; + } +#endif +#if 0 + double phase=0; + for (int x=0; x<440; ++x) + { + // freq = 0.5 .. 5Mhz -> 10 Pixel ~= 1Mhz + double inc = (x/440.0)*(x/440.0) * 3.141 * 2 / 5.0 + 0.5; + phase += inc; + int s = int((sin(phase) + 1) * 4); + if (s < 0) + s = 0; + if (s > 7) + s = 7; + target->setForegroundColor(gray + s); + target->fill(eRect(140+x, 320, 1, 160)); + } +#endif + + break; + } + case testRed: + target->setBackgroundColor(red); + target->clear(); + break; + case testGreen: + target->setBackgroundColor(green); + target->clear(); + break; + case testBlue: + target->setBackgroundColor(blue); + target->clear(); + break; + case testWhite: + target->setBackgroundColor(white); + target->clear(); + break; + case testBlack: + target->setBackgroundColor(black); + target->clear(); + break; + } +} + +eTestPicture::eTestPicture(int testmode): eWidget(0, 1), testmode(testmode), desctimer(eApp) +{ + red = eSkin::getActive()->queryColor("std_red"); + green = eSkin::getActive()->queryColor("std_green"); + blue = eSkin::getActive()->queryColor("std_blue"); + black = eSkin::getActive()->queryColor("std_black"); + white = eSkin::getActive()->queryColor("std_white"); + gray = eSkin::getActive()->queryColor("std_gray"); + setBackgroundColor(-1); + + CONNECT(desctimer.timeout, eTestPicture::hideDesc); + + basic[0] = white; + basic[1] = eSkin::getActive()->queryColor("std_dyellow"); + basic[2] = eSkin::getActive()->queryColor("std_dcyan"); + basic[3] = eSkin::getActive()->queryColor("std_dgreen"); + basic[4] = eSkin::getActive()->queryColor("std_dmagenta"); + basic[5] = eSkin::getActive()->queryColor("std_dred"); + basic[6] = eSkin::getActive()->queryColor("std_dblue"); + basic[7] = black; + + addActionMap(&i_numberActions->map); + addActionMap(&i_cursorActions->map); + + description = new eLabel(this, eLabel::flagVCenter); + switch (testmode) + { + case testColorbar: + case testRed: + case testBlue: + case testGreen: + case testWhite: + case testBlack: + case testGray: + description->move(ePoint(100, 100)); + description->resize(eSize(200, 30)); + description->setBackgroundColor(black); + description->setForegroundColor(white); + break; + case testFUBK: + description->move(ePoint(140, 240)); + description->resize(eSize(440, 80)); + description->setBackgroundColor(black); + description->setForegroundColor(white); + description->setText("ENIGMA"); + description->setAlign(eTextPara::dirCenter); + break; + default: + break; + } + switch (testmode) + { + case testColorbar: description->setText("COLORBAR"); break; + case testRed: description->setText("RED"); break; + case testBlue: description->setText("BLUE"); break; + case testGreen: description->setText("GREEN"); break; + case testWhite: description->setText("WHITE (100%)"); break; + case testGray: description->setText("0% TO 100%"); break; + case testBlack: description->setText("BLACK (0%)"); break; + } + description->show(); + + setHelpID(95); +} + +int eTestPicture::display(int mode) +{ + int res; + eTestPicture test(mode); + test.move(ePoint(0, 0)); + test.resize(eSize(720, 576)); + test.show(); + res = test.exec(); + test.hide(); + return res; +} diff --git a/lib/gui/testpicture.h b/lib/gui/testpicture.h new file mode 100644 index 00000000..568cdede --- /dev/null +++ b/lib/gui/testpicture.h @@ -0,0 +1,36 @@ +#ifndef __testpicture_h +#define __testpicture_h + +#include <lib/gui/ewidget.h> +#include <lib/gdi/grc.h> +#include <lib/base/ebase.h> + +class eLabel; + +class eTestPicture: public eWidget +{ + gColor red, green, blue, white, black; + gColor basic[8]; + gColor gray; + int testmode; + eLabel *description; + eTimer desctimer; + void hideDesc(); +protected: + int eventHandler(const eWidgetEvent &event); + void redrawWidget(gPainter *target, const eRect &area); +public: + enum { + testColorbar, + testRed, + testGreen, + testBlue, + testWhite, + testFUBK, // without circle ;) + testGray, + testBlack}; + eTestPicture(int testmode); + static int display(int mode); +}; + +#endif diff --git a/lib/gui/textinput.cpp b/lib/gui/textinput.cpp new file mode 100644 index 00000000..90ec0086 --- /dev/null +++ b/lib/gui/textinput.cpp @@ -0,0 +1,388 @@ +#include <lib/base/estring.h> +#include <lib/gui/textinput.h> +#include <lib/gui/guiactions.h> +#include <lib/gui/numberactions.h> +#include <lib/gui/eskin.h> +#include <lib/gui/ewindow.h> +#include <lib/base/init.h> +#include <lib/base/econfig.h> +#include <lib/gdi/font.h> + +eTextInputField::eTextInputField( eWidget *parent, eLabel *descr, const char *deco ) + :eButton( parent, descr, 1, deco), maxChars(0), lastKey(-1), editMode(false), nextCharTimer(eApp), + useableChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +// " +-.,:?!\"';_*/()<=>%#@&"), + "ÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîï°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ" + " +-.,:?!\"';_*/()<=>%#@&"), capslock(0) +{ + if ( eConfig::getInstance()->getKey("/ezap/rc/TextInputField/nextCharTimeout", nextCharTimeout ) ) + nextCharTimeout=0; + CONNECT( nextCharTimer.timeout, eTextInputField::nextChar ); + addActionMap(&i_numberActions->map); + flags=0; + align=eTextPara::dirLeft; +} + +void eTextInputField::updated() +{ + unsigned char c[4096]; + strcpy((char *)c,isotext.c_str()); + + text=convertDVBUTF8(c,strlen((char*)c)); + eLabel::invalidate(); + drawCursor(); +} + +void eTextInputField::nextChar() +{ + if ( curPos+1 < (int)maxChars ) + { + ++curPos; + if ( curPos > (int)isotext.length()-1 ) + isotext+=' '; + updated(); + } + lastKey=-1; +} + +// "abc2ABC", // 2 +// "def3DEF", // 3 +// "ghi4GHI»", // 4 +// "jkl5JKL", // 5 +// "mno6MNO", // 6 +// "pqrs7PQRS", // 7 +// "tuv8TUV", // 8 +// "wxyz9WXYZ", // 9 + +const char *keys[2][12] = { +// lowercase + { "+0-.,:?!\"';_", // 0 + " 1#@&/()<=>%", // 1 + "abc2ÐÑÒÓ", // 2 + "def3ÔÕÖ×", // 3 + "ghi4ØÙÚÛ", // 4 + "jkl5ÜÝÞß", // 5 + "mno6àáâã", // 6 + "pqrs7äåæç", // 7 + "tuv8èéêë", // 8 + "wxyz9íîï", // 9 + "*/()<=>%", // < + "#@&`" }, // > +// uppercase + { "+0-.,:?!\"';_", // 0 + " 1#@&/()<=>%", // 1 + "ABC2°±²³", // 2 + "DEF3´µ¶·", // 3 + "GHI4¸¹º»", // 4 + "JKL5¼½¾¿", // 5 + "MNO6ÀÁÂÃ", // 6 + "PQRS7ÄÅÆÇ", // 7 + "TUV8ÈÉÊË", // 8 + "WXYZ9ÍÎÏ", // 9 + "*/()<=>%", // < + "#@&`" } // > +}; + +void eTextInputField::setUseableChars( const char* uchars ) +{ + useableChars=uchars; +} + +void eTextInputField::setNextCharTimeout( unsigned int newtimeout ) +{ + nextCharTimeout=newtimeout; +} + +void eTextInputField::drawCursor() +{ +// eDebug("length = %d", isotext.length()); + eRect rc; + rc.setTop(crect.bottom()-4); + rc.setHeight( 3 ); + if ( isotext.length() ) // text exist? + { + if ( (int)isotext.length() > curPos) // before or on the last char? + { + const eRect &bbox = para->getGlyphBBox(curPos); + if ( !bbox.width() ) // Space + { + if (curPos) // char before space? + { + const eRect &bbBefore = para->getGlyphBBox(curPos-1); + rc.setLeft( bbBefore.right()+2 ); + } + if ( (int)isotext.length() > curPos+1) // char after space ? + { + const eRect &bbAfter = para->getGlyphBBox(curPos+1); + rc.setRight( bbAfter.left()-2 ); + } + else // no char behind Space + rc.setWidth( 10 ); + } + else + { + rc.setLeft( bbox.left() ); + rc.setWidth( bbox.width() ); + } + } + else // we are behind the last character + { + const eRect &bbox = para->getGlyphBBox(isotext.length()-1); + rc.setLeft( bbox.right() + ( ( curPos-isotext.length() ) * 10 ) + 2 ); + rc.setWidth( 10 ); + } + } + else // no one character in text + { + rc.setLeft( 2 ); + rc.setWidth( 10 ); + } + rc.moveBy( (deco_selected?crect_selected.left():crect.left())+1, 0 ); + gPainter *painter = getPainter( deco_selected?crect_selected:crect ); + painter->setForegroundColor( getForegroundColor() ); + painter->setBackgroundColor( getBackgroundColor() ); + painter->clip( rc ); + painter->fill( rc ); + painter->clippop(); + if(capslock) + { + rc.setTop(crect.top()); + rc.setHeight( 3 ); + painter->clip( rc ); + painter->fill( rc ); + painter->clippop(); + } + delete painter; +} + +int eTextInputField::eventHandler( const eWidgetEvent &event ) +{ + isotext=convertUTF8DVB(text); + switch (event.type) + { + case eWidgetEvent::changedText: + if ( maxChars < isotext.length() ) + maxChars = isotext.length(); + return eButton::eventHandler( event ); + break; + case eWidgetEvent::evtAction: + { + if ( curPos < 0 ) + curPos=0; +// eDebug("curPos=%d, isotext.length=%d",curPos, isotext.length()); + int key = -1; + if ( event.action == &i_cursorActions->capslock && editMode) + { + capslock^=1; + eLabel::invalidate(); + drawCursor(); + } + else if ( (event.action == &i_cursorActions->up || + event.action == &i_cursorActions->down) && editMode ) + { + nextCharTimer.stop(); + const char *pc1=useableChars.c_str(); + const char *pc2=strchr( pc1, isotext[curPos] ); + + if( !pc2 || !pc2[0] ) + pc2=pc1; + + if(event.action == &i_cursorActions->up) + { + pc2++; + if(!*pc2) + pc2=pc1; + } + else + { + if(pc2==pc1) + while(*pc2) + pc2++; + pc2--; + } + if ( isotext.length() ) + isotext[curPos] = *pc2; + else + isotext+=*pc2; + updated(); + } + else if (event.action == &i_cursorActions->insertchar && editMode) + { + if ( isotext.length() && isotext.length() < maxChars ) + { + isotext.insert( curPos, " "); + updated(); + } + } + else if (event.action == &i_cursorActions->deletechar && editMode) + { + if ( isotext.length() ) + { + isotext.erase( curPos, 1 ); +// eDebug("curPos=%d, length=%d", curPos, text.length() ); + if ( (int)isotext.length() == curPos ) + { +// eDebug("curPos--"); + --curPos; + } + updated(); + } + } + else if (event.action == &i_cursorActions->left && editMode ) + { + nextCharTimer.stop(); + if ( curPos > 0 ) + { + --curPos; + lastKey=-1; + updated(); + } + } + else if (event.action == &i_cursorActions->right && editMode) + { + nextCharTimer.stop(); + nextChar(); + } + else if (event.action == &i_cursorActions->ok) + { + nextCharTimer.stop(); + if ( editMode ) + { + setHelpText(oldHelpText); + + if(isotext.length()>0) + while ( isotext[isotext.length()-1] == ' ' ) + isotext.erase( isotext.length()-1 ); + + updated(); + eButton::invalidate(); // remove the underline + editMode=false; + eWindow::globalCancel(eWindow::ON); + } + else + { + oldHelpText=helptext; + oldText=text; + setHelpText(_("press ok to leave edit mode, yellow=capslock")); + editMode=true; + curPos=0; + drawCursor(); + eWindow::globalCancel(eWindow::OFF); + } + } + else if ( editMode && event.action == &i_cursorActions->cancel) + { + nextCharTimer.stop(); + editMode=false; + setText(oldText); + setHelpText(oldHelpText); + eWindow::globalCancel(eWindow::ON); + } + else if (event.action == &i_numberActions->key0) + key=0; + else if (event.action == &i_numberActions->key1) + key=1; + else if (event.action == &i_numberActions->key2) + key=2; + else if (event.action == &i_numberActions->key3) + key=3; + else if (event.action == &i_numberActions->key4) + key=4; + else if (event.action == &i_numberActions->key5) + key=5; + else if (event.action == &i_numberActions->key6) + key=6; + else if (event.action == &i_numberActions->key7) + key=7; + else if (event.action == &i_numberActions->key8) + key=8; + else if (event.action == &i_numberActions->key9) + key=9; + else if (event.action == &i_numberActions->keyExt1) + key=10; + else if (event.action == &i_numberActions->keyExt2) + key=11; + else + return eButton::eventHandler( event ); + if ( key != lastKey && nextCharTimer.isActive() ) + { + nextCharTimer.stop(); + nextChar(); + } +// eDebug("editMode = %d, key = %d", editMode, key); + if ( editMode && key != -1 ) + { + char newChar = 0; + + if ( key == lastKey ) + { + char *oldkey = strchr( keys[capslock][key], isotext[curPos] ); + newChar = oldkey?keys[capslock][key][oldkey-keys[capslock][key]+1]:0; + } + + if (!newChar) + { + newChar = keys[capslock][key][0]; + } +// eDebug("newChar = %d", newChar ); + char testChar = newChar; + do + { + if ( strchr( useableChars.c_str(), newChar ) ) // char useable? + { + if ( curPos == (int)isotext.length() ) + isotext += newChar; + else + isotext[curPos] = newChar; + updated(); + if(nextCharTimeout) + nextCharTimer.start(nextCharTimeout,true); + break; + } + else + { + nextCharTimer.stop(); + char *oldkey = strchr( keys[capslock][key], newChar ); + newChar=oldkey?keys[capslock][key][oldkey-keys[capslock][key]+1]:0; + if (!newChar) + newChar=keys[capslock][key][0]; + } + } + while( newChar != testChar ); // all chars tested.. and no char is useable.. + lastKey=key; + } + } + break; + + default: + return eButton::eventHandler( event ); + break; + } + return 1; +} + +void eTextInputField::redrawWidget( gPainter *target, const eRect &area ) +{ + eButton::redrawWidget( target, area ); +} + +static eWidget *create_eTextInputField(eWidget *parent) +{ + return new eTextInputField(parent); +} + +class eTextInputFieldSkinInit +{ +public: + eTextInputFieldSkinInit() + { + eSkin::addWidgetCreator("eTextInputField", create_eTextInputField); + } + ~eTextInputFieldSkinInit() + { + eSkin::removeWidgetCreator("eTextInputField", create_eTextInputField); + } +}; + +eAutoInitP0<eTextInputFieldSkinInit> init_eTextInputFieldSkinInit(25, "eTextInputField"); + diff --git a/lib/gui/textinput.h b/lib/gui/textinput.h new file mode 100644 index 00000000..d0901dc2 --- /dev/null +++ b/lib/gui/textinput.h @@ -0,0 +1,31 @@ +#ifndef __LIB_GUI_TEXTINPUT_H__ +#define __LIB_GUI_TEXTINPUT_H__ + +#include <lib/gui/ebutton.h> + +class eTextInputField: public eButton +{ + int curPos; + unsigned int maxChars; + int eventHandler( const eWidgetEvent &); + void redrawWidget( gPainter *target, const eRect &area ); + void drawCursor(); + void updated(); + void nextChar(); + int lastKey; + bool editMode; + eString oldText; + eString oldHelpText; + eTimer nextCharTimer; + eString useableChars; + unsigned int nextCharTimeout; + bool capslock; + eString isotext; +public: + eTextInputField( eWidget* parent, eLabel *descr=0, const char *deco="eNumber" ); + void setMaxChars( int i ) { maxChars = i; } + void setUseableChars( const char* ); + void setNextCharTimeout( unsigned int ); +}; + +#endif |
