Fairly large overhaul of the JuK codebase to beat out a lot of the Qt 3 stuff.
[kdemultimedia.git] / kmid / kdisptext.cpp
blobb587dc3f4a9e4d6c692c8d7d3a32e7ec859bf15e
1 /**************************************************************************
3 kdisptext.cpp - The widget that displays the karaoke/lyrics text
4 Copyright (C) 1997,98 Antonio Larrosa Jimenez
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 Send comments and bug fixes to larrosa@kde.org
21 or to Antonio Larrosa, Rio Arnoya, 10 5B, 29006 Malaga, Spain
23 ***************************************************************************/
24 #include "kdisptext.h"
25 #include <qpainter.h>
26 #include <QFont>
27 #include <QPalette>
28 #include <qfontmetrics.h>
29 #include <qrect.h>
30 #include <qtextcodec.h>
31 //Added by qt3to4:
32 #include <QTimerEvent>
33 #include <QResizeEvent>
35 #include <kconfig.h>
36 #include <kglobal.h>
37 #include <kglobalsettings.h>
38 #include <kcomponentdata.h>
39 #include <klocale.h>
40 #include <QAbstractEventDispatcher>
41 #include "version.h"
44 #define NUMPREVLINES 2
45 //#define DRAW_BOUNDING_RECTS
48 KDisplayText::KDisplayText(QWidget *parent,const char *name) : Q3ScrollView(parent,name)
50 first_line_[0]=first_line_[1]=NULL;
51 linked_list_[0]=linked_list_[1]=NULL;
52 cursor_line_[0]=cursor_line_[1]=NULL;
53 cursor_[0]=cursor_[1]=NULL;
54 nlines_[0]=nlines_[1]=0;
55 linked_list=NULL;
56 cursor_line=NULL;
57 first_line=NULL;
58 cursor=NULL;
59 nlines=0;
60 lyrics_codec=KGlobal::locale()->codecForEncoding();
62 QPalette palette;
63 palette.setColor(viewport()->backgroundRole(), QColor(110,110,110));
64 viewport()->setPalette(palette);
65 // setBackgroundMode(NoBackground);
66 KSharedConfigPtr kcfg=KGlobal::config();
67 KConfigGroup kmidGroup = kcfg->group("KMid");
68 typeoftextevents = kmidGroup.readEntry("TypeOfTextEvents",1);
69 QFont *qtextfontdefault=new QFont(KGlobalSettings::fixedFont().family(),22);
70 qtextfont = new QFont(kmidGroup.readEntry("KaraokeFont",*qtextfontdefault));
71 delete qtextfontdefault;
72 qfmetr=new QFontMetrics(*qtextfont);
73 nvisiblelines=height()/qfmetr->lineSpacing();
74 autoscrollv=0;
77 KDisplayText::~KDisplayText()
79 RemoveLinkedList();
82 /*void KDisplayText::PreDestroyer(void)
84 delete qfmetr;
85 delete qtextfont;
89 void KDisplayText::RemoveLine(kdispt_line *tmpl)
91 kdispt_ev *tmpe;
92 while (tmpl->ev!=NULL)
94 tmpe=tmpl->ev;
95 tmpl->ev=tmpe->next;
96 // delete tmpe->spev; Remember that the Special Events that this pointer
97 // points to is the same that the Player object has instantiated
98 delete tmpe;
102 void KDisplayText::RemoveLinkedList(void)
104 cursor=NULL;
105 cursor_line=NULL;
106 first_line=NULL;
107 linked_list=NULL;
108 nlines=0;
109 nlines_[0]=nlines_[1]=0;
110 first_line_[0]=first_line_[1]=NULL;
111 cursor_line_[0]=cursor_line_[1]=NULL;
112 cursor_[0]=cursor_[1]=NULL;
114 kdispt_line *tmpl;
115 for (int i=0;i<2;i++)
117 while (linked_list_[i]!=NULL)
119 RemoveLine(linked_list_[i]);
120 tmpl=linked_list_[i];
121 linked_list_[i]=linked_list_[i]->next;
122 delete tmpl;
127 void KDisplayText::ClearEv(bool totally)
129 RemoveLinkedList();
130 if (totally)
132 QAbstractEventDispatcher::instance()->unregisterTimers(this);
133 autoscrollv=0;
134 resizeContents(0,0);
135 viewport()->repaint();
139 int KDisplayText::IsLineFeed(char c,int type)
141 switch (type)
143 case (1) : if (/*(c==0)||*/(c=='\\')||(c=='/')||(c=='@')) return 1;break;
144 case (5) : if (/*(c==0)||*/(c==10)||(c==13)) return 1;break;
145 default : if ((c==0)||(c==10)||(c==13)||(c=='\\')||(c=='/')||(c=='@')) return 1;break;
147 return 0;
150 void KDisplayText::AddEv(SpecialEvent *ev)
152 if ((ev->type==1) || (ev->type==5))
154 int idx=(ev->type==1)? 0 : 1;
155 if (linked_list_[idx]==NULL)
157 linked_list_[idx]=new kdispt_line;
158 linked_list_[idx]->next=NULL;
159 linked_list_[idx]->num=1;
160 linked_list_[idx]->ev=new kdispt_ev;
161 cursor_line_[idx]=linked_list_[idx];
162 cursor_[idx]=cursor_line_[idx]->ev;
163 cursor_[idx]->spev=ev;
164 cursor_[idx]->next=NULL;
165 first_line_[idx]=linked_list_[idx];
166 first_line=first_line_[idx];
167 nlines_[idx]=1;
169 else
171 if (IsLineFeed(ev->text[0],ev->type))
173 nlines_[idx]++;
174 cursor_line_[idx]->next=new kdispt_line;
175 cursor_line_[idx]=cursor_line_[idx]->next;
176 cursor_line_[idx]->num=nlines_[idx];
177 cursor_line_[idx]->ev=new kdispt_ev;
178 cursor_line_[idx]->next=NULL;
179 cursor_[idx]=cursor_line_[idx]->ev;
181 else
183 cursor_[idx]->next=new kdispt_ev;
184 cursor_[idx]=cursor_[idx]->next;
186 cursor_[idx]->spev=ev;
187 cursor_[idx]->next=NULL;
192 void KDisplayText::calculatePositions(void)
194 int typeoftextevents=1;
195 int fin=0;
196 kdispt_line *tmpl;
197 kdispt_ev *tmp;
198 int tmpx=0;
199 int tmpy=0;
200 int tmpw=0;
201 int maxx=0;
202 nlines=nlines_[(typeoftextevents==1)? 0:1];
203 int lineSpacing=qfmetr->lineSpacing();
204 int descent=qfmetr->descent();
205 while (!fin)
207 tmpl=linked_list_[(typeoftextevents==1)?0:1];
208 tmpy=lineSpacing;
209 maxx=0;
210 while (tmpl!=NULL)
212 tmp=tmpl->ev;
213 tmpx=5;
214 while (tmp!=NULL)
216 if (tmp->spev->type==typeoftextevents)
218 if (IsLineFeed(tmp->spev->text[0],typeoftextevents))
220 tmpy+=lineSpacing;
221 tmpx=5;
223 tmp->xpos=tmpx;
224 if (tmp->spev->text[0]!=0) tmpw=qfmetr->width(lyrics_codec->toUnicode(&tmp->spev->text[1]));
225 else tmpw=0;
226 tmp->r=qfmetr->boundingRect(lyrics_codec->toUnicode(&tmp->spev->text[1]));
228 else
230 tmp->xpos=tmpx;
231 tmpw=qfmetr->width(lyrics_codec->toUnicode(tmp->spev->text));
232 tmp->r=qfmetr->boundingRect(lyrics_codec->toUnicode(tmp->spev->text));
234 // We add 5 pixels above, below and to the right because of a
235 // problem with latest released Xft
236 tmp->r.translate(tmpx,tmpy-tmp->r.height()-tmp->r.y()-5);
237 tmp->r.setHeight(tmp->r.height()+descent+10);
238 tmp->r.setWidth(tmp->r.width()+5);
239 tmpx+=tmpw;
240 if (tmpx>maxx) maxx=tmpx;
242 tmp=tmp->next;
244 tmpl->ypos=tmpl->num*lineSpacing;
245 tmpy=tmpl->ypos;
246 tmpl=tmpl->next;
248 maxX[(typeoftextevents==1)?0:1]=maxx+10;
249 maxY[(typeoftextevents==1)?0:1]=
250 nlines_[(typeoftextevents==1)?0:1]*lineSpacing+descent+10;
252 if (typeoftextevents==1) typeoftextevents=5;
253 else fin=1;
258 kdispt_line *KDisplayText::searchYOffset(int y, kdispt_line *start)
260 kdispt_line *t=start;
261 while (t!=NULL)
263 // if (t->ypos+qfmetr->descent()>y) return start;
264 if (t->ypos+qfmetr->descent()+20>y) return start;
265 start=t;
266 t=t->next;
268 return start;
271 void KDisplayText::drawContents(QPainter *p, int /*clipx*/, int clipy, int /*clipw*/, int cliph)
273 p->setFont(*qtextfont);
274 if (linked_list==NULL) return;
275 int i=0;
276 p->setPen(Qt::yellow);
277 int colorplayed=1;
278 if (cursor==NULL) colorplayed=0; // Thus, the program doesn't change the color
279 kdispt_line *tmpl=linked_list;
280 kdispt_ev *tmp;
282 #ifdef KDISPTEXTDEBUG
283 printf("events displayed %d\n",typeoftextevents);
284 #endif
286 tmpl=searchYOffset(clipy,linked_list);
287 int nlinestodraw=1;
288 kdispt_line *t=tmpl;
289 while ((t!=NULL)&&(t->ypos+qfmetr->descent()<clipy+cliph))
291 nlinestodraw++;
292 t=t->next;
295 i=0;
296 while ((i<nlinestodraw)&&(tmpl!=NULL))
298 tmp=tmpl->ev;
299 while ((tmp!=NULL)&&(tmp->spev->type!=typeoftextevents)) tmp=tmp->next;
300 while (tmp!=NULL)
302 if ( colorplayed &&
303 // (tmp->spev->absmilliseconds>=cursor->spev->absmilliseconds))
304 (tmp->spev->id>=cursor->spev->id))
306 p->setPen(Qt::black);
307 colorplayed=0;
310 if (IsLineFeed(tmp->spev->text[0],tmp->spev->type))
311 p->drawText(tmp->xpos,tmpl->ypos,lyrics_codec->toUnicode(&tmp->spev->text[1]));
312 else
313 p->drawText(tmp->xpos,tmpl->ypos,lyrics_codec->toUnicode(tmp->spev->text));
315 #ifdef DRAW_BOUNDING_RECTS
316 p->setPen(Qt::red);
317 p->drawRect(tmp->r);
318 p->setPen((colorplayed)?Qt::yellow:Qt::black);
319 #endif
320 tmp=tmp->next;
321 while ((tmp!=NULL)&&(tmp->spev->type!=typeoftextevents)) tmp=tmp->next;
323 i++;
324 tmpl=tmpl->next;
330 void KDisplayText::resizeEvent(QResizeEvent *e)
332 Q3ScrollView::resizeEvent(e);
333 nvisiblelines=visibleHeight()/qfmetr->lineSpacing();
334 if ( (nlines>nvisiblelines) || (nvisiblelines==0) )
335 resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]);
336 else
337 resizeContents(0,0);
341 void KDisplayText::CursorToHome(void)
343 /* KConfig *kcfg=KGlobal::mainComponent().config();
344 kcfg->setGroup("KMid");
345 typeoftextevents=kcfg->readEntry("TypeOfTextEvents",1);
347 linked_list=linked_list_[(typeoftextevents==1)? 0:1];
348 nlines=nlines_[(typeoftextevents==1)? 0:1];
349 cursor_line_[0]=linked_list_[0];
350 first_line_[0]=cursor_line_[0];
351 if (cursor_line_[0]!=NULL) cursor_[0]=cursor_line_[0]->ev;
352 cursor_line_[1]=linked_list_[1];
353 first_line_[1]=cursor_line_[1];
354 if (cursor_line_[1]!=NULL) cursor_[1]=cursor_line_[1]->ev;
356 if (linked_list==NULL)
358 cursor_line=NULL;
359 cursor=NULL;
360 first_line=NULL;
362 else
364 cursor_line=linked_list;
365 cursor=cursor_line->ev;
366 first_line=linked_list;
369 nvisiblelines=visibleHeight()/qfmetr->lineSpacing();
370 if (nlines>nvisiblelines)
371 resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]);
372 else
373 resizeContents(0,0);
376 setContentsPos(0,0);
377 viewport()->repaint();
380 void KDisplayText::PaintIn(int type)
382 bool paint=false;
383 if (type!=typeoftextevents)
385 int idx=(type==1)?0:1;
386 if (cursor_[idx]==NULL) return;
387 cursor_[idx]=cursor_[idx]->next;
388 while ((cursor_[idx]==NULL)&&(cursor_line_[idx]!=NULL))
390 cursor_line_[idx]=cursor_line_[idx]->next;
391 if (cursor_line_[idx]!=NULL)
393 cursor_[idx]=cursor_line_[idx]->ev;
394 if ((cursor_line_[idx]->num>first_line_[idx]->num+NUMPREVLINES)
395 &&(cursor_line_[idx]->num<first_line_[idx]->num+nvisiblelines+1))
396 if ((first_line_[idx]!=NULL)&&(first_line_[idx]->num+nvisiblelines<=nlines_[idx])) first_line_[idx]=first_line_[idx]->next;
399 return;
402 if ((cursor==NULL)||(cursor_line==NULL))
404 printf("KDispT : cursor == NULL !!!\n");
405 return;
408 kdispt_ev *tmp=cursor;
409 if (cursor->spev->type==typeoftextevents)
411 // int x,y;
412 // contentsToViewport(cursor->xpos,cursor_line->ypos,x,y);
414 cursor=cursor->next;
415 paint=true;
418 else
419 cursor=cursor->next;
422 while ((cursor==NULL)&&(cursor_line!=NULL))
424 cursor_line=cursor_line->next;
425 if (cursor_line!=NULL)
427 cursor=cursor_line->ev;
428 if ((cursor_line->ypos>contentsY()+(visibleHeight()*5/8))&&
429 (cursor_line->ypos<contentsY()+visibleHeight()+autoscrollv))
431 bool b=(autoscrollv==0);
432 autoscrollv+=qfmetr->lineSpacing();
433 if (b) startTimer(100);
434 else {
435 QAbstractEventDispatcher::instance()->unregisterTimers(this);
436 startTimer(100/(autoscrollv/qfmetr->lineSpacing()+1));
439 // scrollBy(0,qfmetr->lineSpacing());
442 if (paint) repaintContents(tmp->r);
445 void KDisplayText::gotomsec(ulong i)
447 int notidx=(typeoftextevents==1)?1:0;
449 if (linked_list_[notidx]!=NULL)
451 cursor_line_[notidx]=linked_list_[notidx];
452 first_line_[notidx]=cursor_line_[notidx];
453 cursor_[notidx]=cursor_line_[notidx]->ev;
454 while ((cursor_line_[notidx]!=NULL)&&(cursor_[notidx]->spev->absmilliseconds<i))
456 cursor_[notidx]=cursor_[notidx]->next;
457 while ((cursor_[notidx]==NULL)&&(cursor_line_[notidx]!=NULL))
459 cursor_line_[notidx]=cursor_line_[notidx]->next;
460 if (cursor_line_[notidx]!=NULL)
462 cursor_[notidx]=cursor_line_[notidx]->ev;
463 if ((cursor_line_[notidx]->num>first_line_[notidx]->num+NUMPREVLINES)
464 &&(cursor_line_[notidx]->num<first_line_[notidx]->num+nvisiblelines+1))
465 if ((first_line_[notidx]!=NULL)&&(first_line_[notidx]->num+nvisiblelines<=nlines_[notidx])) first_line_[notidx]=first_line_[notidx]->next;
471 if (linked_list!=NULL)
473 cursor_line=linked_list;
474 cursor=cursor_line->ev;
475 first_line=linked_list;
476 while ((cursor_line!=NULL)&&(cursor->spev->absmilliseconds<i))
478 cursor=cursor->next;
479 while ((cursor==NULL)&&(cursor_line!=NULL))
481 cursor_line=cursor_line->next;
482 if (cursor_line!=NULL)
484 cursor=cursor_line->ev;
485 if ((cursor_line->num>first_line->num+NUMPREVLINES)
486 &&(cursor_line->num<first_line->num+nvisiblelines+1))
487 if ((first_line!=NULL)&&(first_line->num+nvisiblelines<=nlines)) first_line=first_line->next;
494 QAbstractEventDispatcher::instance()->unregisterTimers(this);
495 autoscrollv=0;
496 setContentsPos(0,first_line->ypos);
497 viewport()->repaint();
502 QFont *KDisplayText::getFont(void)
504 return qtextfont;
507 void KDisplayText::fontChanged(void)
509 KSharedConfigPtr kcfg=KGlobal::config();
510 KConfigGroup kmidGroup = kcfg->group("KMid");
511 QFont *qtextfontdefault=new QFont(*qtextfont);
512 delete qtextfont;
513 qtextfont = new QFont(kmidGroup.readEntry("KaraokeFont",*qtextfontdefault));
514 delete qtextfontdefault;
515 qfmetr=new QFontMetrics(*qtextfont);
516 calculatePositions();
517 nvisiblelines=height()/qfmetr->lineSpacing();
518 viewport()->repaint();
521 void KDisplayText::ChangeTypeOfTextEvents(int type)
523 int idxold=(typeoftextevents==1)?0:1;
524 int idxnew=(type==1)?0:1;
525 cursor_line_[idxold]=cursor_line;
526 first_line_[idxold]=first_line;
527 cursor_[idxold]=cursor;
528 linked_list=linked_list_[idxnew];
529 cursor_line=cursor_line_[idxnew];
530 first_line=first_line_[idxnew];
531 cursor=cursor_[idxnew];
532 nlines=nlines_[idxnew];
533 typeoftextevents=type;
534 if (first_line!=NULL)
536 nvisiblelines=height()/qfmetr->lineSpacing();
537 if (nlines>nvisiblelines)
538 resizeContents(maxX[(typeoftextevents==1)?0:1],maxY[(typeoftextevents==1)?0:1]);
539 else
540 resizeContents(0,0);
542 setContentsPos(0,first_line->ypos);
544 viewport()->repaint();
547 int KDisplayText::ChooseTypeOfTextEvents(void)
549 return (nlines_[0]>nlines_[1])? 1 : 5;
552 void KDisplayText::ScrollDown()
554 scrollBy(0,2/**qfmetr->lineSpacing()*/);
557 void KDisplayText::ScrollUp()
559 scrollBy(0,-2/**qfmetr->lineSpacing()*/);
562 void KDisplayText::ScrollPageDown()
564 scrollBy(0,nvisiblelines*qfmetr->lineSpacing());
567 void KDisplayText::ScrollPageUp()
569 scrollBy(0,-nvisiblelines*qfmetr->lineSpacing());
572 void KDisplayText::saveLyrics(FILE *fh)
574 kdispt_line *Lptr=linked_list_[(typeoftextevents==1)? 0:1];
575 while (Lptr!=NULL)
577 kdispt_ev *Cptr=Lptr->ev;
578 if (Cptr!=NULL)
580 if (strcmp(Cptr->spev->text,"")!=0)
581 if (IsLineFeed(Cptr->spev->text[0],Cptr->spev->type))
582 fputs(&Cptr->spev->text[1],fh);
583 else
584 fputs(Cptr->spev->text,fh);
585 Cptr=Cptr->next;
587 while (Cptr!=NULL)
589 fputs(Cptr->spev->text,fh);
590 Cptr=Cptr->next;
592 fputs("\n",fh);
593 Lptr=Lptr->next;
597 void KDisplayText::timerEvent(QTimerEvent *e)
599 int dy;
600 if (autoscrollv>0)
602 dy=2+autoscrollv/50;
603 scrollBy(0,dy);
604 autoscrollv-=dy;
605 if (autoscrollv<0)
607 killTimer(e->timerId());
608 autoscrollv=0;
611 else
612 if (autoscrollv<0)
614 // dy=(autoscrollv<-2*qfmetr->lineSpacing())?-7:-2;
615 dy=-2+autoscrollv/50;
616 scrollBy(0,dy);
617 autoscrollv-=dy;
618 if (autoscrollv>0)
620 killTimer(e->timerId());
621 autoscrollv=0;
624 else
625 killTimer(e->timerId());
629 void KDisplayText::setLyricsEncoding(const QString &enc)
631 QTextCodec *newcodec;
632 if (enc.isEmpty())
633 newcodec=KGlobal::locale()->codecForEncoding();
634 else
635 newcodec=QTextCodec::codecForName(enc.toLatin1());
637 if (newcodec!=lyrics_codec)
639 if (newcodec)
641 lyrics_codec=newcodec;
642 fontChanged();
647 #include "kdisptext.moc"