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"
28 #include <qfontmetrics.h>
30 #include <qtextcodec.h>
32 #include <QTimerEvent>
33 #include <QResizeEvent>
37 #include <kglobalsettings.h>
38 #include <kcomponentdata.h>
40 #include <QAbstractEventDispatcher>
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;
60 lyrics_codec
=KGlobal::locale()->codecForEncoding();
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();
77 KDisplayText::~KDisplayText()
82 /*void KDisplayText::PreDestroyer(void)
89 void KDisplayText::RemoveLine(kdispt_line
*tmpl
)
92 while (tmpl
->ev
!=NULL
)
96 // delete tmpe->spev; Remember that the Special Events that this pointer
97 // points to is the same that the Player object has instantiated
102 void KDisplayText::RemoveLinkedList(void)
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
;
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
;
127 void KDisplayText::ClearEv(bool totally
)
132 QAbstractEventDispatcher::instance()->unregisterTimers(this);
135 viewport()->repaint();
139 int KDisplayText::IsLineFeed(char c
,int 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;
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
];
171 if (IsLineFeed(ev
->text
[0],ev
->type
))
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
;
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;
202 nlines
=nlines_
[(typeoftextevents
==1)? 0:1];
203 int lineSpacing
=qfmetr
->lineSpacing();
204 int descent
=qfmetr
->descent();
207 tmpl
=linked_list_
[(typeoftextevents
==1)?0:1];
216 if (tmp
->spev
->type
==typeoftextevents
)
218 if (IsLineFeed(tmp
->spev
->text
[0],typeoftextevents
))
224 if (tmp
->spev
->text
[0]!=0) tmpw
=qfmetr
->width(lyrics_codec
->toUnicode(&tmp
->spev
->text
[1]));
226 tmp
->r
=qfmetr
->boundingRect(lyrics_codec
->toUnicode(&tmp
->spev
->text
[1]));
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);
240 if (tmpx
>maxx
) maxx
=tmpx
;
244 tmpl
->ypos
=tmpl
->num
*lineSpacing
;
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;
258 kdispt_line
*KDisplayText::searchYOffset(int y
, kdispt_line
*start
)
260 kdispt_line
*t
=start
;
263 // if (t->ypos+qfmetr->descent()>y) return start;
264 if (t
->ypos
+qfmetr
->descent()+20>y
) 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;
276 p
->setPen(Qt::yellow
);
278 if (cursor
==NULL
) colorplayed
=0; // Thus, the program doesn't change the color
279 kdispt_line
*tmpl
=linked_list
;
282 #ifdef KDISPTEXTDEBUG
283 printf("events displayed %d\n",typeoftextevents
);
286 tmpl
=searchYOffset(clipy
,linked_list
);
289 while ((t
!=NULL
)&&(t
->ypos
+qfmetr
->descent()<clipy
+cliph
))
296 while ((i
<nlinestodraw
)&&(tmpl
!=NULL
))
299 while ((tmp
!=NULL
)&&(tmp
->spev
->type
!=typeoftextevents
)) tmp
=tmp
->next
;
303 // (tmp->spev->absmilliseconds>=cursor->spev->absmilliseconds))
304 (tmp
->spev
->id
>=cursor
->spev
->id
))
306 p
->setPen(Qt::black
);
310 if (IsLineFeed(tmp
->spev
->text
[0],tmp
->spev
->type
))
311 p
->drawText(tmp
->xpos
,tmpl
->ypos
,lyrics_codec
->toUnicode(&tmp
->spev
->text
[1]));
313 p
->drawText(tmp
->xpos
,tmpl
->ypos
,lyrics_codec
->toUnicode(tmp
->spev
->text
));
315 #ifdef DRAW_BOUNDING_RECTS
318 p
->setPen((colorplayed
)?Qt::yellow
:Qt::black
);
321 while ((tmp
!=NULL
)&&(tmp
->spev
->type
!=typeoftextevents
)) tmp
=tmp
->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]);
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
)
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]);
377 viewport()->repaint();
380 void KDisplayText::PaintIn(int type
)
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
;
402 if ((cursor
==NULL
)||(cursor_line
==NULL
))
404 printf("KDispT : cursor == NULL !!!\n");
408 kdispt_ev
*tmp
=cursor
;
409 if (cursor
->spev
->type
==typeoftextevents
)
412 // contentsToViewport(cursor->xpos,cursor_line->ypos,x,y);
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);
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
))
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);
496 setContentsPos(0,first_line
->ypos
);
497 viewport()->repaint();
502 QFont
*KDisplayText::getFont(void)
507 void KDisplayText::fontChanged(void)
509 KSharedConfigPtr kcfg
=KGlobal::config();
510 KConfigGroup kmidGroup
= kcfg
->group("KMid");
511 QFont
*qtextfontdefault
=new QFont(*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]);
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];
577 kdispt_ev
*Cptr
=Lptr
->ev
;
580 if (strcmp(Cptr
->spev
->text
,"")!=0)
581 if (IsLineFeed(Cptr
->spev
->text
[0],Cptr
->spev
->type
))
582 fputs(&Cptr
->spev
->text
[1],fh
);
584 fputs(Cptr
->spev
->text
,fh
);
589 fputs(Cptr
->spev
->text
,fh
);
597 void KDisplayText::timerEvent(QTimerEvent
*e
)
607 killTimer(e
->timerId());
614 // dy=(autoscrollv<-2*qfmetr->lineSpacing())?-7:-2;
615 dy
=-2+autoscrollv
/50;
620 killTimer(e
->timerId());
625 killTimer(e
->timerId());
629 void KDisplayText::setLyricsEncoding(const QString
&enc
)
631 QTextCodec
*newcodec
;
633 newcodec
=KGlobal::locale()->codecForEncoding();
635 newcodec
=QTextCodec::codecForName(enc
.toLatin1());
637 if (newcodec
!=lyrics_codec
)
641 lyrics_codec
=newcodec
;
647 #include "kdisptext.moc"