// This sourcefile is created by Peter Jodda / peter@jodda.de
// It is under the Peter Jodda license:
// Everyboy may use it on his own risk. This header must stay in the file!
// If you expand this file, please contact me, that I can integrate the
// enhancemants in the original file.
//

#include <qimage.h>
#include <qpainter.h>
#include <qlayout.h>
#include <qfont.h>
#include <qfontmetrics.h>

#include <stdio.h>

#include "malbox.h"
#include "thumbnail.h"
#include "buffer2d.h"

MalBox::MalBox(QWidget *parent,QWidget *ParentBox) : 
		QWidget(parent,"malbox")
{
   int x,y;
   int schrifthoehe;
  
   // parent eintragen
   this->parentBox = (ScrollMalBox *) ParentBox;
   
   // liste für bilder erzeugen
   bilder = new ThumbnailListe();
   
   // ausdehnung eines Elementes
   thumbnailBreite = 100;
   thumbnailHoehe  = 100;
   
   verhaeltnisProzent = 80;
   
   maxImageBreite = (thumbnailBreite *94)/100;
   maxImageHoehe  = (thumbnailHoehe*verhaeltnisProzent)/100;
   
   
   
   // font laden und auf groesse skalieren   
   schriftfont = new QFont("courier");
   schrifthoehe = (thumbnailHoehe - (thumbnailHoehe*verhaeltnisProzent/100)) *75/100;
   schriftfont->setPixelSize(schrifthoehe);
   

   // irgend eine groesse muss da ja rein
   setMinimumSize(301,277);
   
   // berechnen der geometriedaten
   neuberechnen();
}

//-----------------------------------------------------------------


void MalBox::loescheAlleBilder()
{
   bilder->loescheAlle();

   // neu anzeigen 
   neuberechnen();
   maleAllesNeu();
}

//-----------------------------------------------------------------

void MalBox::addImage(buffer2d *bild, char *name)
{
   Thumbnail *neuesThumb;
   QImage    *image;
   int       breite,hoehe;
   int       neueBreite,neueHoehe;
   int       laufX,laufY;
   int       alteZeilenAnzahl;


   neuesThumb = new Thumbnail();
   
   breite = bild->breite();
   hoehe  = bild->hoehe();

   {
      // brechnung des maximalen bildes
      float faktorX,faktorY;
      float kleinererFaktor;

      faktorX =  (float) maxImageBreite / (float) breite ;
      faktorY =  (float) maxImageHoehe / (float) hoehe ;
      
      if(faktorX < faktorY)
         kleinererFaktor = faktorX;
      else
         kleinererFaktor = faktorY;
         
      neueBreite =(int)( breite * kleinererFaktor);
      neueHoehe  =(int)( hoehe  * kleinererFaktor);
      
   }
   
   //  skalieren 
   image = new QImage(neueBreite,neueHoehe,32);
   
   {
      int altY =0;
      int differenzY;
      
      differenzY=neueHoehe /2;

      // bilddaten uebertragen
      for( laufY=0 ; laufY < neueHoehe; laufY++)
      {
         uint *imImage;
         int   altX =0;
         int   differenzX;
         
         differenzX = neueBreite /2;

         imImage = (uint *) image->scanLine(laufY);
         for( laufX=0; laufX < neueBreite; laufX++)
         {
            unsigned char r,g,b;
            
            bild->get(altX,altY,&r,&g,&b);
            *imImage++ = qRgb(r,g,b);      

            // im original die naechste spalte berechnen     
            differenzX -= breite;
            while(differenzX <0)
            {
               differenzX += neueBreite;
               altX++;
            }
         
         }
    
         // im original die naechste zeile berechnen     
         differenzY -= hoehe;
         while(differenzY <0)
         {
            differenzY += neueHoehe;
            altY++;
         }
      }
   }
   
   // thumb mit den daten fuellen
   neuesThumb->setzeBild(image);
   neuesThumb->setzeNamen((char *)name);
   
   // jetzt in die liste einbauen
   bilder->add(neuesThumb);
   
   // geometriedaten neuberechnen
   // neuberechnen();
   
   alteZeilenAnzahl =  anzahlZeilen;
   anzahlZeilen     = bilder->anzahlBilder() / anzahlBreite;

   // eine zeile mit rest ??
   if( (bilder->anzahlBilder() % anzahlBreite) >0)
   {
      anzahlZeilen += 1;
   }
   
   if( anzahlZeilen != alteZeilenAnzahl )
   {
      // runterscrollen
      if (anzahlZeilen > sichtbareZeilen)
      {
         obersteZeile ++;
      }
      maleAllesNeu();
   }
   else
   {
      // nur das letzte neu zeichnen
      maleThumbnail(bilder->anzahlBilder() -1 );
   }
   parentBox->setzeScrollbalken(anzahlZeilen,sichtbareZeilen,obersteZeile) ;  


}

//-----------------------------------------------------------------

int MalBox::holeSelektiert(int letzter)
{
   int start;
   int i;
   
   if( letzter < 0 )
      start=0;
   else
      start =letzter+1;
   
   // den naechsten selektierten suchen      
   for(i=start; i < bilder->anzahlBilder(); i++)
   {
      
      if( bilder->gibBild(i)->selektiert == true)
         return i;
   }
   
   // nichts weiteres gefunden 
   return -1;
}

//-----------------------------------------------------------------

void MalBox::holSelektiertListe(int *anzahl,int **selektiertListe)
{
   bilder->holSelektiertListe(anzahl,selektiertListe); 
}

//-----------------------------------------------------------------

void MalBox::mousePressEvent(QMouseEvent *theEvent)
{
   Thumbnail *angeklicktesBild;
   int       mausX,mausY;
   int       bildNummer;
   
   
   mausX = theEvent->x();
   mausY = theEvent->y();
   
   // jetzt berechnen, welches bild darunter liegt;
   
   mausX /= thumbnailBreite;
   mausY /= thumbnailHoehe;
   
   if( mausX >= anzahlBreite)
      return;
   if( mausY >= sichtbareZeilen)
      return;
   
   bildNummer =  obersteZeile*anzahlBreite 
                + mausY * anzahlBreite
                + mausX;
   if(bildNummer >= bilder->anzahlBilder())
   {
      return;
   }      
   angeklicktesBild = bilder-> gibBild( bildNummer );
   
   // selektion wechseln 
   angeklicktesBild->selektiert = ! angeklicktesBild->selektiert;           
   
   // jetzt das bild neuzeichnen
   QPainter painter(this);
   maleThumbnail(&painter,
                 angeklicktesBild,
                 mausX*thumbnailBreite,
                 mausY*thumbnailHoehe  );
   
}


//-----------------------------------------------------------------

void MalBox::paintEvent(QPaintEvent *theEvent)
{
   QRect rect;
   int   erstesBild,aktuellesBild;
   int   x,y;
   
   rect = theEvent->rect();
   /*fprintf(stderr,"repaint %d %d %d %d\n",
   		rect.x(),
   		rect.y(),
   		rect.width(),
   		rect.height());
    */

   // alle elemente neu malen   
   maleAlles();
   
}

//-----------------------------------------------------------------

void MalBox::resizeEvent(QResizeEvent *theEvent)
{
   QRect rect;
   int   erstesBild,aktuellesBild;
   int   x,y;
   
   // fprintf(stderr,"resize \n");
   
   // geometrie jetzt neu berechnen
   neuberechnen();
   
}

//-----------------------------------------------------------------

void MalBox::maleAllesNeu()
{
   // erst den hintergrund loeschen
   erase();

   // dann komplett neu malen
   maleAlles();
}

//-----------------------------------------------------------------
// alle sichtbare thumbnails neu malen, dabei vorher nicht den 
// hintergrund loeschen

void MalBox::maleAlles()
{
   int erstesBild,aktuellesBild;
   int x,y;
   
   QPainter painter(this);
   erstesBild = obersteZeile * anzahlBreite;
   
   for(y=0;y<sichtbareZeilen;y++)
   {
      for(x=0; x<anzahlBreite; x++)
      {
         Thumbnail *bild;
         int       aktuellesBild;
         int       positionX,positionY;
         
         aktuellesBild = erstesBild + y*anzahlBreite+x;

         bild = bilder->gibBild(aktuellesBild);
         if(bild == NULL)
            break;

         positionX = x* thumbnailBreite;
         positionY = y* thumbnailHoehe;
         maleThumbnail(&painter,bild,positionX,positionY);
            
      } // for x ;
   } // for y
   painter.flush();
   
}
//-----------------------------------------------------------------

void MalBox::maleThumbnail(int index)
{
   QPainter painter(this);
   int      erstesBild;
   int      x,y;

   erstesBild = obersteZeile * anzahlBreite;
   
   // vor dem ausschnitt
   if (index < erstesBild )
      return;
   
   // nach dem ausschnitt
   if(index >= erstesBild + sichtbareZeilen*anzahlBreite)
      return;
   
   x = index % anzahlBreite;
   y = ((index-erstesBild) / anzahlBreite );
   
   x *= thumbnailBreite;
   y *= thumbnailHoehe;

   maleThumbnail(&painter, 
                 bilder->gibBild(index),
                 x,
                 y);
   painter.flush();
}


//-----------------------------------------------------------------
// das bild und die schrift darunter zentriert ausgeben

void MalBox::maleThumbnail(QPainter *painter,Thumbnail *dasBild,int x,int y)
{
   QFontMetrics fontmetrics(*schriftfont);
   QColor       weiss  =QColor(255,255,255);
   QColor       schwarz=QColor(0,0,0);
   QRect        schriftbereich;
   int          hoeheBild ,bildx,bildy,schriftx,schrifty;


   if(dasBild->selektiert)
   {
      painter->setBrush(schwarz);
      painter->setPen(weiss);
      painter->fillRect(x,y,thumbnailBreite,thumbnailHoehe,schwarz);
   }
   else
   {
      painter->setBrush(weiss);
      painter->setPen(schwarz);
      painter->fillRect(x,y,thumbnailBreite,thumbnailHoehe,weiss);
   }
   hoeheBild = thumbnailHoehe *verhaeltnisProzent/100;
   
   // das bild in zentriert ausgeben
   bildy = (hoeheBild - dasBild->bild->height() ) /2;
   if (bildy <0)
      bildy = 0;
   bildx = (thumbnailBreite - dasBild->bild->width() ) /2;
   if (bildx <0)
      bildx = 0;
   painter->drawImage(x+bildx,y+bildy,*(dasBild->bild));
   
   painter->setFont(*schriftfont);
   fontmetrics = painter->fontMetrics();
   
   schriftbereich = fontmetrics.boundingRect(dasBild->name);

/*   fprintf(stderr,"schrift %d %d %d %d\n",
   		schriftbereich.x(),
   		schriftbereich.y(),
   		schriftbereich.width(),
   		schriftbereich.height());
*/
   schriftx = (thumbnailBreite - schriftbereich.width() ) /2;
   if (schriftx <0)
      schriftx = 0;
   schrifty = ((thumbnailHoehe -hoeheBild) -schriftbereich.height() ) /2;
   if (schrifty <0)
      schrifty = 0;

   painter->drawText(x+schriftx,
                     y+schrifty+hoeheBild+schriftbereich.height(),
                     dasBild->name);

}

//-----------------------------------------------------------------

// nach layout-aenderungen alle werte neu berechnen
void MalBox::neuberechnen()
{
   

   aktuelleBoxBreite = width();
   aktuelleBoxHoehe  = height();
   
   anzahlBreite      = aktuelleBoxBreite / thumbnailBreite;
   anzahlZeilen      = bilder->anzahlBilder() / anzahlBreite;

   // eine zeile mit rest ??
   if( (bilder->anzahlBilder() % anzahlBreite) >0)
   {
      anzahlZeilen += 1;
   }
   
   // von vorne beginnen
   obersteZeile    = 0; 
   sichtbareZeilen = aktuelleBoxHoehe / thumbnailHoehe;

   parentBox->setzeScrollbalken(anzahlZeilen,
                                sichtbareZeilen,
                                obersteZeile) ;  

}


//===========================================================================
//===========================================================================
//===========================================================================

ScrollMalBox::ScrollMalBox(QWidget *parent) : 
		QWidget(parent,"ScrollMalbox")
{
   QBoxLayout *graphicsLayout; 
   
   hoehenScrollbalken = NULL;
   graphicsLayout     = new QHBoxLayout( this);
   dieMalBox          = new MalBox(this,this);
   hoehenScrollbalken = new QScrollBar(0,1,1,1,0,QScrollBar::Vertical,this);
   
   graphicsLayout->addWidget(dieMalBox);
   graphicsLayout->addWidget(hoehenScrollbalken);

   // signal auf den scrollbar umsetzen
   connect(hoehenScrollbalken,
           SIGNAL(valueChanged(int)),
           this,
           SLOT(scrollbalkenBewegt(int)) );

}

//----------------------------------------------------------------
// scrollbalken den gegebenheiten anpassen

void ScrollMalBox::setzeScrollbalken(int gesamt,int sichtbar,int position)
{
   // fprintf(stderr,"setze Scroll %d %d %d\n",gesamt,sichtbar,position);

   if(hoehenScrollbalken == NULL)
      return;

   if(gesamt <= sichtbar)
   {
      // scrollbar ist gesamt zu sehen
      hoehenScrollbalken->setValue(0);
      hoehenScrollbalken->setRange(0,0);
      hoehenScrollbalken->setSteps(1,1);
   }  
   else
   {
      // scrollbar ist nur in teilen zu sehen
      hoehenScrollbalken->setValue(0);
      hoehenScrollbalken->setRange(0,gesamt-sichtbar);
      hoehenScrollbalken->setSteps(1,sichtbar);
      hoehenScrollbalken->setValue(position);
   }
}

//----------------------------------------------------------------
// signal-funktion für bewegung des scrollbalkens

void ScrollMalBox::scrollbalkenBewegt(int wert)
{
   
   dieMalBox->obersteZeile = wert;
   dieMalBox->maleAllesNeu();
}

void ScrollMalBox::loescheAlleBilder()
{
   // direkt weiterreichen
   dieMalBox->loescheAlleBilder();
}

void ScrollMalBox::addImage(buffer2d *bild, char *name)
{
   // direkt weiterreichen
   dieMalBox->addImage(bild, name);
}

int ScrollMalBox::holeSelektiert(int letzter)
{
   // direkt weiterreichen
   return dieMalBox->holeSelektiert( letzter );
}

void ScrollMalBox::holSelektiertListe(int *anzahl,int **selektiertListe)
{
   // direkt weiterreichen
   dieMalBox->holSelektiertListe(anzahl,selektiertListe); 
}
