#include <xclass/OXWidgets.h>
#include "OXNameList.h"

const char * _menu_name;

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

extern OLayoutHints * topexpandxlayout;

OXNameList::OXNameList(const OXWindow *p, OXPopupMenu *popup, int w, int h,
		     unsigned int options)
  : OXVerticalFrame(p, w, h, options | VERTICAL_FRAME) {

    _popup = popup;
    _stick = True;
    _current = NULL;

    XGrabButton(GetDisplay(), Button1, AnyModifier, _id, True,
		ButtonPressMask | ButtonReleaseMask |
		EnterWindowMask,
		GrabModeAsync, GrabModeAsync, None, None);
  }

OXNameList::~OXNameList() {
  SListFrameElt *ptr;
  OXName *t;
  
  for (ptr = _flist; ptr != NULL; ptr = ptr->next) {
    t = (OXName *) ptr->frame;
  }
}

int OXNameList::HandleMotion(XMotionEvent *event) {
  SListFrameElt *ptr;
  int dummy;
  Window wtarget;
  OXName *target;

  _stick = False; // use some threshold!

  XTranslateCoordinates(GetDisplay(), _id, _id, event->x, event->y,
                        &dummy, &dummy, &wtarget);
  target = (OXName*)_client->GetWindowById(wtarget);

  if (target != NULL && target != _current) {
  // Deactivate all others :
    for (ptr = _flist; ptr != NULL; ptr = ptr->next)
      ((OXMenuTitle*)ptr->frame)->SetState(False);

    target->SetState(True);
    _stick = True;
    _current = target;
  }

  return True;
}

int OXNameList::HandleButton(XButtonEvent *event) {
  SListFrameElt *ptr;
  int dummy;
  Window wtarget;

  // Here we are looking for a _child_ of a menu bar, so it can _ONLY_ be
  // a MenuTitle : BEWARE !

  OXName *target;

  // We don't need to check the button number as XGrabButton will
  // only allow button1 events

  if (event->type == ButtonPress) {

    XTranslateCoordinates(GetDisplay(), _id, _id, event->x, event->y,
                          &dummy, &dummy, &wtarget);
    target = (OXName*)_client->GetWindowById(wtarget);

    if (target != NULL) {
      _stick = True;

      if (target != _current) {
        // Deactivate all others :
        for (ptr = _flist; ptr != NULL; ptr = ptr->next)
          ((OXName*)ptr->frame)->SetState(False);

        target->SetState(True);
        _stick = True;
        _current = target;

        XGrabPointer(GetDisplay(), _id, True,
                     ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
                     GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
      }
    }
  }

  if (event->type == ButtonRelease) {
    if (_stick) {
      _stick = False;
      return True;
    }
    XUngrabPointer(GetDisplay(), CurrentTime);

    for (ptr = _flist; ptr != NULL; ptr = ptr->next)
      ((OXName*)ptr->frame)->SetState(False);

    if (_current != NULL) {
      target = _current; /* tricky, because WaitFor */
      _current = NULL;
      target->DoSendMessage();
    }
  }

  return True;
}

void OXNameList::AddPopup(OHotString *s, OXPopupMenu *menu, OLayoutHints *l) {
  OXName * name;
  AddFrame(name = new OXName(this, s, menu), l);
  name->Associate(_msgWindow);
}

OXName *  OXNameList::GetName(char *s) {
  SListFrameElt *ptr;
  OXName *t, *returnval = NULL;

  for (ptr = _flist; ptr != NULL; ptr = ptr->next) {
    t = (OXName *) ptr->frame;
    if (!strcasecmp(s, t->_label->GetString()))
      returnval = t;
  }
  return(returnval);
}

void OXNameList::AddName(char *s) {
  if (!GetName(s)) {
    AddPopup(new OHotString(s), _popup, topexpandxlayout);
    MapSubwindows();
    Layout();
  }
}

void OXNameList::RemoveName(char *s) {
  OXName * t = GetName(s);

  if (t) {
    RemoveFrame(t);
    XClearWindow(_client->GetDisplay(), t->_id);
    delete t;
    MapSubwindows();
    Layout();
  }
}

void OXNameList::ChangeName(char *o, char *n) {
  OXName * t = GetName(o);

  if (t) {
    delete (t->_label);
    t->_label = new OHotString(n);
    t->_DoRedraw();
  }
}

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

OXName::OXName(const OXWindow *p, OHotString *s, OXPopupMenu *menu, 
	       GC norm, XFontStruct *font, unsigned int options) :
  OXMenuTitle(p, s, menu, norm, font, options) {
  int tw;

  tw = XTextWidth(_fontStruct, _label->GetString(), _label->GetLength());

  Resize(tw + 8, _fontStruct->max_bounds.ascent +
                 _fontStruct->max_bounds.descent + 4);
} 

void OXName::SetState(int state) {
  _state = state;
  if (state) {
    if (_menu != NULL) {
      int ax, ay;
      Window wdummy;

      XTranslateCoordinates(GetDisplay(), _id, (_menu->GetParent())->GetId(),
			0, 0, &ax, &ay, &wdummy);

      // Place the menu just under the window :
      _menu->PlaceMenu(ax+_w+1, ay+2, True, False); //True);
    }
  } else {
    if (_menu != NULL) {
      _ID = _menu->EndMenu();
    }
  }
  _client->NeedRedraw(this);
}

void OXName::_DoRedraw() {
  const char * name = _label->GetString();
  int x, y;

  x = (_w - XTextWidth(_fontStruct, name, strlen(name))) >> 1;
  y = 2;
  if (_state) {
    _options |= SUNKEN_FRAME;
    _options &= ~RAISED_FRAME;
  } else {
    _options |= RAISED_FRAME;
    _options &= ~SUNKEN_FRAME;
  }
  OXFrame::_DoRedraw();
  if (_state) {
    _label->Draw(GetDisplay(), _id, _normGC,
                 x+1, y + _fontStruct->max_bounds.ascent+1);
  } else {
    _label->Draw(GetDisplay(), _id, _normGC,
                 x, y + _fontStruct->max_bounds.ascent);
  }
}

void OXName::DoSendMessage() {
  _menu_name = _label->GetString();
  if (_ID != -1)
    SendMessage(_msgWindow, MK_MSG(XC_COMMAND, CM_MENU), _ID, 0L);
}
