/*****************************************************************************
 * scrollinglist.c: Demonstrate the ScrollingList widget.
 *
 *         From:
 *                   The X Window System, 
 *            Programming and Applications with Xt
 *                   OPEN LOOK Edition
 *         by
 *              Douglas Young & John Pew
 *              Prentice Hall, 1991
 *
 *              Example described on pages: 
 *
 *
 *  Copyright 1991 by Prentice Hall
 *  All Rights Reserved
 *
 * This code is based on the OPEN LOOK Intrinsics Toolkit (OLIT) and 
 * the X Window System
 *
 * Permission to use, copy, modify, and distribute this software for 
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation.
 *
 * Prentice Hall and the authors disclaim all warranties with regard to 
 * this software, including all implied warranties of merchantability and 
 * fitness.
 * In no event shall Prentice Hall or the authors be liable for any special,
 * indirect or consequential damages or any damages whatsoever resulting from 
 * loss of use, data or profits, whether in an action of contract, negligence 
 * or other tortious action, arising out of or in connection with the use 
 * or performance of this software.
 *
 * OPEN LOOK is a trademark of UNIX System Laboratories.
 * X Window System is a trademark of the Massachusetts Institute of Technology
 ****************************************************************************/

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xol/OpenLook.h>
#include <Xol/RubberTile.h>
#include <Xol/ScrollingL.h>
#include <Xol/ControlAre.h>
#include <Xol/OblongButt.h>
#include <sys/dirent.h>
#include <sys/dir.h>

OlListToken (*AddItem)();
void        (*DeleteItem)();
void        (*TouchItem)();
void        (*UpdateView)();
void        (*ViewItem)();

typedef struct _file {
  String         filename;
  OlListToken    token;
  struct _file *next;
} file;

file *head = NULL;     /* head of the list */
OlListToken lasttoken = NULL;

main(argc, argv)
  int argc;
  char *argv[];
{
  int        n;
  Arg        wargs[10];
  Widget     toplevel, rt, sl, ca, delete, findcurrent;
  String     directory;
  void       initList(), current_callback(), delete_callback();
  void       findcurrent_callback();

  toplevel = OlInitialize(argv[0], "Scrollinglist", NULL, 0, 
                          &argc, argv);
  /*
   * Get the command line argument, if any
   */
  directory = argv[1];
  rt = XtCreateManagedWidget("rt", rubberTileWidgetClass,
                              toplevel, NULL, 0);
  /*
   * Create the ScrollingList widget
   */
  n = 0;
  XtSetArg(wargs[n], XtNviewHeight, 6); n++;
  XtSetArg(wargs[n], XtNselectable, FALSE); n++;
  sl = XtCreateManagedWidget("sl", scrollingListWidgetClass,
                                  rt, wargs, n);
  n = 0;
  XtSetArg(wargs[n], XtNapplAddItem,    &AddItem); n++;
  XtSetArg(wargs[n], XtNapplTouchItem,  &TouchItem); n++;
  XtSetArg(wargs[n], XtNapplUpdateView, &UpdateView); n++;
  XtSetArg(wargs[n], XtNapplDeleteItem, &DeleteItem); n++;
  XtSetArg(wargs[n], XtNapplViewItem,   &ViewItem); n++;
  XtGetValues(sl, wargs, n);
  XtAddCallback(sl, XtNuserMakeCurrent, current_callback, NULL);
  /*
   * Create the ControlArea and Buttons
   */
  ca = XtCreateManagedWidget("ca", controlAreaWidgetClass,
                              rt, NULL, 0);
  delete = XtCreateManagedWidget("Delete", 
                                 oblongButtonWidgetClass,
                                 ca, NULL, 0);
  XtAddCallback(delete, XtNselect, delete_callback, sl);
  findcurrent = XtCreateManagedWidget("Current", 
                                      oblongButtonWidgetClass,
                                      ca, NULL, 0);
  XtAddCallback(findcurrent, XtNselect, 
                findcurrent_callback, sl);
  initList(sl, directory);

  XtRealizeWidget(toplevel);
  XtMainLoop();
}

void
initList(sl, directory)
  Widget sl;
  String directory;
{
  OlListItem     item;
  short          count = 0;
  DIR           *dirp;
  struct direct *dp;
  file          *filep, *prevp;

  if(directory == NULL)
    directory = ".";
  dirp = opendir(directory);
  if(dirp == NULL) {
    perror(directory);
    exit(-1);
  }
  (*UpdateView)(sl, FALSE);
  for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
    filep = (file *)XtCalloc(1, sizeof(file));
    if(head == NULL)
      head = prevp = filep;
    else {
      prevp->next = filep;
      prevp = filep;
    }
    filep->next = NULL;
    item.label_type = OL_STRING;
    item.attr = count;
    item.label = filep->filename = XtNewString(dp->d_name);
    item.mnemonic = NULL;
    filep->token = (*AddItem)(sl, 0, 0, item);
    count++;
  }
  closedir(dirp);
  (*UpdateView)(sl, TRUE);
}

void
current_callback(w, client_data, call_data)
  Widget w;
  XtPointer client_data, call_data;
{
  OlListToken token = (OlListToken)call_data;
  OlListItem *newItem = OlListItemPointer(token);
  OlListItem *lastItem;

  if(lasttoken == token) {      /* unset current choice */
    newItem->attr &= ~OL_LIST_ATTR_CURRENT;
    (*TouchItem)(w, token);
    lasttoken = NULL;
    return;
  }

  if(lasttoken) {
    lastItem = OlListItemPointer(lasttoken);
    if(lastItem->attr & OL_LIST_ATTR_CURRENT)
      lastItem->attr &= ~OL_LIST_ATTR_CURRENT;
    (*TouchItem)(w, lasttoken);
  }
  newItem->attr |= OL_LIST_ATTR_CURRENT;
  (*TouchItem)(w, token);
  lasttoken = token;
}

void
delete_callback(w, client_data, call_data)
  Widget    w;
  XtPointer client_data, call_data;
{
  Widget      sl = (Widget)client_data;
  file       *filep, *prevp;
  OlListItem *fileItem;

  filep = prevp = head;
  while(filep) {
    fileItem = OlListItemPointer(filep->token);
    if(fileItem->attr & OL_LIST_ATTR_CURRENT) {
      (*DeleteItem)(sl, filep->token);
      if(filep == head) {
        head = filep->next;
        XtFree(filep);
        filep = prevp = head;
      } else {
        prevp->next = filep->next;
        XtFree(filep);
        filep = prevp->next;
      }
    } else {
      prevp = filep;
      filep = filep->next;
    }
  }
  lasttoken = NULL;
}

void
findcurrent_callback(w, client_data, call_data)
  Widget w;
  XtPointer client_data, call_data;
{
  Widget sl = (Widget)client_data;

  if(lasttoken)
    (*ViewItem)(sl, lasttoken);
}
