trunk 20080912
[gitenigma.git] / lib / gui / listbox.cpp
blob68fb6a6d905a3aebdf7d154f7c16ffec31a1f255
1 #include <lib/gui/listbox.h>
2 #include <lib/gui/eprogress.h>
3 #include <lib/gui/numberactions.h>
4 #include <lib/system/econfig.h>
5 #include <lib/gdi/font.h>
7 gFont eListBoxEntryText::font;
8 gFont eListBoxEntryTextStream::font;
10 eListBoxBase::eListBoxBase(eWidget* parent, const eWidget* descr, int takefocus, int item_height, const char *deco )
11 : eDecoWidget(parent, takefocus, deco),
12 removed_height_pixel(0), descr(descr),
13 #ifndef DISABLE_LCD
14 tmpDescr(0),
15 #endif
16 colorActiveB(eSkin::getActive()->queryScheme("listbox.selected.background")),
17 colorActiveF(eSkin::getActive()->queryScheme("listbox.selected.foreground")),
18 movemode(0), MaxEntries(0), flags(0), item_height(item_height),
19 columns(1), in_atomic(0), entries(0), currentPos(-1), top(childs.end()), bottom(childs.end()), current(childs.end())
21 scrollbar = new eProgress(this);
22 scrollbar->setDirection(1);
23 childs.setAutoDelete(false); // machen wir selber
24 addActionMap(&i_cursorActions->map);
25 addActionMap(&i_listActions->map);
26 if ( !colorActiveB )
27 colorActiveB=eSkin::getActive()->queryScheme("global.selected.background");
28 if ( !colorActiveF )
29 colorActiveF=eSkin::getActive()->queryScheme("global.selected.foreground");
31 gColor col = eSkin::getActive()->queryScheme("listbox.normal.background");
32 if (col)
33 backgroundColor=col;
36 gColor col = eSkin::getActive()->queryScheme("listbox.normal.foreground");
37 if (col)
38 foregroundColor=col;
42 eListBoxBase::~eListBoxBase()
44 ePtrList<eListBoxEntry>::iterator it(childs.begin());
45 while (it != childs.end())
47 it->clearLB();
48 delete *it;
49 childs.erase(it++);
53 void eListBoxBase::setFlags(int _flags)
55 flags |= _flags;
56 if (_flags == flagHasShortcuts)
57 addActionMap(&i_shortcutActions->map);
60 void eListBoxBase::removeFlags(int _flags)
62 flags &= ~_flags;
63 if (_flags == flagHasShortcuts)
64 removeActionMap(&i_shortcutActions->map);
67 void eListBoxBase::recalcMaxEntries()
69 // MaxEntries is PER COLUMN
70 int decoheight=0;
71 if (deco_selected && have_focus)
73 MaxEntries = crect_selected.height();
74 decoheight = height() - crect_selected.height();
76 else if (deco)
78 MaxEntries = crect.height();
79 decoheight = height() - crect.height();
81 else
82 MaxEntries = height();
83 int tmp = MaxEntries;
84 MaxEntries /= item_height;
85 /* eDebug("height = %d, MaxEntries = %d, item height = %d",
86 tmp, MaxEntries, item_height);*/
87 // das ist echt mal komischer code hier.. aber funktioniert :)
88 // damit werden listboxen automatisch auf die höhe resized,
89 // die benötigt wird damit alle entrys genau sichtbar sind..
90 // und kein Rand bleibt..
91 if ( tmp - ( MaxEntries*item_height ) > 0 )
93 if ( !removed_height_pixel )
95 removed_height_pixel = height() - ((MaxEntries*item_height) + decoheight);
96 resize( eSize( size.width(), height()-removed_height_pixel ) );
98 else
100 int newMax = (tmp + removed_height_pixel) / item_height;
101 if ( newMax > MaxEntries )
103 removed_height_pixel -= (newMax*item_height) - tmp;
104 resize( eSize( size.width(), newMax*item_height+decoheight ) );
106 else
108 int tmp = height() - ((MaxEntries*item_height) + decoheight);
109 resize( eSize( size.width(), height() - tmp ) );
110 removed_height_pixel += tmp;
114 /* else
115 eDebug("is ok .. do nothing");*/
118 eRect eListBoxBase::getEntryRect(int pos)
120 bool sbar =
121 ( entries > (unsigned int)(MaxEntries*columns) && MaxEntries*columns > 1 );
123 int lme=MaxEntries;
124 // in case we show partial last lines (which only works in single-column),
125 // we increase MaxEntries by one since we don't want the last line
126 // one the next (invisible) column
127 if ( (columns == 1) && (flags & flagShowPartial))
128 ++lme;
129 if ( deco_selected && have_focus )
130 return eRect( ePoint( deco_selected.borderLeft + ( ( pos / lme) * ( crect_selected.width() / columns ) ) , deco_selected.borderTop + ( pos % lme) * item_height ), eSize( (crect_selected.width() / columns) - (sbar?scrollbar->width()+5:columns>1?5:0), item_height ) );
131 else if (deco)
132 return eRect( ePoint( deco.borderLeft + ( ( pos / lme ) * ( crect.width() / columns ) ) , deco.borderTop + ( pos % lme) * item_height ), eSize( (crect.width() / columns) - (sbar?scrollbar->width()+5:columns>1?5:0), item_height ) );
133 else if ( deco_selected )
134 return eRect( ePoint( deco_selected.borderLeft + ( ( pos / lme) * ( crect_selected.width() / columns ) ) , deco_selected.borderTop + ( pos % lme) * item_height ), eSize( (crect_selected.width() / columns) - (sbar?scrollbar->width()+5:columns>1?5:0), item_height ) );
135 else
136 return eRect( ePoint( ( ( pos / lme ) * ( size.width() / columns ) ) , ( pos % lme) * item_height ), eSize( (size.width() / columns) - (sbar?scrollbar->width()+5:columns>1?5:0), item_height ) );
139 void eListBoxBase::setColumns(int col)
141 if (col)
142 columns=col;
145 int eListBoxBase::setProperty(const eString &prop, const eString &value)
147 if (prop == "noPageMovement")
149 if (value == "off")
150 flags &= ~flagNoPageMovement;
151 else
152 flags |= flagNoPageMovement;
154 else if (prop == "noUpDownMovement")
156 if (value == "off")
157 flags &= ~flagNoUpDownMovement;
158 else
159 flags |= flagNoUpDownMovement;
161 else if (prop=="activeForegroundColor")
162 colorActiveF=eSkin::getActive()->queryScheme(value);
163 else if (prop=="activeBackgroundColor")
164 colorActiveB=eSkin::getActive()->queryScheme(value);
165 else if (prop=="showEntryHelp")
166 setFlags( flagShowEntryHelp );
167 else if (prop=="columns")
168 setColumns( value?atoi(value.c_str()):1 );
169 else
170 return eDecoWidget::setProperty(prop, value);
172 return 0;
175 void eListBoxBase::recalcScrollBar()
177 int scrollbarwidth=0;
178 eRect rc;
179 if ( have_focus && deco_selected )
180 rc = crect_selected;
181 else if ( deco )
182 rc = crect;
183 else
184 rc = clientrect;
185 scrollbarwidth=rc.width()/16;
186 if ( scrollbarwidth < 18 )
187 scrollbarwidth=18;
188 if ( scrollbarwidth > 22 )
189 scrollbarwidth=22;
190 scrollbar->move( ePoint(rc.right() - scrollbarwidth, rc.top()) );
191 scrollbar->resize( eSize( scrollbarwidth, (MaxEntries*item_height) ) );
192 scrollbar->hide();
195 void eListBoxBase::recalcClientRect()
197 if (deco)
199 crect.setLeft( deco.borderLeft );
200 crect.setTop( deco.borderTop );
201 crect.setRight( width() - deco.borderRight );
202 crect.setBottom( height() - deco.borderBottom );
204 if (deco_selected)
206 crect_selected.setLeft( deco_selected.borderLeft );
207 crect_selected.setTop( deco_selected.borderTop );
208 crect_selected.setRight( width() - deco_selected.borderRight );
209 crect_selected.setBottom( height() - deco_selected.borderBottom );
211 eWidget::recalcClientRect();
214 int eListBoxBase::eventHandler(const eWidgetEvent &event)
216 switch (event.type)
218 case eWidgetEvent::changedSize:
219 eWidget::eventHandler(event);
220 recalcMaxEntries();
221 recalcScrollBar();
222 init();
223 return 1;
224 break;
225 case eWidgetEvent::evtAction:
226 if ((flags & flagHasShortcuts) && eventHandlerShortcuts(event))
227 return 1;
228 else if ((event.action == &i_listActions->pageup) && !(flags & flagNoPageMovement))
229 moveSelection(dirPageUp);
230 else if ((event.action == &i_listActions->pagedown) && !(flags & flagNoPageMovement))
231 moveSelection(dirPageDown);
232 else if ( entries && current->eventHandler(event) )
233 return 1;
234 else if ((event.action == &i_cursorActions->up) && !(flags & flagNoUpDownMovement) && !(flags&flagLostFocusOnFirst && current == childs.begin()) )
235 moveSelection(dirUp);
236 else if ((event.action == &i_cursorActions->down) && !(flags & flagNoUpDownMovement) && !(flags&flagLostFocusOnLast && current == --childs.end()) )
237 moveSelection(dirDown);
238 else if (event.action == &i_cursorActions->ok)
240 if ( current == childs.end() )
241 /*emit*/ SendSelected(0);
242 else
243 /*emit*/ SendSelected(*current);
245 else if (event.action == &i_cursorActions->cancel && MaxEntries > 1 )
246 /*emit*/ SendSelected(0);
247 else
248 break;
249 return 1;
250 default:
251 break;
253 return eWidget::eventHandler(event);
256 void eListBoxBase::invalidateContent()
258 if ( have_focus && deco_selected )
259 invalidate( crect_selected );
260 else if ( deco )
261 invalidate( crect );
262 else
263 invalidate();
266 int eListBoxBase::newFocus()
268 if (deco && deco_selected)
270 recalcMaxEntries();
271 recalcScrollBar();
273 if (isVisible())
274 invalidate();
276 return 1;
278 return 0;
281 int eListBoxBase::setCurrent(const eListBoxEntry *c, bool sendSelected )
283 /* if (childs.empty() || ((current != childs.end()) && (*current == c))) // no entries or current is equal the entry to search
284 return E_ALLREADY_SELECTED; // do nothing*/
286 if ( !entries )
287 return E_COULDNT_FIND;
289 ePtrList<eListBoxEntry>::iterator item(childs.begin()), it(childs.begin());
291 int cnt=0;
292 for ( ; item != childs.end(); ++item, ++cnt)
293 if ( *item == c )
294 break;
296 if ( item == childs.end() ) // entry not in listbox... do nothing
297 return E_COULDNT_FIND;
299 currentPos=cnt;
301 int newCurPos=-1;
302 int oldCurPos=-1;
303 ePtrList<eListBoxEntry>::iterator oldCur(current);
305 int i = 0;
307 for (it=top; it != bottom; ++it, ++i) // check if entry to set between bottom and top
309 if (it == item)
311 newCurPos=i;
312 current = it;
314 if ( it == oldCur)
315 oldCurPos=i;
318 if (newCurPos != -1) // found on current screen, so redraw only old and new
320 if (isVisible())
322 if (in_atomic)
324 if (atomic_redraw == arNothing)
326 atomic_redraw = arCurrentOld;
327 atomic_old = oldCurPos;
329 if (atomic_redraw == arCurrentOld)
330 atomic_new = newCurPos;
331 }else
333 invalidateEntry(newCurPos);
334 if (oldCurPos != -1)
335 invalidateEntry(oldCurPos);
338 } else // then we start to search from begin
340 bottom = childs.begin();
342 while (newCurPos == -1 && MaxEntries) // MaxEntries is already checked above...
344 if ( bottom != childs.end() )
345 top = bottom; // nächster Durchlauf
347 for (i = 0; (i < (MaxEntries*columns) ) && (bottom != childs.end()); ++bottom, ++i)
349 if (bottom == item)
351 current = bottom; // we have found
352 ++newCurPos;
356 if (isVisible())
358 if (!in_atomic)
359 invalidateContent(); // Draw all
360 else
361 atomic_redraw=arAll;
365 if (!in_atomic)
367 /*emit*/ SendSelChanged(*current);
368 if ( sendSelected )
369 /*emit*/ SendSelected(*current);
370 }else
372 atomic_selchanged=1;
373 if ( sendSelected )
374 atomic_selected=1;
377 return OK;
380 void eListBoxBase::append(eListBoxEntry* entry, bool holdCurrent, bool front)
382 eListBoxEntry* cur = 0;
383 if (holdCurrent)
384 cur = current;
386 if ( front )
387 childs.push_front(entry);
388 else
389 childs.push_back(entry);
390 ++entries;
391 init();
393 if (cur)
394 setCurrent(cur);
397 void eListBoxBase::take(eListBoxEntry* entry, bool holdCurrent)
399 eListBoxEntry *cur = 0;
401 if (holdCurrent && current != entry)
402 cur = current;
404 childs.take(entry);
405 if ( entries != childs.size() )
407 --entries;
408 init();
411 if (cur)
412 setCurrent(cur);
415 void eListBoxBase::clearList()
417 ePtrList<eListBoxEntry>::iterator it(childs.begin());
418 while (entries)
420 it->clearLB();
421 delete *it;
422 childs.erase(it++);
423 --entries;
425 current = top = bottom = childs.end();
426 if (!in_atomic)
428 /*emit*/ SendSelChanged(0);
429 invalidateContent();
430 } else
432 atomic_selected=0;
433 atomic_selchanged=0;
434 atomic_redraw=arAll;
435 atomic_new=0;
436 atomic_old=0;
438 currentPos=-1;
441 eListBoxEntry *eListBoxBase::goNext()
443 moveSelection(dirDown);
444 return current!=childs.end() ? *current : 0;
447 eListBoxEntry* eListBoxBase::goPrev()
449 moveSelection(dirUp);
450 return current!=childs.end() ? *current : 0;
453 void eListBoxBase::redrawWidget(gPainter *target, const eRect &where)
455 // redraw scrollbar only...
456 if ( where.size() == scrollbar->getSize() &&
457 where.topLeft() == scrollbar->getPosition() )
458 return;
460 eRect rc;
462 if (deco_selected && have_focus)
464 deco_selected.drawDecoration(target, ePoint(width(), height()));
465 rc = crect_selected;
467 else if (deco)
469 deco.drawDecoration(target, ePoint(width(), height()));
470 rc = crect;
472 else
473 rc = where;
475 if ( currentPos == -1 )
477 currentPos = 0;
478 ePtrList<eListBoxEntry>::iterator it = childs.begin();
479 for (; it != childs.end() ;++it, ++currentPos )
480 if ( it == current )
481 break;
484 if ( entries > (unsigned int)(MaxEntries*columns) && MaxEntries*columns > 1 )
486 int pages = entries / (MaxEntries*columns);
487 if ( (unsigned int)(pages*MaxEntries*columns) < entries )
488 pages++;
489 int start=(currentPos/(MaxEntries*columns)*MaxEntries*columns*100)/(pages*MaxEntries*columns);
490 int vis=MaxEntries*columns*100/(pages*MaxEntries*columns);
491 if (vis < 3)
492 vis=3;
493 scrollbar->setParams(start,vis);
494 scrollbar->show();
496 else
497 scrollbar->hide();
499 int i=0;
500 for (ePtrList<eListBoxEntry>::iterator entry(top); ((flags & flagShowPartial) || (entry != bottom)) && (entry != childs.end()); ++entry)
502 eRect rect = getEntryRect(i);
503 if ( rc.intersects(rect) )
505 target->clip(rect & rc);
506 if ( entry == current )
508 #ifndef DISABLE_LCD
509 if ( LCDTmp ) // LCDTmp is only valid, when we have the focus
510 LCDTmp->setText( entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 1 ) );
511 else if ( parent->LCDElement && have_focus )
512 parent->LCDElement->setText( entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 1 ) );
513 else
514 #endif
515 entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), ( have_focus ? 1 : ( MaxEntries > 1 ? 2 : 0 ) ) );
517 else
518 entry->redraw(target, rect, colorActiveB, colorActiveF, getBackgroundColor(), getForegroundColor(), 0 /*( have_focus ? 0 : ( MaxEntries > 1 ? 2 : 0 ) )*/ );
519 target->clippop();
521 // special case for "showPartial": as bottom is set to the
522 // last, half visible entry we want to redraw this, too.
523 if (flags & flagShowPartial)
524 if (entry == bottom)
525 break;
527 ++i;
531 void eListBoxBase::gotFocus()
533 #ifndef DISABLE_LCD
534 if (parent && parent->LCDElement) // detect if LCD Avail
535 if (descr)
537 parent->LCDElement->setText("");
538 LCDTmp = new eLabel(parent->LCDElement);
539 LCDTmp->hide();
540 eSize s = parent->LCDElement->getSize();
541 LCDTmp->move(ePoint(0,s.height()/2));
542 LCDTmp->resize(eSize(s.width(), s.height()/2));
543 LCDTmp->show();
544 tmpDescr = new eLabel(parent->LCDElement);
545 tmpDescr->hide();
546 tmpDescr->move(ePoint(0,0));
547 tmpDescr->resize(eSize(s.width(), s.height()/2));
548 tmpDescr->setText( descr->getText() );
549 tmpDescr->show();
551 #endif
552 ++have_focus;
553 if (entries)
555 if ( newFocus() ) // recalced ?
557 ePtrList<eListBoxEntry>::iterator it = current;
558 init();
559 setCurrent(it);
561 else if ( isVisible() )
563 int i=0;
564 for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry)
565 if (entry == current)
566 invalidateEntry(i);
569 if (flags & flagShowEntryHelp)
570 setHelpText( current != childs.end() ? current->getHelpText(): eString(" ")); // eString(_("no description available")));
573 void eListBoxBase::lostFocus()
575 #ifndef DISABLE_LCD
576 if ( descr )
578 delete LCDTmp;
579 LCDTmp=0;
580 delete tmpDescr;
581 tmpDescr=0;
583 #endif
584 --have_focus;
585 if (entries)
586 if ( newFocus() ) //recalced ?
588 ePtrList<eListBoxEntry>::iterator it = current;
589 init();
590 setCurrent(it);
592 else if ( isVisible() )
594 int i = 0;
595 for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry)
596 if (entry == current)
597 invalidateEntry(i);
599 #ifndef DISABLE_LCD
600 if (parent && parent->LCDElement)
601 parent->LCDElement->setText("");
602 #endif
605 void eListBoxBase::invalidateCurrent()
607 int n=0;
608 for (ePtrList<eListBoxEntry>::iterator i(top); i != bottom; ++i, ++n)
609 if ( i == current )
610 invalidate(getEntryRect(n));
613 void eListBoxBase::init()
615 currentPos=entries?0:-1;
616 current = top = bottom = childs.begin();
617 for (int i = 0; i < (MaxEntries*columns); ++i, ++bottom)
618 if (bottom == childs.end() )
619 break;
621 /* when the first item isn't a selectable item, keep scrolling down till we find one */
622 while ( !current->isSelectable() && current != --childs.end())
624 ++current;
625 ++currentPos;
628 if (!in_atomic)
630 invalidateContent();
632 else
634 atomic_redraw=arAll;
638 int eListBoxBase::moveSelection(int dir, bool sendSelected)
640 int direction=0, forceredraw=0;
642 if (!entries)
643 return 0;
645 ePtrList<eListBoxEntry>::iterator oldptr=current, oldtop=top;
647 switch (dir)
649 case dirPageDown:
650 direction=+1;
651 for (int i = 0; i < MaxEntries; ++i)
653 ++currentPos;
654 if (++current == bottom) // unten (rechts) angekommen? page down
656 if (bottom == childs.end()) // einzige ausnahme: unten (rechts) angekommen
658 --currentPos;
659 --current;
660 break;
662 for (int i = 0; i < MaxEntries * columns; ++i)
664 if (bottom != childs.end())
665 ++bottom;
666 if (top != childs.end())
667 ++top;
671 /* when we didn't find a selectable item, keep scrolling down till we find one */
672 while ( !current->isSelectable() && current != --childs.end())
674 ++current;
675 ++currentPos;
677 /* when we couldn't find a selectable item below, find the nearest one above */
678 while ( !current->isSelectable() && current != childs.begin())
680 --current;
681 --currentPos;
683 break;
685 case dirPageUp:
686 direction=-1;
687 for (int i = 0; i < MaxEntries; ++i)
689 if (current == childs.begin())
690 break;
691 --currentPos;
692 if (current-- == top/* && current != childs.begin()*/ ) // oben (links) angekommen? page up
694 for (int i = 0; i < MaxEntries * columns; ++i)
696 if (--top == childs.begin()) // einzige ausnahme: oben (links) angekommen
697 break;
700 // und einmal bottom neuberechnen :)
701 bottom=top;
702 for (int i = 0; i < MaxEntries*columns; ++i)
703 if (bottom != childs.end())
704 ++bottom;
707 /* when we didn't find a selectable item, keep scrolling up till we find one */
708 while ( !current->isSelectable() && current != childs.begin())
710 --current;
711 --currentPos;
713 /* when we couldn't find a selectable item above, find the nearest one below */
714 while ( !current->isSelectable() && current != --childs.end())
716 ++current;
717 ++currentPos;
719 break;
721 case dirUp:
723 bool first=true;
724 while (first || !current->isSelectable() )
726 first=false;
727 if ( current == childs.begin() ) // wrap around?
729 direction=+1;
730 top = bottom = current = childs.end();
731 --current;
732 currentPos=entries-1;
733 int cnt = entries%(MaxEntries*columns);
734 for (int i = 0; i < (cnt?cnt:MaxEntries*columns); ++i, --top)
735 if (top == childs.begin())
736 break;
738 else
740 direction=-1;
741 --currentPos;
742 if (current-- == top) // new top must set
744 for (int i = 0; i < MaxEntries*columns; ++i, --top)
745 if (top == childs.begin())
746 break;
747 bottom=top;
748 for (int i = 0; i < MaxEntries*columns; ++i, ++bottom)
749 if (bottom == childs.end())
750 break;
755 break;
757 case dirDown:
759 bool first=true;
760 while (first || !current->isSelectable() )
762 first=false;
763 if ( current == --ePtrList<eListBoxEntry>::iterator(childs.end()) ) // wrap around?
765 direction=-1;
766 currentPos=0;
767 top = current = bottom = childs.begin(); // goto first
768 for (int i = 0; i < MaxEntries * columns; ++i, ++bottom)
769 if ( bottom == childs.end() )
770 break;
772 else
774 direction=+1;
775 ++currentPos;
776 if (++current == bottom) // ++current ??
778 for (int i = 0; i<MaxEntries * columns; ++i)
780 if (bottom != childs.end() )
781 ++bottom;
782 if (top != childs.end() )
783 ++top;
788 break;
790 case dirFirst:
791 direction=-1;
792 currentPos=0;
793 top = current = bottom = childs.begin(); // goto first;
794 for (int i = 0; i < MaxEntries * columns; ++i, ++bottom)
795 if ( bottom == childs.end() )
796 break;
797 /* when the first item isn't a selectable item, keep scrolling down till we find one */
798 while ( !current->isSelectable() && current != --childs.end())
800 ++current;
801 ++currentPos;
803 break;
804 case dirLast:
806 direction=1;
807 top = bottom = current = childs.end();
808 --current;
809 currentPos=entries-1;
810 int cnt = entries%(MaxEntries*columns);
811 for (int i = 0; i < (cnt?cnt:MaxEntries*columns); ++i, --top)
812 if (top == childs.begin())
813 break;
814 /* when the last item isn't a selectable item, keep scrolling up till we find one */
815 while ( !current->isSelectable() && current != childs.begin())
817 --current;
818 --currentPos;
820 break;
822 default:
823 return 0;
826 if (current != oldptr) // current has changed
828 if (movemode)
830 // feel free to rewrite using stl::copy[_backward], but i didn't succeed.
831 std::list<eListBoxEntry*>::iterator o=oldptr,
832 c=current,
833 curi=current,
834 oldi=oldptr;
835 int count=0;
837 eListBoxEntry* old=*o;
839 if (direction > 0)
841 ++o;
842 ++c;
843 while (o != c)
845 *oldi++=*o++;
846 ++count;
848 } else
850 while (o != curi)
852 *oldi--=*--o;
853 ++count;
857 if (count > 1)
858 forceredraw=1;
860 *curi=old;
864 if (flags & flagShowEntryHelp)
865 setHelpText( current != childs.end() ? current->getHelpText():eString(_("no description available")));
867 if (!in_atomic)
869 /*emit*/ SendSelChanged(*current);
870 if ( sendSelected )
871 /*emit*/ SendSelected(*current);
873 else
875 atomic_selchanged=1;
876 if ( sendSelected )
877 atomic_selected=1;
880 if (isVisible())
882 if ((oldtop != top) || forceredraw)
884 if (in_atomic)
885 atomic_redraw=arAll;
886 else
887 invalidateContent();
888 } else if ( current != oldptr)
890 int i=0;
891 int old=-1, cur=-1;
893 for (ePtrList<eListBoxEntry>::iterator entry(top); entry != bottom; ++i, ++entry)
894 if ( entry == oldptr)
895 old=i;
896 else if ( entry == current )
897 cur=i;
899 if (in_atomic)
901 if (atomic_redraw == arNothing)
903 atomic_old=old;
904 atomic_redraw = arCurrentOld;
906 if (atomic_redraw == arCurrentOld)
907 atomic_new=cur;
908 } else
910 if (old != -1)
911 invalidateEntry(old);
912 if (cur != -1)
913 invalidateEntry(cur);
917 return 1;
920 void eListBoxBase::setActiveColor(gColor back, gColor front)
922 if (back)
923 colorActiveB=back;
924 if (front)
925 colorActiveF=front;
927 if ((back || front) && current != childs.end())
929 int i = 0;
930 for (ePtrList<eListBoxEntry>::iterator it(top); it != bottom; ++i, ++it)
932 if (it == current)
934 invalidateEntry(i);
935 break;
941 void eListBoxBase::beginAtomic()
943 if (!in_atomic++)
945 atomic_redraw=arNothing;
946 atomic_selchanged=0;
947 atomic_selected=0;
948 atomic_new=-1;
952 void eListBoxBase::endAtomic()
954 if (!--in_atomic)
956 if (atomic_redraw == arAll)
957 invalidateContent();
958 else if (atomic_redraw == arCurrentOld)
960 if (atomic_new != -1)
961 invalidateEntry(atomic_new);
962 if (atomic_old != -1)
963 invalidateEntry(atomic_old);
965 if (atomic_selchanged)
966 if (!entries)
967 /*emit*/ SendSelChanged(0);
968 else
969 /*emit*/ SendSelChanged(*current);
971 if (atomic_selected)
972 if (!entries)
973 /*emit*/ SendSelected(0);
974 else
975 /*emit*/ SendSelected(*current);
979 void eListBoxBase::sort()
981 eListBoxEntry* cur = current;
982 childs.sort();
984 init();
986 if (cur)
987 setCurrent(cur);
990 int eListBoxBase::getShortcut(eListBoxEntry* e)
992 int i = 0;
993 for (ePtrList<eListBoxEntry>::iterator it(childs.begin());
994 it != childs.end(); ++it )
996 if ( it->isSelectable()&2)
998 i++;
999 if ( it == e )
1000 return i;
1003 return -1;
1006 int eListBoxBase::eventHandlerShortcuts(const eWidgetEvent &event)
1008 int num=-1;
1009 int ColorShortcutsFirst = (getFlags() & flagColorShortcutsFirst ? 1 : 0);
1011 switch (event.type)
1013 case eWidgetEvent::evtAction:
1014 if (event.action == &i_shortcutActions->number0)
1015 num=9 + ColorShortcutsFirst*4;
1016 else if (event.action == &i_shortcutActions->number1)
1017 num=0 + ColorShortcutsFirst*4;
1018 else if (event.action == &i_shortcutActions->number2)
1019 num=1 + ColorShortcutsFirst*4;
1020 else if (event.action == &i_shortcutActions->number3)
1021 num=2 + ColorShortcutsFirst*4;
1022 else if (event.action == &i_shortcutActions->number4)
1023 num=3 + ColorShortcutsFirst*4;
1024 else if (event.action == &i_shortcutActions->number5)
1025 num=4 + ColorShortcutsFirst*4;
1026 else if (event.action == &i_shortcutActions->number6)
1027 num=5 + ColorShortcutsFirst*4;
1028 else if (event.action == &i_shortcutActions->number7)
1029 num=6 + ColorShortcutsFirst*4;
1030 else if (event.action == &i_shortcutActions->number8)
1031 num=7 + ColorShortcutsFirst*4;
1032 else if (event.action == &i_shortcutActions->number9)
1033 num=8 + ColorShortcutsFirst*4;
1034 else if (event.action == &i_shortcutActions->red)
1035 num=10 - ColorShortcutsFirst*10;
1036 else if (event.action == &i_shortcutActions->green)
1037 num=11 - ColorShortcutsFirst*10;
1038 else if (event.action == &i_shortcutActions->yellow)
1039 num=12 - ColorShortcutsFirst*10;
1040 else if (event.action == &i_shortcutActions->blue)
1041 num=13 - ColorShortcutsFirst*10;
1042 else
1043 break;
1044 if (num != -1)
1046 for (ePtrList<eListBoxEntry>::iterator i(childs.begin()); i!=childs.end(); ++i)
1047 if (i->isSelectable()&2 && !num--)
1049 SendSelected(i);
1050 return 1;
1053 default:
1054 break;
1056 return 0;
1059 eListBoxBaseExt::eListBoxBaseExt(eWidget* parent, const eWidget* descr, int takefocus, int item_height, const char *deco)
1060 :eListBoxBase(parent, descr, takefocus, item_height, deco), browseTimer(eApp)
1062 CONNECT(browseTimer.timeout, eListBoxBaseExt::browseTimeout);
1063 addActionMap(&i_numberActions->map);
1066 void eListBoxBaseExt::gotFocus()
1068 eListBoxBase::gotFocus();
1069 eRCInput::getInstance()->setKeyboardMode(eRCInput::kmAscii);
1072 int eListBoxBaseExt::eventHandler(const eWidgetEvent &event)
1074 switch (event.type)
1076 case eWidgetEvent::evtAction:
1077 if (event.action == &i_cursorActions->ok)
1079 browseText="";
1080 browseHistory.clear();
1081 return eListBoxBase::eventHandler(event);
1083 else if (event.action == &i_numberActions->keyBackspace)
1085 if ( browseText )
1086 browseText.erase(browseText.length()-1,1);
1087 if ( browseHistory.size() )
1089 setCurrent(browseHistory.front(),false);
1090 browseHistory.pop_front();
1092 browseTimer.start(2*1000,true);
1094 else if (event.action == &i_cursorActions->down && browseTimer.isActive())
1096 const char *browseBuf = browseText.c_str();
1097 int len = browseText.length();
1098 ePtrList<eListBoxEntry>::iterator it(current);
1099 ++it;
1100 for (;it != childs.end(); ++it )
1102 if ( !strncasecmp(it->getText().c_str(), browseBuf, len) )
1104 if ( it != current )
1106 setCurrent(*it,false);
1107 browseTimer.start(2*1000,true);
1109 return 1;
1112 it=childs.begin();
1113 for (;it != childs.end(); ++it)
1115 if ( !strncasecmp(it->getText().c_str(), browseBuf, len) )
1117 if ( it != current )
1119 setCurrent(*it,false);
1120 browseTimer.start(2*1000,true);
1122 return 1;
1126 else if (event.action == &i_cursorActions->up && browseTimer.isActive() )
1128 const char *browseBuf = browseText.c_str();
1129 int len = browseText.length();
1130 ePtrList<eListBoxEntry>::reverse_iterator it((ePtrList<eListBoxEntry>::reverse_iterator&)current);
1131 for (;it != childs.rend(); ++it )
1133 if ( !strncasecmp(it->getText().c_str(), browseBuf, len) )
1135 if ( it != current )
1137 setCurrent(*it,false);
1138 browseTimer.start(2*1000,true);
1140 return 1;
1143 it=childs.rbegin();
1144 for (;it != childs.rend(); ++it )
1146 if ( !strncasecmp(it->getText().c_str(), browseBuf, len) )
1148 if ( it != current )
1150 setCurrent(*it,false);
1151 browseTimer.start(2*1000,true);
1153 return 1;
1157 else
1158 break;
1159 return 1;
1160 default:
1161 break;
1163 return eListBoxBase::eventHandler(event);
1166 int eListBoxBaseExt::keyDown(int key)
1168 if (key >= KEY_ASCII)
1170 browseTimer.start(2*1000,true);
1171 // TODO convert browseText to utf8 !!
1172 browseText+=(char)key;
1173 const char *browseBuf = browseText.c_str();
1174 int len = browseText.length();
1175 for (ePtrList<eListBoxEntry>::iterator it(childs.begin());
1176 it != childs.end(); ++it )
1178 if ( !strncasecmp(it->getText().c_str(), browseBuf, len) )
1180 if ( it != current )
1182 browseHistory.push_front(current);
1183 setCurrent(*it,false);
1185 return 1;
1188 browseText.erase(len-1,1);
1190 return 0;
1193 void eListBoxBaseExt::clearList()
1195 eListBoxBase::clearList();
1196 browseHistory.clear();
1199 void eListBoxBaseExt::lostFocus()
1201 eListBoxBase::lostFocus();
1202 eRCInput::getInstance()->setKeyboardMode(eRCInput::kmNone);
1203 browseText="";
1204 browseHistory.clear();
1207 void eListBoxEntry::drawEntryBorder(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF )
1209 rc->setForegroundColor(coActiveB);
1210 rc->line( ePoint(rect.left(), rect.bottom()-1), ePoint(rect.right()-1, rect.bottom()-1) );
1211 rc->line( ePoint(rect.left(), rect.top()), ePoint(rect.right()-1, rect.top()) );
1212 rc->line( ePoint(rect.left(), rect.top()), ePoint(rect.left(), rect.bottom()-1) );
1213 rc->line( ePoint(rect.right()-1, rect.top()), ePoint(rect.right()-1, rect.bottom()-1) );
1214 rc->line( ePoint(rect.left()+1, rect.bottom()-2), ePoint(rect.right()-2, rect.bottom()-2) );
1215 rc->line( ePoint(rect.left()+1, rect.top()+1), ePoint(rect.right()-2, rect.top()+1) );
1216 rc->line( ePoint(rect.left()+1, rect.top()+2), ePoint(rect.left()+1, rect.bottom()-3) );
1217 rc->line( ePoint(rect.right()-2, rect.top()+2), ePoint(rect.right()-2, rect.bottom()-3) );
1218 rc->line( ePoint(rect.left()+2, rect.bottom()-3), ePoint(rect.right()-3, rect.bottom()-3) );
1219 rc->line( ePoint(rect.left()+2, rect.top()+2), ePoint(rect.right()-3, rect.top()+2) );
1220 rc->line( ePoint(rect.left()+2, rect.top()+3), ePoint(rect.left()+2, rect.bottom()-4) );
1221 rc->line( ePoint(rect.right()-3, rect.top()+3), ePoint(rect.right()-3, rect.bottom()-4) );
1224 void eListBoxEntry::drawEntryRect(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state )
1226 if ( (coNormalB != -1 && !state) || (state && coActiveB != -1) )
1228 rc->setForegroundColor(state?coActiveB:coNormalB);
1229 rc->fill(rect);
1230 rc->setBackgroundColor(state?coActiveB:coNormalB);
1232 else
1234 eWidget *w=listbox->getNonTransparentBackground();
1235 rc->setForegroundColor(w->getBackgroundColor());
1236 rc->fill(rect);
1237 rc->setBackgroundColor(w->getBackgroundColor());
1239 rc->setForegroundColor(state?coActiveF:coNormalF);
1242 eListBoxEntryText::~eListBoxEntryText()
1244 if (para)
1246 para->destroy();
1247 para = 0;
1251 int eListBoxEntryText::getEntryHeight()
1253 if ( !font.pointSize)
1254 font = eSkin::getActive()->queryFont("eListBox.EntryText.normal");
1256 return calcFontHeight( font ) + 4;
1259 int eListBoxEntryTextStream::getEntryHeight()
1261 if ( !font.pointSize)
1262 font = eSkin::getActive()->queryFont("eListBox.EntryText.normal");
1264 return calcFontHeight( font ) + 4;
1267 int calcFontHeight( const gFont& font)
1269 eTextPara *test;
1270 test = new eTextPara( eRect(0,0,100,50) );
1271 test->setFont( font );
1272 test->renderString("Mjdyl");
1273 int i = test->getBoundBox().height();
1274 test->destroy();
1275 return i;
1278 const eString& eListBoxEntryText::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state)
1280 bool b;
1282 if ( (b = (state == 2)) )
1283 state = 0;
1285 drawEntryRect( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF, state );
1287 int lft = rect.left();
1288 if (listbox->getFlags() & eListBoxBase::flagHasShortcuts)
1290 int hideshortcuts=0;
1291 eConfig::getInstance()->getKey("/ezap/osd/hideshortcuts", hideshortcuts);
1292 if (!hideshortcuts)
1294 int shortcut = listbox->getShortcut(this);
1295 if (listbox->getFlags() & eListBoxBase::flagColorShortcutsFirst)
1297 if (shortcut < 5)
1298 shortcut += 10;
1299 else if (shortcut < 15)
1300 shortcut -= 4;
1303 eString strShortcut;
1304 switch (shortcut)
1306 case 10: shortcut = 0;
1307 case 1:
1308 case 2:
1309 case 3:
1310 case 4:
1311 case 5:
1312 case 6:
1313 case 7:
1314 case 8:
1315 case 9:
1316 strShortcut = eString().sprintf("shortcut.%d",shortcut);
1317 break;
1318 case 11:
1319 strShortcut = eString().sprintf("shortcut.red");
1320 break;
1321 case 12:
1322 strShortcut = eString().sprintf("shortcut.green");
1323 break;
1324 case 13:
1325 strShortcut = eString().sprintf("shortcut.yellow");
1326 break;
1327 case 14:
1328 strShortcut = eString().sprintf("shortcut.blue");
1329 break;
1330 default:
1331 shortcut=-1;
1333 if (shortcut >= 0)
1336 gPixmap* pm = eSkin::getActive()->queryImage(strShortcut);
1337 eRect left = rect;
1338 lft = pm->x + 10;
1339 left.setRight( lft );
1340 left.setLeft(rect.left()+5);
1341 rc->clip(left);
1343 eSize psize = pm->getSize(),
1344 esize = rect.size();
1346 int yOffs = rect.top()+((esize.height() - psize.height()) / 2);
1348 rc->blit(*pm, ePoint(left.left(), yOffs), left, gPixmap::blitAlphaTest );
1350 rc->clippop();
1354 if (!para)
1356 para = new eTextPara( eRect( 0, 0, rect.width()-lft, rect.height() ) );
1357 para->setFont( font );
1358 para->renderString(text);
1359 para->realign(align);
1360 // yOffs = ((rect.height() - para->getBoundBox().height()) / 2 + 0) - para->getBoundBox().top() ;
1361 yOffs=0;
1363 rc->renderPara(*para, ePoint( lft, rect.top()+yOffs ) );
1365 if (b)
1366 drawEntryBorder( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF );
1368 return text;
1371 const eString &eListBoxEntryTextStream::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state)
1373 rc->setFont( font );
1375 drawEntryRect( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF, state );
1377 rc->setForegroundColor(state?coActiveF:coNormalF);
1378 rc->renderText(rect, text.str());
1380 static eString ret;
1381 return ret = text.str();
1384 void eListBoxEntryText::SetText(const eString& txt)
1386 if(para){
1387 para->destroy();
1388 para=0;
1390 text=txt;
1393 const eString& eListBoxSeparator::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state )
1395 int x = 0;
1396 if ( pm )
1398 rc->clip(rect);
1399 eSize psize = pm->getSize(),
1400 esize = rect.size();
1401 int yOffs = rect.top()+((esize.height() - psize.height()) / 2);
1404 rc->blit(*pm, ePoint(x, yOffs), eRect(x, yOffs, psize.width(), psize.height()), alphatest?gPixmap::blitAlphaTest:0 );
1405 x+=distance;
1406 x+=psize.width();
1408 while (x<esize.width());
1409 rc->clippop();
1411 static eString ret="separator";
1412 return ret;
1415 // deprecated...
1416 const eString& eListBoxEntrySeparator::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state )
1418 int x = 0;
1419 if ( pm )
1421 rc->clip(rect);
1422 eSize psize = pm->getSize(),
1423 esize = rect.size();
1424 int yOffs = rect.top()+((esize.height() - psize.height()) / 2);
1427 rc->blit(*pm, ePoint(x, yOffs), eRect(x, yOffs, psize.width(), psize.height()), alphatest?gPixmap::blitAlphaTest:0 );
1428 x+=distance;
1429 x+=psize.width();
1431 while (x<esize.width());
1432 rc->clippop();
1434 static eString ret="separator";
1435 return ret;
1438 eListBoxEntryCheck::eListBoxEntryCheck( eListBox<eListBoxEntryMenu> *lb, const char* text, const char* regkey, const eString& hlptxt )
1439 :eListBoxEntryMenu(lb, text, hlptxt, 0 )
1440 ,pm(eSkin::getActive()->queryImage("eListBoxEntryCheck"))
1441 ,regKey(regkey), checked(0)
1443 selectable=1;
1444 if ( regKey )
1446 if ( eConfig::getInstance()->getKey( regKey.c_str(), checked ) )
1447 eConfig::getInstance()->setKey( regKey.c_str(), checked );
1451 void eListBoxEntryCheck::LBSelected(eListBoxEntry* t)
1453 if (t == this)
1455 checked^=1;
1456 eConfig::getInstance()->setKey( regKey.c_str(), checked );
1457 listbox->invalidateCurrent();
1458 /* emit */ selected((bool)checked);
1462 const eString& eListBoxEntryCheck::redraw(gPainter *rc, const eRect& rect, gColor coActiveB, gColor coActiveF, gColor coNormalB, gColor coNormalF, int state )
1464 bool b;
1466 if ( (b = (state == 2)) )
1467 state = 0;
1469 eListBoxEntryText::redraw( rc, rect, coActiveB, coActiveF, coNormalB, coNormalF, state );
1471 if ( pm && checked )
1473 eRect right = rect;
1474 right.setLeft( rect.right() - (pm->x + 10) );
1475 rc->clip(right);
1477 eSize psize = pm->getSize(),
1478 esize = rect.size();
1480 int yOffs = rect.top()+((esize.height() - psize.height()) / 2);
1482 rc->blit(*pm, ePoint(right.left(), yOffs), right, gPixmap::blitAlphaTest );
1484 rc->clippop();
1487 return text;
1490 eListBoxEntryMulti::eListBoxEntryMulti( eListBox<eListBoxEntryMenu> *lb, const char *hlptext )
1491 :eListBoxEntryMenu( lb, NULL, hlptext, (int)eTextPara::dirCenter ),
1492 cur(entrys.end())
1494 selectable=1;
1497 void eListBoxEntryMulti::add( const char *text, int key )
1499 entrys.push_back( std::pair< int, eString>(key,text) );
1502 void eListBoxEntryMulti::add( const eString &text, int key )
1504 entrys.push_back( std::pair< int, eString>(key,text) );
1507 void eListBoxEntryMulti::setCurrent(int key)
1509 for ( std::list< std::pair< int, eString > >::iterator it(entrys.begin())
1510 ;it != entrys.end(); ++it )
1512 if ( it->first == key )
1514 cur=it;
1515 text = cur->second;
1516 this->key = (void*) cur->first;
1517 if ( para )
1519 para->destroy();
1520 para=0;
1522 listbox->invalidateCurrent();
1523 listbox->selchanged(this);
1524 break;
1529 int eListBoxEntryMulti::eventHandler( const eWidgetEvent &e )
1531 switch(e.type)
1533 case eWidgetEvent::evtAction:
1534 if ( e.action == &i_listActions->pageup )
1536 std::list< std::pair< int, eString > >::iterator it(cur);
1537 --it;
1538 if ( it != entrys.end() )
1540 --cur;
1541 text = cur->second;
1542 key = (void*) cur->first;
1543 if ( para )
1545 para->destroy();
1546 para=0;
1547 listbox->invalidateCurrent();
1548 listbox->selchanged(this);
1551 return 1;
1553 else if ( e.action == &i_listActions->pagedown )
1555 std::list< std::pair< int, eString > >::iterator it(cur);
1556 ++it;
1557 if ( it != entrys.end() )
1559 ++cur;
1560 text = cur->second;
1561 key = (void*) cur->first;
1562 if ( para )
1564 para->destroy();
1565 para=0;
1566 listbox->invalidateCurrent();
1567 listbox->selchanged(this);
1570 return 1;
1572 default:
1573 break;
1575 return 0;