/*
 * system_dialog.cc
 *
 * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai
 * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with blwm; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "main.h"
#include "misc.h"
#include "blwm.h"
#include "system_dialog.h"
#include "radio_button.h"
#include "radio_set.h"
#include "string_button.h"
#include "blwmrc.h"
#include "image.h"

SystemDialog::SystemDialog(const Rect& rc)
: Dialog(rc)
{
  XSetWindowAttributes attributes;
  unsigned long valueMask;
  
  attributes.background_pixel = DialogColor.pixel;
  attributes.override_redirect = True;
  attributes.event_mask = ExposureMask;
  valueMask = CWBackPixel | CWOverrideRedirect | CWEventMask;

  parent = XCreateWindow(display, root,
			 rc.x - 3, rc.y - 4 - TITLE_HEIGHT / 2,
			 rc.width + 6, rc.height + 7 + TITLE_HEIGHT,
			 0, CopyFromParent, InputOutput, CopyFromParent,
			 valueMask, &attributes);

  attributes.background_pixel = TitlebarActiveColor.pixel;
  valueMask = CWBackPixel | CWEventMask;

  title = XCreateWindow(display, parent,
			3, 3, rc.width, TITLE_HEIGHT,
			0, CopyFromParent, InputOutput, CopyFromParent,
			valueMask, &attributes);

  if (GradTitlebar && rc.width > 1) {
    Pixmap pixGrad = CreateGradPixmap(gradActivePattern, rc.width, title);
    XSetWindowBackgroundPixmap(display, title, pixGrad);
    XFreePixmap(display, pixGrad);
  }

  XReparentWindow(display, frame, parent, 3, 4 + TITLE_HEIGHT);

  for (int i = 0; i < 256; i++)
    scKeyTable[i] = NO_ID;

  sbNum = rsNum = stNum = ipNum = 0;
}

SystemDialog::~SystemDialog()
{
  int i;

  for (i = 0; i < sbNum; i++)
    delete sb[i];
  if (sbNum > 0)
    delete [] sb;

  for (i = 0; i < rsNum; i++)
    delete rs[i];
  if (rsNum > 0)
    delete [] rs;

  for (i = 0; i < stNum; i++)
    delete st[i];
  if (stNum > 0)
    delete [] st;

  for (i = 0; i < ipNum; i++)
    delete ip[i];
  if (ipNum > 0)
    delete [] ip;

  XUnmapWindow(display, frame);
  XReparentWindow(display, frame, root, 0, 0);
  XDestroyWindow(display, parent);
}

void SystemDialog::SetRect(const Rect& rect)
{
  Dialog::SetRect(Rect(3, 4 + TITLE_HEIGHT, rect.width, rect.height));

  XMoveResizeWindow(display, parent,
		    rect.x - 3, rect.y - 4 - TITLE_HEIGHT / 2,
		    rect.width + 6, rect.height + 7 + TITLE_HEIGHT);

  XMoveResizeWindow(display, title,
		    3, 3, rect.width, TITLE_HEIGHT);

  if (GradTitlebar) {
    Pixmap pixGrad = CreateGradPixmap(gradActivePattern, rect.width, title);
    XSetWindowBackgroundPixmap(display, title, pixGrad);
    XFreePixmap(display, pixGrad);
  }
}

/*
 * CreateDialogResource --
 *   Create resources for system dialog.
 */
void SystemDialog::CreateDialogResource(DialogRes** dr, int drNum)
{
  RadioButton** rb = NULL;
  int i, nRb = 0, nSb = 0, nRs = 0, nSt = 0, nIp = 0;

  for (i = 0; i < drNum; i++) {
    ASSERT(dr[i]);
    switch (dr[i]->kind) {
    case STRINGBUTTON:
      sbNum++;
      break;

    case RADIOSET:
      rsNum++;
      break;

    case STATICTEXT:
      stNum++;
      break;

    case ICONPIXMAP:
      ipNum++;
      break;

    default:
      break;
    }
  }

  if (sbNum > 0)
    sb = new StringButton*[sbNum];
  if (rsNum > 0)
    rs = new RadioSet*[rsNum];
  if (stNum > 0)
    st = new StaticText*[stNum];
  if (ipNum > 0)
    ip = new IconPixmap*[ipNum];

  if (drNum > 0)
    rb = new RadioButton*[drNum];

  for (i = 0; i < drNum; i++) {
    ASSERT(dr[i]);
    switch (dr[i]->kind) {
    case STRINGBUTTON:
      ASSERT(nSb < sbNum);
      sb[nSb] = new StringButton(frame, dr[i]->rc, dr[i]->str, dr[i]->fs,
				   dr[i]->rid);
      SetShortcutKeyTable(dr[i]->str, dr[i]->rid);

      if (DialogImage) {
	sb[nSb]->SetBgImage(imgDialog, Point(dr[i]->rc.x, dr[i]->rc.y));
	sb[nSb]->SetBgActiveImage(imgDialog,
				  Point(dr[i]->rc.x, dr[i]->rc.y - 1));
      }

      nSb++;
      break;
      
    case RADIOBUTTON:
      ASSERT(nRb < drNum);
      rb[nRb++] = new RadioButton(frame, Point(dr[i]->rc.x, dr[i]->rc.y),
				  dr[i]->str, dr[i]->fs, dr[i]->rid);
      break;

    case RADIOSET:
      ASSERT(nRs < rsNum);
      rs[nRs++] = new RadioSet(rb, nRb, dr[i]->rid, dr[i]->initId);
      nRb = 0;
      break;

    case STATICTEXT:
      ASSERT(nSt < stNum);
      st[nSt++] = new StaticText(Point(dr[i]->rc.x, dr[i]->rc.y), dr[i]->str,
				 dr[i]->fs);
      break;

    case ICONPIXMAP:
      ASSERT(nIp < ipNum);
      ip[nIp++] = new IconPixmap(dr[i]->img,
				 Point(dr[i]->rc.x, dr[i]->rc.y));
      break;
    }
  }
}

void SystemDialog::MapDialog()
{
  int i;

  XMapRaised(display, parent);
  XMapWindow(display, title);

  Dialog::MapDialog();

  for (i = 0; i < sbNum; i++) {
    ASSERT(sb[i]);
    sb[i]->MapButton();
  }
  for (i = 0; i < rsNum; i++) {
    ASSERT(rs[i]);
    rs[i]->MapRadioButtons();
  }
}

void SystemDialog::UnmapDialog()
{
  Dialog::UnmapDialog();

  XUnmapWindow(display, parent);
}

/*
 * DrawDialog --
 *   Draw the dialog frame.
 */
void SystemDialog::DrawDialog()
{
  XPoint xp[3];
  int width, height;

  width = rc.width + 6;
  height = rc.height + 7 + TITLE_HEIGHT;

  xp[0].x = width - 2;
  xp[0].y = 0;
  xp[1].x = 0;
  xp[1].y = 0;
  xp[2].x = 0;
  xp[2].y = height - 2;

  XSetForeground(display, ::gc, gray.pixel);
  XDrawLines(display, parent, ::gc, xp, 3, CoordModeOrigin);
  
  xp[0].x = width - 1;
  xp[0].y = 0;
  xp[1].x = width - 1;
  xp[1].y = height - 1;
  xp[2].x = 0;
  xp[2].y = height - 1;

  XSetForeground(display, ::gc, darkGrey.pixel);
  XDrawLines(display, parent, ::gc, xp, 3, CoordModeOrigin);

  xp[0].x = width - 3;
  xp[0].y = 1;
  xp[1].x = 1;
  xp[1].y = 1;
  xp[2].x = 1;
  xp[2].y = height - 3;

  XSetForeground(display, ::gc, white.pixel);
  XDrawLines(display, parent, ::gc, xp, 3, CoordModeOrigin);
  
  xp[0].x = width - 2;
  xp[0].y = 1;
  xp[1].x = width - 2;
  xp[1].y = height - 2;
  xp[2].x = 1;
  xp[2].y = height - 2;

  XSetForeground(display, ::gc, darkGray.pixel);
  XDrawLines(display, parent, ::gc, xp, 3, CoordModeOrigin);
}  

/*
 * DrawTitle --
 *   Draw the title.
 */
void SystemDialog::DrawTitle()
{
  XRectangle ink, log;
  Point ptTitle;

  XClearWindow(display, title);

  XmbTextExtents(fsTitle, name, strlen(name), &ink, &log);
  ptTitle.x = 4;
  ptTitle.y = (TITLE_HEIGHT-log.height)/2 - log.y;
  
  XSetForeground(display, ::gc, white.pixel);
  XmbDrawString(display, title, fsTitle, ::gc, ptTitle.x, ptTitle.y,
		name, strlen(name));
}  

/*
 * GetSelectableRB --
 *   Get selectable radio set.
 */
ResourceId SystemDialog::GetSelectedRB(ResourceId idRadioSet)
{
  for (int i = 0; i < rsNum; i++) {
    ASSERT(rs[i]);
    if (rs[i]->GetResId() == idRadioSet)
      return rs[i]->GetFocusRB();
  }

  return NO_ID;
}

/*
 * DrawClientWin --
 *   Draw client window.
 */
void SystemDialog::DrawClientWin()
{
  int i;
  XRectangle ink, log;

  /*
   * Draw texts.
   */
  for (i = 0; i < stNum; i++) {
    ASSERT(st[i]);
    XmbTextExtents(st[i]->fs, st[i]->text, strlen(st[i]->text), &ink, &log);
    XSetForeground(display, ::gc, DialogStringColor.pixel);
    XmbDrawString(display, frame, st[i]->fs, ::gc, st[i]->pt.x,
		  st[i]->pt.y-log.y, st[i]->text, strlen(st[i]->text));
  }

  /*
   * Draw icon pixmaps.
   */
  for (i = 0; i < ipNum; i++) {
    ASSERT(ip[i]);
    ip[i]->img->Display(frame, ip[i]->pt);
  }
}

/*
 * Exposure --
 *   Process expose event.
 */
void SystemDialog::Exposure(Window win)
{
  StringButton* sb;
  RadioButton* rb;

  if (XFindContext(display, win, Button::context, (caddr_t*)&sb) == XCSUCCESS)
    sb->DrawButton();
  else if (XFindContext(display, win, RadioButton::context, (caddr_t*)&rb)
                                                                 == XCSUCCESS)
    rb->DrawButton(True);
  else {
    if (win == parent)
      DrawDialog();
    else if (win == title)
      DrawTitle();
    else if (win == frame)
      DrawClientWin();
  }
}

/*
 * Button1Press --
 *   Process the press of button1(mouse left button).
 */
ResourceId SystemDialog::Button1Press(Window win)
{
  StringButton* sb;
  RadioButton* rb;

  if (XFindContext(display, win, Button::context, (caddr_t*)&sb)
                                                               == XCSUCCESS) {
    if (sb->GetParent() == frame) {
      sb->Button1Press();
      if (sb->IsTriggered())
	return sb->GetResId();
    }
  }
  else if (XFindContext(display, win, RadioButton::context, (caddr_t*)&rb)
	                                                        == XCSUCCESS)
    rb->Button1Press();
  else
    XAllowEvents(display, ReplayPointer, CurrentTime);

  return NO_ID;
}

ResourceId SystemDialog::FindShortCutKey(char key)
{
  ResourceId id;

  if (key >= 'a' && key <= 'z')
    key -= 0x20;

  id = scKeyTable[key];

  return id;
}

void SystemDialog::SetShortcutKeyTable(char* str, ResourceId id)
{
  char* keyStr = strstr(str, "\\&");
  char key;

  if (keyStr) {
    key = (unsigned char)*(keyStr + 2);
    if (key >= 'a' && key <= 'z')
      key -= 0x20;
    scKeyTable[key] = id;
  }
}


syntax highlighted by Code2HTML, v. 0.9.1