/************************************************************************** kdisptext.cpp - The widget that displays the karaoke/lyrics text Copyright (C) 1997,98 Antonio Larrosa Jimenez This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Send comments and bug fixes to larrosa@kde.org or to Antonio Larrosa, Rio Arnoya, 10 5B, 29006 Malaga, Spain ***************************************************************************/ #include "kdisptext.h" #include #include #include #include #include #include #include #include #include #include #include "version.h" #define NUMPREVLINES 2 //#define DRAW_BOUNDING_RECTS KDisplayText::KDisplayText(TQWidget *parent,const char *name) : TQScrollView(parent,name) { first_line_[0]=first_line_[1]=NULL; linked_list_[0]=linked_list_[1]=NULL; cursor_line_[0]=cursor_line_[1]=NULL; cursor_[0]=cursor_[1]=NULL; nlines_[0]=nlines_[1]=0; linked_list=NULL; cursor_line=NULL; first_line=NULL; cursor=NULL; nlines=0; lyrics_codec=TDEGlobal::locale()->codecForEncoding(); viewport()->setBackgroundColor(TQColor (110,110,110)); // setBackgroundMode(NoBackground); TDEConfig *kcfg=TDEGlobal::instance()->config(); kcfg->setGroup("KMid"); typeoftextevents=kcfg->readNumEntry("TypeOfTextEvents",1); TQFont *qtextfontdefault=new TQFont(TDEGlobalSettings::fixedFont().family(),22); qtextfont=new TQFont(kcfg->readFontEntry("KaraokeFont",qtextfontdefault)); delete qtextfontdefault; qfmetr=new TQFontMetrics(*qtextfont); nvisiblelines=height()/qfmetr->lineSpacing(); autoscrollv=0; } KDisplayText::~KDisplayText() { RemoveLinkedList(); } /*void KDisplayText::PreDestroyer(void) { delete qfmetr; delete qtextfont; } */ void KDisplayText::RemoveLine(kdispt_line *tmpl) { kdispt_ev *tmpe; while (tmpl->ev!=NULL) { tmpe=tmpl->ev; tmpl->ev=tmpe->next; // delete tmpe->spev; Remember that the Special Events that this pointer // points to is the same that the Player object has instantiated delete tmpe; } } void KDisplayText::RemoveLinkedList(void) { cursor=NULL; cursor_line=NULL; first_line=NULL; linked_list=NULL; nlines=0; nlines_[0]=nlines_[1]=0; first_line_[0]=first_line_[1]=NULL; cursor_line_[0]=cursor_line_[1]=NULL; cursor_[0]=cursor_[1]=NULL; kdispt_line *tmpl; for (int i=0;i<2;i++) { while (linked_list_[i]!=NULL) { RemoveLine(linked_list_[i]); tmpl=linked_list_[i]; linked_list_[i]=linked_list_[i]->next; delete tmpl; } } } void KDisplayText::ClearEv(bool totally) { RemoveLinkedList(); if (totally) { this->killTimers(); autoscrollv=0; resizeContents(0,0); viewport()->repaint(TRUE); } } int KDisplayText::IsLineFeed(char c,int type) { switch (type) { case (1) : if (/*(c==0)||*/(c=='\\')||(c=='/')||(c=='@')) return 1;break; case (5) : if (/*(c==0)||*/(c==10)||(c==13)) return 1;break; default : if ((c==0)||(c==10)||(c==13)||(c=='\\')||(c=='/')||(c=='@')) return 1;break; } return 0; } void KDisplayText::AddEv(SpecialEvent *ev) { if ((ev->type==1) || (ev->type==5)) { int idx=(ev->type==1)? 0 : 1; if (linked_list_[idx]==NULL) { linked_list_[idx]=new kdispt_line; linked_list_[idx]->next=NULL; linked_list_[idx]->num=1; linked_list_[idx]->ev=new kdispt_ev; cursor_line_[idx]=linked_list_[idx]; cursor_[idx]=cursor_line_[idx]->ev; cursor_[idx]->spev=ev; cursor_[idx]->next=NULL; first_line_[idx]=linked_list_[idx]; first_line=first_line_[idx]; nlines_[idx]=1; } else { if (IsLineFeed(ev->text[0],ev->type)) { nlines_[idx]++; cursor_line_[idx]->next=new kdispt_line; cursor_line_[idx]=cursor_line_[idx]->next; cursor_line_[idx]->num=nlines_[idx]; cursor_line_[idx]->ev=new kdispt_ev; cursor_line_[idx]->next=NULL; cursor_[idx]=cursor_line_[idx]->ev; } else { cursor_[idx]->next=new kdispt_ev; cursor_[idx]=cursor_[idx]->next; } cursor_[idx]->spev=ev; cursor_[idx]->next=NULL; } } } void KDisplayText::calculatePositions(void) { int typeoftextevents=1; int fin=0; kdispt_line *tmpl; kdispt_ev *tmp; int tmpx=0; int tmpy=0; int tmpw=0; int maxx=0; nlines=nlines_[(typeoftextevents==1)? 0:1]; int lineSpacing=qfmetr->lineSpacing(); int descent=qfmetr->descent(); while (!fin) { tmpl=linked_list_[(typeoftextevents==1)?0:1]; tmpy=lineSpacing; maxx=0; while (tmpl!=NULL) { tmp=tmpl->ev; tmpx=5; while (tmp!=NULL) { if (tmp->spev->type==typeoftextevents) { if (IsLineFeed(tmp->spev->text[0],typeoftextevents)) { tmpy+=lineSpacing; tmpx=5; tmp->xpos=tmpx; if (tmp->spev->text[0]!=0) tmpw=qfmetr->width(lyrics_codec->toUnicode(&tmp->spev->text[1])); else tmpw=0; tmp->r=qfmetr->boundingRect(lyrics_codec->toUnicode(&tmp->spev->text[1])); } else { tmp->xpos=tmpx; tmpw=qfmetr->width(lyrics_codec->toUnicode(tmp->spev->text)); tmp->r=qfmetr->boundingRect(lyrics_codec->toUnicode(tmp->spev->text)); } // We add 5 pixels above, below and to the right because of a // problem with latest released Xft tmp->r.moveBy(tmpx,tmpy-tmp->r.height()-tmp->r.y()-5); tmp->r.setHeight(tmp->r.height()+descent+10); tmp->r.setWidth(tmp->r.width()+5); tmpx+=tmpw; if (tmpx>maxx) maxx=tmpx; } tmp=tmp->next; } tmpl->ypos=tmpl->num*lineSpacing; tmpy=tmpl->ypos; tmpl=tmpl->next; } maxX[(typeoftextevents==1)?0:1]=maxx+10; maxY[(typeoftextevents==1)?0:1]= nlines_[(typeoftextevents==1)?0:1]*lineSpacing+descent+10; if (typeoftextevents==1) typeoftextevents=5; else fin=1; } } kdispt_line *KDisplayText::searchYOffset(int y, kdispt_line *start) { kdispt_line *t=start; while (t!=NULL) { // if (t->ypos+qfmetr->descent()>y) return start; if (t->ypos+qfmetr->descent()+20>y) return start; start=t; t=t->next; }; return start; } void KDisplayText::drawContents(TQPainter *p, int /*clipx*/, int clipy, int /*clipw*/, int cliph) { p->setFont(*qtextfont); if (linked_list==NULL) return; int i=0; p->setPen(yellow); int colorplayed=1; if (cursor==NULL) colorplayed=0; // Thus, the program doesn't change the color kdispt_line *tmpl=linked_list; kdispt_ev *tmp; #ifdef KDISPTEXTDEBUG printf("events displayed %d\n",typeoftextevents); #endif tmpl=searchYOffset(clipy,linked_list); int nlinestodraw=1; kdispt_line *t=tmpl; while ((t!=NULL)&&(t->ypos+qfmetr->descent()next; } i=0; while ((iev; while ((tmp!=NULL)&&(tmp->spev->type!=typeoftextevents)) tmp=tmp->next; while (tmp!=NULL) { if ( colorplayed && // (tmp->spev->absmilliseconds>=cursor->spev->absmilliseconds)) (tmp->spev->id>=cursor->spev->id)) { p->setPen(black); colorplayed=0; } if (IsLineFeed(tmp->spev->text[0],tmp->spev->type)) p->drawText(tmp->xpos,tmpl->ypos,lyrics_codec->toUnicode(&tmp->spev->text[1])); else p->drawText(tmp->xpos,tmpl->ypos,lyrics_codec->toUnicode(tmp->spev->text)); #ifdef DRAW_BOUNDING_RECTS p->setPen(red); p->drawRect(tmp->r); p->setPen((colorplayed)?yellow:black); #endif tmp=tmp->next; while ((tmp!=NULL)&&(tmp->spev->type!=typeoftextevents)) tmp=tmp->next; } i++; tmpl=tmpl->next; } } void KDisplayText::resizeEvent(TQResizeEvent *e) { TQScrollView::resizeEvent(e); nvisiblelines=visibleHeight()/qfmetr->lineSpacing(); if ( (nlines>nvisiblelines) || (nvisiblelines==0) ) resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]); else resizeContents(0,0); } void KDisplayText::CursorToHome(void) { /* TDEConfig *kcfg=TDEGlobal::instance()->config(); kcfg->setGroup("KMid"); typeoftextevents=kcfg->readNumEntry("TypeOfTextEvents",1); */ linked_list=linked_list_[(typeoftextevents==1)? 0:1]; nlines=nlines_[(typeoftextevents==1)? 0:1]; cursor_line_[0]=linked_list_[0]; first_line_[0]=cursor_line_[0]; if (cursor_line_[0]!=NULL) cursor_[0]=cursor_line_[0]->ev; cursor_line_[1]=linked_list_[1]; first_line_[1]=cursor_line_[1]; if (cursor_line_[1]!=NULL) cursor_[1]=cursor_line_[1]->ev; if (linked_list==NULL) { cursor_line=NULL; cursor=NULL; first_line=NULL; } else { cursor_line=linked_list; cursor=cursor_line->ev; first_line=linked_list; } nvisiblelines=visibleHeight()/qfmetr->lineSpacing(); if (nlines>nvisiblelines) resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]); else resizeContents(0,0); setContentsPos(0,0); viewport()->repaint(true); } void KDisplayText::PaintIn(int type) { bool paint=false; if (type!=typeoftextevents) { int idx=(type==1)?0:1; if (cursor_[idx]==NULL) return; cursor_[idx]=cursor_[idx]->next; while ((cursor_[idx]==NULL)&&(cursor_line_[idx]!=NULL)) { cursor_line_[idx]=cursor_line_[idx]->next; if (cursor_line_[idx]!=NULL) { cursor_[idx]=cursor_line_[idx]->ev; if ((cursor_line_[idx]->num>first_line_[idx]->num+NUMPREVLINES) &&(cursor_line_[idx]->numnum+nvisiblelines+1)) if ((first_line_[idx]!=NULL)&&(first_line_[idx]->num+nvisiblelines<=nlines_[idx])) first_line_[idx]=first_line_[idx]->next; } } return; } if ((cursor==NULL)||(cursor_line==NULL)) { printf("KDispT : cursor == NULL !!!\n"); return; } kdispt_ev *tmp=cursor; if (cursor->spev->type==typeoftextevents) { // int x,y; // contentsToViewport(cursor->xpos,cursor_line->ypos,x,y); cursor=cursor->next; paint=true; } else cursor=cursor->next; while ((cursor==NULL)&&(cursor_line!=NULL)) { cursor_line=cursor_line->next; if (cursor_line!=NULL) { cursor=cursor_line->ev; if ((cursor_line->ypos>contentsY()+(visibleHeight()*5/8))&& (cursor_line->yposlineSpacing(); if (b) startTimer(100); else { this->killTimers(); startTimer(100/(autoscrollv/qfmetr->lineSpacing()+1)); } } // scrollBy(0,qfmetr->lineSpacing()); } } if (paint) repaintContents(tmp->r); } void KDisplayText::gotomsec(ulong i) { int notidx=(typeoftextevents==1)?1:0; if (linked_list_[notidx]!=NULL) { cursor_line_[notidx]=linked_list_[notidx]; first_line_[notidx]=cursor_line_[notidx]; cursor_[notidx]=cursor_line_[notidx]->ev; while ((cursor_line_[notidx]!=NULL)&&(cursor_[notidx]->spev->absmillisecondsnext; while ((cursor_[notidx]==NULL)&&(cursor_line_[notidx]!=NULL)) { cursor_line_[notidx]=cursor_line_[notidx]->next; if (cursor_line_[notidx]!=NULL) { cursor_[notidx]=cursor_line_[notidx]->ev; if ((cursor_line_[notidx]->num>first_line_[notidx]->num+NUMPREVLINES) &&(cursor_line_[notidx]->numnum+nvisiblelines+1)) if ((first_line_[notidx]!=NULL)&&(first_line_[notidx]->num+nvisiblelines<=nlines_[notidx])) first_line_[notidx]=first_line_[notidx]->next; } } } } if (linked_list!=NULL) { cursor_line=linked_list; cursor=cursor_line->ev; first_line=linked_list; while ((cursor_line!=NULL)&&(cursor->spev->absmillisecondsnext; while ((cursor==NULL)&&(cursor_line!=NULL)) { cursor_line=cursor_line->next; if (cursor_line!=NULL) { cursor=cursor_line->ev; if ((cursor_line->num>first_line->num+NUMPREVLINES) &&(cursor_line->numnum+nvisiblelines+1)) if ((first_line!=NULL)&&(first_line->num+nvisiblelines<=nlines)) first_line=first_line->next; } } } this->killTimers(); autoscrollv=0; setContentsPos(0,first_line->ypos); viewport()->repaint(); } } TQFont *KDisplayText::getFont(void) { return qtextfont; } void KDisplayText::fontChanged(void) { TDEConfig *kcfg=TDEGlobal::instance()->config(); kcfg->setGroup("KMid"); TQFont *qtextfontdefault=new TQFont(*qtextfont); delete qtextfont; qtextfont=new TQFont(kcfg->readFontEntry("KaraokeFont",qtextfontdefault)); delete qtextfontdefault; qfmetr=new TQFontMetrics(*qtextfont); calculatePositions(); nvisiblelines=height()/qfmetr->lineSpacing(); viewport()->repaint(TRUE); } void KDisplayText::ChangeTypeOfTextEvents(int type) { int idxold=(typeoftextevents==1)?0:1; int idxnew=(type==1)?0:1; cursor_line_[idxold]=cursor_line; first_line_[idxold]=first_line; cursor_[idxold]=cursor; linked_list=linked_list_[idxnew]; cursor_line=cursor_line_[idxnew]; first_line=first_line_[idxnew]; cursor=cursor_[idxnew]; nlines=nlines_[idxnew]; typeoftextevents=type; if (first_line!=NULL) { nvisiblelines=height()/qfmetr->lineSpacing(); if (nlines>nvisiblelines) resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]); else resizeContents(0,0); setContentsPos(0,first_line->ypos); } viewport()->repaint(TRUE); } int KDisplayText::ChooseTypeOfTextEvents(void) { return (nlines_[0]>nlines_[1])? 1 : 5; } void KDisplayText::ScrollDown() { scrollBy(0,2/**qfmetr->lineSpacing()*/); } void KDisplayText::ScrollUp() { scrollBy(0,-2/**qfmetr->lineSpacing()*/); } void KDisplayText::ScrollPageDown() { scrollBy(0,nvisiblelines*qfmetr->lineSpacing()); } void KDisplayText::ScrollPageUp() { scrollBy(0,-nvisiblelines*qfmetr->lineSpacing()); } void KDisplayText::saveLyrics(FILE *fh) { kdispt_line *Lptr=linked_list_[(typeoftextevents==1)? 0:1]; while (Lptr!=NULL) { kdispt_ev *Cptr=Lptr->ev; if (Cptr!=NULL) { if (strcmp(Cptr->spev->text,"")!=0) if (IsLineFeed(Cptr->spev->text[0],Cptr->spev->type)) fputs(&Cptr->spev->text[1],fh); else fputs(Cptr->spev->text,fh); Cptr=Cptr->next; } while (Cptr!=NULL) { fputs(Cptr->spev->text,fh); Cptr=Cptr->next; } fputs("\n",fh); Lptr=Lptr->next; } } void KDisplayText::timerEvent(TQTimerEvent *e) { int dy; if (autoscrollv>0) { dy=2+autoscrollv/50; scrollBy(0,dy); autoscrollv-=dy; if (autoscrollv<0) { killTimer(e->timerId()); autoscrollv=0; } } else if (autoscrollv<0) { // dy=(autoscrollv<-2*qfmetr->lineSpacing())?-7:-2; dy=-2+autoscrollv/50; scrollBy(0,dy); autoscrollv-=dy; if (autoscrollv>0) { killTimer(e->timerId()); autoscrollv=0; } } else killTimer(e->timerId()); } void KDisplayText::setLyricsEncoding(const TQString &enc) { TQTextCodec *newcodec; if (enc.isEmpty()) newcodec=TDEGlobal::locale()->codecForEncoding(); else newcodec=TQTextCodec::codecForName(enc.latin1()); if (newcodec!=lyrics_codec) { if (newcodec) { lyrics_codec=newcodec; fontChanged(); } } } #include "kdisptext.moc"