/* This file is part of the KDE libraries
    Copyright (C) 1997 Sven Radej (sven.radej@iname.com)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/
#include <qpainter.h>
#include <qdrawutl.h>
#include <qpalette.h>
#include <qstring.h>
#include <qframe.h>

#include "ktopwidget.h"

#include "kmenubar.moc"

#include <klocale.h>
#include <kapp.h>
#include <kwm.h>

#define CONTEXT_TOP 1
#define CONTEXT_BOTTOM 2
#define CONTEXT_FLOAT 3

// uncomment this to have menubar raised:

#define MENUBAR_IS_RAISED


_menuBar::_menuBar (QWidget *parent, const char *name)
  : QMenuBar (parent, name)
 {
#ifndef MENUBAR_IS_RAISED
   setFrameStyle(NoFrame);
#endif
	
   //MD (17-9-97)
   setLineWidth(1);
 }

_menuBar::~_menuBar ()
 {
 }

/*************************************************************/

KMenuBar::KMenuBar(QWidget *parent, const char *name)
  : QFrame( parent, name )
{
  Parent = parent;        // our father
  title = 0;

  frame = new QFrame (this);
  frame->setFrameStyle(NoFrame);
  menu = new _menuBar (frame);
  oldMenuFrameStyle = menu->frameStyle();


  // WARNING: this is a hack for qt-1.3
  // Real qt-1.3 support should use heightFromWidth() in 
  // resizeEvent. But this will not work for qt-1.2.
  // Let us wait until qt-1.3 is released.  Matthias
  frame->installEventFilter(menu);


  connect (menu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
  connect (menu, SIGNAL(highlighted(int)), this, SLOT(slotHighlighted(int)));
  handle = new QFrame (this);
  handle->setMouseTracking( TRUE );
  handle->setFrameStyle(NoFrame);
  handle->installEventFilter(this);
  handle->show();
  handle->raise();
  init();
}


void KMenuBar::resizeEvent (QResizeEvent *)
{
  if (position == Floating) // What now?
   {
     // Khm... I'm resized from kwm
     // menu bar installs eventFilter on parent, so we don't have
     // to bother with resizing her
     frame->setGeometry( 9, 0, width()-9, height());
     frame->resize(menu->width(), menu->height());
     if (height() != frame->height() ||
         width() != frame->width()+9)
      {
        //warning ("resize");
        resize(frame->width()+9, frame->height());
      }
     handle->setGeometry(0,0,9,height());
   }
  else
   {
     // I will be resized from KtopLevel
	 
	 // MD (17-9-97) change offset from 11 pixels to 9 pixels
     frame->setGeometry (9, 0, width()-9, height());
	 
     if (menu->height() != height())
      {
        frame->resize(frame->width(), menu->height());
        resize(width(), menu->height());
      }
     handle->setGeometry(0,0,9,height());
   }
}

void KMenuBar::ContextCallback( int index )
{
  switch ( index )
   {
    case CONTEXT_TOP:
      setMenuBarPos( Top );
      break;
    case CONTEXT_BOTTOM:
      setMenuBarPos( Bottom );
      break;
    case CONTEXT_FLOAT:
      if (position == Floating){
        setMenuBarPos (lastPosition);
      }
      else {
        setMenuBarPos( Floating );
	move(QCursor::pos());
	show();
      }
      break;
   }
}

void KMenuBar::init()
{
  context = new QPopupMenu( 0, "context" );
  context->insertItem( klocale->translate("Top"),  CONTEXT_TOP );
  context->insertItem( klocale->translate("Bottom"), CONTEXT_BOTTOM );
  context->insertItem( klocale->translate("Floating"), CONTEXT_FLOAT );
  connect( context, SIGNAL( activated( int ) ), this,
	   SLOT( ContextCallback( int ) ) );
  
  position = Top;
  moving = TRUE;

  setLineWidth( 0 );
  resize( Parent->width(), menu->height());
  enableFloating (TRUE);
}


KMenuBar::~KMenuBar()
{
  if (position == Floating)
     recreate (Parent, oldWFlags, QPoint (oldX, oldY), TRUE);
  
  // MD: Get a seg. fault if following line included.
  // Sven recommeds, as a temporary measure, remove it.
  //delete context; 
}

void KMenuBar::mousePressEvent ( QMouseEvent * )
{
}

void KMenuBar::paintEvent(QPaintEvent *)
{
}

void KMenuBar::closeEvent (QCloseEvent *e)
{
  if (position == Floating)
   {
     position = lastPosition;
     recreate (Parent, oldWFlags, QPoint (oldX, oldY), TRUE);
     context->changeItem (klocale->translate("Float"), CONTEXT_FLOAT);
     emit moved (position);
     e->ignore();
     return;
   }
  e->accept();
}

void KMenuBar::leaveEvent (QEvent *e){
  QApplication::sendEvent(menu, e);
}


bool KMenuBar::eventFilter(QObject *ob, QEvent *ev){
  QPoint p;
  if (ob == handle){
    if (ev->type() == Event_MouseButtonPress){
      pointerOffset = mapFromGlobal(handle->mapToGlobal(((QMouseEvent*)ev)->pos()));
      if ( moving && ((QMouseEvent*)ev)->button() != LeftButton)
	context->popup( handle->mapToGlobal(((QMouseEvent*)ev)->pos()), 0 );
      else
	handle->grabMouse(sizeAllCursor);
      return TRUE;
    }
    if (ev->type() == Event_MouseButtonRelease){
      handle->releaseMouse();
    }
    if (ev->type() == Event_MouseMove){
      if (!moving || mouseGrabber() != handle)
	return TRUE;
      if (position != Floating){
	p = mapFromGlobal(QCursor::pos()) - pointerOffset;
	if (p.x()*p.x()+p.y()*p.y()<169)
	  return TRUE;
	XUngrabPointer( qt_xdisplay(), CurrentTime );
 	setMenuBarPos(Floating);
	show();
	QApplication::syncX();
	while(XGrabPointer( qt_xdisplay(), handle->winId(), TRUE,
			    ButtonPressMask | ButtonReleaseMask |
			    PointerMotionMask | EnterWindowMask | LeaveWindowMask,
			    GrabModeAsync, GrabModeAsync,
			    None, sizeAllCursor.handle(), 
			    CurrentTime ) != GrabSuccess);
	handle->grabMouse(sizeAllCursor);
      }
      move(QCursor::pos() - pointerOffset);    
      p = QCursor::pos() - pointerOffset - (Parent->mapToGlobal(QPoint(0,0)) + parentOffset);
      if (p.x()*p.x()+p.y()*p.y()<169){
	releaseMouse();
	setMenuBarPos(lastPosition);
	QApplication::syncX();
	while(XGrabPointer( qt_xdisplay(), handle->winId(), TRUE,
			    ButtonPressMask | ButtonReleaseMask |
			    PointerMotionMask | EnterWindowMask | LeaveWindowMask,
			    GrabModeAsync, GrabModeAsync,
			    None, sizeAllCursor.handle(),
			    CurrentTime ) != GrabSuccess);
	handle->grabMouse(sizeAllCursor);
      }
      return TRUE;
    }
    if (ev->type() == Event_Paint){
      QColorGroup g = QWidget::colorGroup();
      QPainter paint(handle); 
      int stipple_height;
      qDrawShadePanel( &paint, 0, 0, 9, handle->height(),
                       g , FALSE, 1);
      paint.setPen( g.light() );
      stipple_height = 3;
      while ( stipple_height < handle->height()-3 ) {
	paint.drawPoint( 1, stipple_height+1);
	paint.drawPoint( 4, stipple_height);
	stipple_height+=3;
      }
      paint.setPen( g.dark() );
      stipple_height = 4;
      while ( stipple_height < handle->height()-3 ) {
	paint.drawPoint( 2, stipple_height+1);
	paint.drawPoint( 5, stipple_height);
	stipple_height+=3;
      }
      return TRUE;
    }
  }
  return FALSE;
}

void KMenuBar::enableMoving(bool flag)
{
  moving = flag; 
}

void KMenuBar::setMenuBarPos(menuPosition mpos)
{
  if (position != mpos)
   {
     if (mpos == Floating)
      {
        lastPosition = position;
        position = mpos;
        oldX = x();
        oldY = y();
        oldWFlags = getWFlags();
	QPoint p = mapToGlobal(QPoint(0,0));
	parentOffset = pos();
        hide();
        recreate(0, 0,
                 p, FALSE);
 	XSetTransientForHint( qt_xdisplay(), winId(), Parent->topLevelWidget()->winId());
	KWM::setDecoration(winId(), 2);
	KWM::moveToDesktop(winId(), KWM::desktop(Parent->winId()));
	setCaption(""); // this triggers a qt bug
	if (title){
	  setCaption(title);
	}
	else {
	  QString s = Parent->caption();
	  s.append(" [menu]");
	  setCaption(s);
	}
	setFrameStyle( NoFrame);
	menu->setFrameStyle( NoFrame) ;
        context->changeItem (klocale->translate("UnFloat"), CONTEXT_FLOAT);
        emit moved (mpos);
        return;
      }
     else if (position == Floating) // was floating
      {
        position = mpos;
        hide();
	setFrameStyle(NoFrame);
	menu->setFrameStyle(oldMenuFrameStyle);
        recreate(Parent, oldWFlags, QPoint(oldX, oldY), TRUE);
        context->changeItem (klocale->translate("Float"), CONTEXT_FLOAT);
        emit moved (mpos);
        return;
      }
     else
      {
        position = mpos;
        emit moved ( mpos );
        return;
      }
   }
}

void KMenuBar::enableFloating (bool arrrrrrgh)
{
  context->setItemEnabled (CONTEXT_FLOAT, arrrrrrgh);
}

/*******************************************************/

uint KMenuBar::count()
{
  return menu->count();
}

int KMenuBar::insertItem(const char *text,
               const QObject *receiver, const char *member,
               int accel)
{
  return menu->insertItem(text, receiver, member, accel);
}

int KMenuBar::insertItem( const char *text, int id, int index)
{
  return menu->insertItem(text, id, index);
}
int KMenuBar::insertItem( const char *text, QPopupMenu *popup,
                          int id, int index)
{
  return menu->insertItem(text, popup, id, index);
}

void KMenuBar::insertSeparator(int index)
{
  menu->insertSeparator(index);
}

void KMenuBar::removeItem( int id )
{
  menu->removeItem(id);
}
void KMenuBar::removeItemAt( int index )
{
  menu->removeItemAt(index);
}
void KMenuBar::clear()
{
  menu->clear();
}

int KMenuBar::accel( int id )
{
  return menu->accel(id);
}
void KMenuBar::setAccel( int key, int id )
{
  menu->setAccel(key, id);
}

const char *KMenuBar::text( int id )
{
  return menu->text(id);
}

void KMenuBar::changeItem( const char *text, int id )
{
  menu->changeItem(text, id);
}

void KMenuBar::setItemChecked(int id , bool flag)
{
  menu->setItemChecked(id , flag);
}

void KMenuBar::setItemEnabled(int id, bool flag)
{
  menu->setItemEnabled(id, flag);
}


void KMenuBar::slotActivated (int id)
{
  emit activated(id);
}

void KMenuBar::slotHighlighted (int id)
{
  emit highlighted (id);
}
