diff options
| author | Felix Domke <tmbinc@elitedvb.net> | 2005-01-28 02:39:09 +0000 |
|---|---|---|
| committer | Felix Domke <tmbinc@elitedvb.net> | 2005-01-28 02:39:09 +0000 |
| commit | 8ade23537a682d4b0c9709d533b25702bde2ee23 (patch) | |
| tree | d558411192229a6ddb407b8b067658572b6a9e6b /lib/gui | |
| parent | 1a46b8d1505a1496dfdce0a9f96dde7efbc65d65 (diff) | |
| download | enigma2-8ade23537a682d4b0c9709d533b25702bde2ee23.tar.gz enigma2-8ade23537a682d4b0c9709d533b25702bde2ee23.zip | |
- add listbox
- add listbox example to python (press space, use 1..5)
- fix label text positions
Diffstat (limited to 'lib/gui')
| -rw-r--r-- | lib/gui/Makefile.am | 2 | ||||
| -rw-r--r-- | lib/gui/ebutton.cpp | 2 | ||||
| -rw-r--r-- | lib/gui/elabel.cpp | 4 | ||||
| -rw-r--r-- | lib/gui/elistbox.cpp | 261 | ||||
| -rw-r--r-- | lib/gui/elistbox.h | 66 | ||||
| -rw-r--r-- | lib/gui/eslider.cpp | 2 | ||||
| -rw-r--r-- | lib/gui/ewindowstyle.cpp | 36 | ||||
| -rw-r--r-- | lib/gui/ewindowstyle.h | 20 |
8 files changed, 379 insertions, 14 deletions
diff --git a/lib/gui/Makefile.am b/lib/gui/Makefile.am index 1b175c9a..670d15fc 100644 --- a/lib/gui/Makefile.am +++ b/lib/gui/Makefile.am @@ -5,5 +5,5 @@ INCLUDES = \ noinst_LIBRARIES = libenigma_gui.a libenigma_gui_a_SOURCES = \ - ebutton.cpp elabel.cpp eslider.cpp ewidget.cpp ewidgetdesktop.cpp ewindow.cpp ewindowstyle.cpp + ebutton.cpp elabel.cpp eslider.cpp ewidget.cpp ewidgetdesktop.cpp ewindow.cpp ewindowstyle.cpp elistbox.cpp diff --git a/lib/gui/ebutton.cpp b/lib/gui/ebutton.cpp index e24abd66..06cfda07 100644 --- a/lib/gui/ebutton.cpp +++ b/lib/gui/ebutton.cpp @@ -21,7 +21,7 @@ int eButton::event(int event, void *data, void *data2) getStyle(style); eLabel::event(event, data, data2); - style->drawButtonFrame(painter, eRect(ePoint(0, 0), size())); + style->drawFrame(painter, eRect(ePoint(0, 0), size()), eWindowStyle::frameButton); return 0; } diff --git a/lib/gui/elabel.cpp b/lib/gui/elabel.cpp index f9dcf31b..281a9d27 100644 --- a/lib/gui/elabel.cpp +++ b/lib/gui/elabel.cpp @@ -20,8 +20,8 @@ int eLabel::event(int event, void *data, void *data2) gPainter &painter = *(gPainter*)data2; ePtr<gFont> fnt = new gFont("Arial", 14); painter.setFont(fnt); - style->setForegroundStyle(painter); - painter.renderText(eRect(0, 0, size().width(), size().height()), m_text); + style->setStyle(painter, eWindowStyle::styleLabel); + painter.renderText(eRect(0, 0, size().width(), size().height()), m_text, gPainter::RT_HALIGN_CENTER|gPainter::RT_VALIGN_CENTER); return 0; } diff --git a/lib/gui/elistbox.cpp b/lib/gui/elistbox.cpp new file mode 100644 index 00000000..c2af3d32 --- /dev/null +++ b/lib/gui/elistbox.cpp @@ -0,0 +1,261 @@ +#include <lib/gui/elistbox.h> + +/* + The basic idea is to have an interface which gives all relevant list + processing functions, and can be used by the listbox to browse trough + the list. + + The listbox directly uses the implemented cursor. It tries hard to avoid + iterating trough the (possibly very large) list, so it should be O(1), + i.e. the performance should not be influenced by the size of the list. + + The list interface knows how to draw the current entry to a specified + offset. Different interfaces can be used to adapt different lists, + pre-filter lists on the fly etc. + + cursorSave/Restore is used to avoid re-iterating the list on redraw. + The current selection is always selected as cursor position, the + cursor is then positioned to the start, and then iterated. This gives + at most 2x m_items_per_page cursor movements per redraw, indepenent + of the size of the list. + + Although cursorSet is provided, it should be only used when there is no + other way, as it involves iterating trough the list. + */ + +class eListboxTestContent: public virtual iListboxContent +{ + DECLARE_REF; +public: + void cursorHome(); + void cursorEnd(); + int cursorMove(int count=1); + int cursorValid(); + int cursorSet(int n); + int cursorGet(); + + void cursorSave(); + void cursorRestore(); + int size(); + + RESULT connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection); + + // void setOutputDevice ? (for allocating colors, ...) .. requires some work, though + void setSize(const eSize &size); + + /* the following functions always refer to the selected item */ + void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected); +private: + int m_cursor, m_saved_cursor; + eSize m_size; +}; + +DEFINE_REF(eListboxTestContent); + +void eListboxTestContent::cursorHome() +{ + m_cursor = 0; +} + +void eListboxTestContent::cursorEnd() +{ + m_cursor = size(); +} + +int eListboxTestContent::cursorMove(int count) +{ + m_cursor += count; + + if (m_cursor < 0) + cursorHome(); + else if (m_cursor > size()) + cursorEnd(); + return 0; +} + +int eListboxTestContent::cursorValid() +{ + return m_cursor < size(); +} + +int eListboxTestContent::cursorSet(int n) +{ + m_cursor = n; + + if (m_cursor < 0) + cursorHome(); + else if (m_cursor > size()) + cursorEnd(); + return 0; +} + +int eListboxTestContent::cursorGet() +{ + return m_cursor; +} + +void eListboxTestContent::cursorSave() +{ + m_saved_cursor = m_cursor; +} + +void eListboxTestContent::cursorRestore() +{ + m_cursor = m_saved_cursor; +} + +int eListboxTestContent::size() +{ + return 10; +} + +RESULT eListboxTestContent::connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection) +{ + return 0; +} + +void eListboxTestContent::setSize(const eSize &size) +{ + m_size = size; +} + +void eListboxTestContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) +{ + ePtr<gFont> fnt = new gFont("Arial", 14); + painter.clip(eRect(offset, m_size)); + style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal); + painter.clear(); + + if (cursorValid()) + { + painter.setFont(fnt); + char string[10]; + sprintf(string, "%d.)", m_cursor); + + ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1)); + + painter.renderText(eRect(text_offset, m_size), string); + + if (selected) + style.drawFrame(painter, eRect(offset, m_size), eWindowStyle::frameListboxEntry); + } + + painter.clippop(); +} + +eListbox::eListbox(eWidget *parent): eWidget(parent) +{ + setContent(new eListboxTestContent()); + m_content->cursorHome(); + m_top = 0; + m_selected = 0; +} + +void eListbox::setContent(iListboxContent *content) +{ + m_content = content; +} + +void eListbox::moveSelection(int dir) +{ + /* we need the old top/sel to see what we have to redraw */ + int oldtop = m_top; + int oldsel = m_selected; + + /* first, move cursor */ + switch (dir) + { + case moveUp: + m_content->cursorMove(-1); + break; + case moveDown: + m_content->cursorMove(1); + /* ok - we could have reached the end. we just go one back then. */ + if (!m_content->cursorValid()) + m_content->cursorMove(-1); + break; + case moveTop: + m_content->cursorHome(); + m_top = 0; /* align with top, speeds up process */ + break; + case moveEnd: + /* move to last existing one ("end" is already invalid) */ + m_content->cursorEnd(); m_content->cursorMove(-1); + + m_top = m_content->cursorGet() - m_items_per_page + 1; + if (m_top < 0) + m_top = 0; + break; + } + + /* note that we could be on an invalid cursor position, but we don't + care. this only happens on empty lists, and should have almost no + side effects. */ + + /* now, look wether the current selection is out of screen */ + m_selected = m_content->cursorGet(); + if (m_selected < m_top) + { + m_top -= m_items_per_page; + if (m_top < 0) + m_top = 0; + } else if (m_selected >= m_top + m_items_per_page) + { + /* m_top should be always valid here as it's selected */ + m_top += m_items_per_page; + } + + if (m_top != oldtop) + invalidate(); + else + { + /* redraw the old and newly selected */ + gRegion inv = eRect(0, m_itemheight * (m_selected-m_top), size().width(), m_itemheight); + inv |= eRect(0, m_itemheight * (oldsel-m_top), size().width(), m_itemheight); + + invalidate(inv); + } +} + +int eListbox::event(int event, void *data, void *data2) +{ + switch (event) + { + case evtPaint: + { + ePtr<eWindowStyle> style; + + assert(m_content); + recalcSize(); // move to event + + getStyle(style); + + if (!m_content) + return 0; + + gPainter &painter = *(gPainter*)data2; + + m_content->cursorSave(); + m_content->cursorMove(m_top - m_selected); + + for (int y = 0, i = 0; i < m_items_per_page; y += m_itemheight, ++i) + { + m_content->paint(painter, *style, ePoint(0, y), m_selected == m_content->cursorGet()); + m_content->cursorMove(+1); + } + + m_content->cursorRestore(); + + return 0; + } + default: + return eWidget::event(event, data, data2); + } +} + +void eListbox::recalcSize() +{ + m_itemheight = 20; + m_content->setSize(eSize(size().width(), m_itemheight)); + m_items_per_page = size().height() / m_itemheight; +} diff --git a/lib/gui/elistbox.h b/lib/gui/elistbox.h new file mode 100644 index 00000000..ac45a332 --- /dev/null +++ b/lib/gui/elistbox.h @@ -0,0 +1,66 @@ +#ifndef __lib_listbox_h +#define __lib_listbox_h + +#include <lib/gui/ewidget.h> +#include <connection.h> + +class iListboxContent: public iObject +{ +public: + /* indices go from 0 to size(). + the end is reached when the cursor is on size(), + i.e. one after the last entry (this mimics + stl behaviour) + + cursors never invalidate - they can become invalid + when stuff is removed. Cursors will always try + to stay on the same data, however when the current + item is removed, this won't work. you'll be notified + anyway. */ + + virtual void cursorHome()=0; + virtual void cursorEnd()=0; + virtual int cursorMove(int count=1)=0; + virtual int cursorValid()=0; + virtual int cursorSet(int n)=0; + virtual int cursorGet()=0; + + virtual void cursorSave()=0; + virtual void cursorRestore()=0; + + virtual int size()=0; + + virtual RESULT connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection)=0; + + // void setOutputDevice ? (for allocating colors, ...) .. requires some work, though + virtual void setSize(const eSize &size)=0; + + /* the following functions always refer to the selected item */ + virtual void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)=0; +}; + +class eListbox: public eWidget +{ +public: + eListbox(eWidget *parent); + void setContent(iListboxContent *content); + + void moveSelection(int how); + enum { + moveUp, + moveDown, + moveTop, + moveEnd + }; +protected: + int event(int event, void *data=0, void *data2=0); + void recalcSize(); +private: + int m_top, m_selected; + int m_itemheight; + int m_items_per_page; + ePtr<iListboxContent> m_content; +}; + + +#endif diff --git a/lib/gui/eslider.cpp b/lib/gui/eslider.cpp index 20b3ab47..665c6c1c 100644 --- a/lib/gui/eslider.cpp +++ b/lib/gui/eslider.cpp @@ -16,7 +16,7 @@ int eSlider::event(int event, void *data, void *data2) getStyle(style); style->paintBackground(painter, ePoint(0, 0), size()); - style->setForegroundStyle(painter); + style->setStyle(painter, eWindowStyle::styleLabel); // TODO - own style painter.fill(m_currently_filled); return 0; diff --git a/lib/gui/ewindowstyle.cpp b/lib/gui/ewindowstyle.cpp index 8599cfd7..64adfb58 100644 --- a/lib/gui/ewindowstyle.cpp +++ b/lib/gui/ewindowstyle.cpp @@ -57,17 +57,43 @@ void eWindowStyleSimple::paintBackground(gPainter &painter, const ePoint &offset painter.clear(); } -void eWindowStyleSimple::setForegroundStyle(gPainter &painter) +void eWindowStyleSimple::setStyle(gPainter &painter, int what) { - painter.setForegroundColor(gColor(0x1F)); + switch (what) + { + case styleLabel: + painter.setForegroundColor(gColor(0x1F)); + break; + case styleListboxSelected: + painter.setForegroundColor(gColor(0x1F)); + painter.setBackgroundColor(gColor(0x1A)); + break; + case styleListboxNormal: + painter.setForegroundColor(gColor(0x1C)); + painter.setBackgroundColor(m_background_color); + break; + } } -void eWindowStyleSimple::drawButtonFrame(gPainter &painter, const eRect &frame) +void eWindowStyleSimple::drawFrame(gPainter &painter, const eRect &frame, int what) { - painter.setForegroundColor(m_border_color_tl); + gColor c1, c2; + switch (what) + { + case frameButton: + c1 = m_border_color_tl; + c2 = m_border_color_br; + break; + case frameListboxEntry: + c1 = m_border_color_br; + c2 = m_border_color_tl; + break; + } + + painter.setForegroundColor(c2); painter.line(frame.topLeft1(), frame.topRight1()); painter.line(frame.topRight1(), frame.bottomRight1()); - painter.setForegroundColor(m_border_color_br); + painter.setForegroundColor(c1); painter.line(frame.bottomRight1(), frame.bottomLeft1()); painter.line(frame.bottomLeft1(), frame.topLeft1()); } diff --git a/lib/gui/ewindowstyle.h b/lib/gui/ewindowstyle.h index d5da5a34..74ff88d5 100644 --- a/lib/gui/ewindowstyle.h +++ b/lib/gui/ewindowstyle.h @@ -13,9 +13,21 @@ public: virtual void handleNewSize(eWindow *wnd, const eSize &size) = 0; virtual void paintWindowDecoration(eWindow *wnd, gPainter &painter, const std::string &title) = 0; virtual void paintBackground(gPainter &painter, const ePoint &offset, const eSize &size) = 0; - virtual void setForegroundStyle(gPainter &painter) = 0; - virtual void drawButtonFrame(gPainter &painter, const eRect &frame) = 0; + virtual void setStyle(gPainter &painter, int what) = 0; + enum { + styleLabel, + styleListboxSelected, + styleListboxNormal + }; + + virtual void drawFrame(gPainter &painter, const eRect &frame, int type) = 0; + + enum { + frameButton, + frameListboxEntry + }; virtual ~eWindowStyle() = 0; + }; class eWindowStyleSimple: public eWindowStyle @@ -31,8 +43,8 @@ public: void handleNewSize(eWindow *wnd, const eSize &size); void paintWindowDecoration(eWindow *wnd, gPainter &painter, const std::string &title); void paintBackground(gPainter &painter, const ePoint &offset, const eSize &size); - void setForegroundStyle(gPainter &painter); - void drawButtonFrame(gPainter &painter, const eRect &frame); + void setStyle(gPainter &painter, int what); + void drawFrame(gPainter &painter, const eRect &frame, int what); }; #endif |
