Logo Search packages:      
Sourcecode: xaos version File versions  Download package

filesel.c

#ifndef _plan9_
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


#include <config.h>
#include <filter.h>
#include <fractal.h>
#include <ui_helper.h>
#include <xmenu.h>
#include <grlib.h>
#include <ui.h>
#include <xerror.h>
#include <misc-f.h>
#include "uiint.h"

#ifdef HAVE_GETTEXT
#include <libintl.h>
#else
#define gettext(STRING) STRING
#endif

static char **dirs;
static char **sdirs;
static int ndirs;
static char **names;
static char **snames;
static int nnames;

struct ui_textdata *dir, *filename;
static char lastdir[256];
static char *currdir;

static struct uih_window *filew;
static CONST char *mask;
static void (*callback) (CONST char *name, int succ);
int filevisible;
static int filex, filey, filewidth, fileheight;

#define ADIR 0
#define AFILELIST 1
#define ADIRLIST 2
#define AFILE 3
#define AOK 4

#define DIRSTART (filey+BORDERHEIGHT)
#define LISTSTART (DIRSTART+BUTTONHEIGHT+BORDERHEIGHT)
#define LISTEND (FILESTART-BORDERHEIGHT)
#define FILESTART (OKSTART-BORDERHEIGHT-BUTTONHEIGHT)
#define OKSTART (filey+fileheight-BORDERHEIGHT-BUTTONHEIGHT)
#define SCROLLWIDTH 10

#define LISTWIDTH ((filewidth-10*BORDERWIDTH-2*SCROLLWIDTH)/2)

#define NVISIBLE ((LISTEND-LISTSTART-2*BORDERHEIGHT)/xtextheight(uih->font))

static int selectedname;
static int selecteddir;
static int namestart;
static int dirstart;

static int pressedbutton;
static int activebutton;
static int active;

static void
ui_freenames (void)
{
  int i;
  selectedname = 0;
  selecteddir = 0;
  if (nnames)
    {
      for (i = 0; i < nnames; i++)
      free (names[i]), free (snames[i]);
      free (names);
      nnames = 0;
    }
  if (ndirs)
    {
      for (i = 0; i < ndirs; i++)
      free (dirs[i]), free (sdirs[i]);
      free (dirs);
      ndirs = 0;
    }
  if (snames)
    free (snames), snames = NULL;
  if (sdirs)
    free (sdirs), sdirs = NULL;
}
static int
compar (CONST void *a, CONST void *b)
{
  return (strcmp (*(CONST char **) a, *(CONST char **) b));
}
static char **
ui_mksnames (int nnames, char **names, int width)
{
  char **snames = NULL;
  int i;
  if (nnames)
    {
      qsort (names, nnames, sizeof (*names),    /*(int (*)(CONST void *, CONST
                                       void *))strcmp */ compar);
      snames = (char **) malloc (sizeof (*snames) * nnames);
      for (i = 0; i < nnames; i++)
      {
        if (xtextwidth (uih->font, names[i]) <= width)
          snames[i] = mystrdup (names[i]);
        else
          {
            int y;
            int swidth = 0;
            int len = (int) strlen (names[i]);
            snames[i] = (char *) malloc (strlen (names[i]) + 2);
            for (y = len - 4; y < len; y++)
            swidth += xtextcharw (uih->font, names[i][y]);
            swidth += xtextcharw (uih->font, '|');
            y = 0;
            while (swidth < width)
            {
              snames[i][y] = names[i][y];
              swidth += xtextcharw (uih->font, names[i][y]);
              y++;
            }
            snames[i][y - 1] = '|';
            snames[i][y] = 0;
            strcat (snames[i], names[i] + len - 4);
          }
      }
    }
  return (snames);
}
static void
ui_buildnames (int width)
{
  ui_freenames ();
  xio_getfiles (currdir, &names, &dirs, &nnames, &ndirs);
  if (snames)
    free (snames), snames = NULL;
  if (sdirs)
    free (sdirs), sdirs = NULL;
  snames = ui_mksnames (nnames, names, width);
  sdirs = ui_mksnames (ndirs, dirs, width);
}

void
ui_closefilesel (int success)
{
  char *text =
    (char *) malloc ((int) strlen (filename->text) + (int) strlen (currdir) +
                 3);
  filevisible = 0;
  uih_removew (uih, filew);
  ui_freenames ();
  sprintf (text, "%s" XIO_PATHSEPSTR "%s", currdir, filename->text);
  ui_closetext (dir);
  ui_closetext (filename);
  strcpy (lastdir, currdir);
  free (currdir);
  callback (text, success);
  free (text);
  uih->display = 1;
  ui_freenames ();
}
static void
filepos (uih_context * c, int *x, int *y, int *w, int *h, void *data)
{
  *x = filex;
  *y = filey;
  *w = filewidth;
  *h = fileheight;
}
static void
drawfile (uih_context * c, void *data)
{
  int i;
  int ypos;
  int h = xtextheight (uih->font);
  uih_drawborder (uih, filex + BORDERWIDTH, DIRSTART,
              filewidth - 2 * BORDERWIDTH, BUTTONHEIGHT,
              BORDER_PRESSED | BORDER_LIGHT);
  uih_drawborder (uih, filex + BORDERWIDTH, FILESTART,
              filewidth - 2 * BORDERWIDTH, BUTTONHEIGHT,
              BORDER_PRESSED | BORDER_LIGHT);

  ui_drawbutton ("OK", (pressedbutton == 0), active == AOK
             && activebutton == 0, filex + BORDERWIDTH,
             filex + filewidth / 2 - BORDERWIDTH, OKSTART);
  ui_drawbutton (gettext ("Cancel"), (pressedbutton == 1), active == AOK
             && activebutton == 1, filex + filewidth / 2 + BORDERWIDTH,
             filex + filewidth - BORDERWIDTH, OKSTART);

  uih_drawborder (uih, filex + BORDERWIDTH, LISTSTART,
              LISTWIDTH + 3 * BORDERWIDTH + SCROLLWIDTH,
              LISTEND - LISTSTART, BORDER_PRESSED);
  uih_drawborder (uih, filex + filewidth / 2 + BORDERWIDTH, LISTSTART,
              LISTWIDTH + 3 * BORDERWIDTH + SCROLLWIDTH,
              LISTEND - LISTSTART, BORDER_PRESSED);
  ypos = LISTSTART + BORDERHEIGHT;
  for (i = 0; ypos + h < LISTEND && i + namestart < nnames; i++)
    {
      if (i + namestart == selectedname)
      {
        xrectangle (uih->image, filex + 2 * BORDERWIDTH, ypos, LISTWIDTH, h,
                  (uih->palette->type & BITMAPS) ? BGCOLOR (uih) :
                  LIGHTGRAYCOLOR (uih));
      }
      if (uih->palette->type & BITMAPS)
      xprint (uih->image, uih->font, filex + 2 * BORDERWIDTH, ypos,
            snames[i + namestart],
            i + namestart == selectedname ? FGCOLOR (uih) : BGCOLOR (uih),
            BGCOLOR (uih), TEXT_PRESSED);
      else
      xprint (uih->image, uih->font, filex + 2 * BORDERWIDTH, ypos,
            snames[i + namestart], (i + namestart) == selectedname
            && active == AFILELIST ? SELCOLOR (uih) : FGCOLOR (uih),
            BGCOLOR (uih), 0);
      ypos += h;
    }
  if (nnames)
    {
      int xstart = (namestart) * (LISTEND - LISTSTART) / nnames;
      int xend = (namestart + NVISIBLE) * (LISTEND - LISTSTART) / nnames;
      if (xstart > (LISTEND - LISTSTART - 2 * BORDERHEIGHT))
      xstart = LISTEND - LISTSTART - 2 * BORDERHEIGHT;
      if (xend > (LISTEND - LISTSTART - 2 * BORDERHEIGHT))
      xend = LISTEND - LISTSTART - 2 * BORDERHEIGHT;
      uih_drawborder (uih, filex + LISTWIDTH + 3 * BORDERWIDTH, LISTSTART + xstart + BORDERHEIGHT, SCROLLWIDTH, xend - xstart,      /*1|BORDER_LIGHT */
                  0);
    }

  ypos = LISTSTART + BORDERHEIGHT;
  for (i = 0; ypos + h < LISTEND && i + dirstart < ndirs; i++)
    {
      if (i + dirstart == selecteddir)
      {
        xrectangle (uih->image, filex + filewidth / 2 + 2 * BORDERWIDTH,
                  ypos, LISTWIDTH, h,
                  (uih->palette->type & BITMAPS) ? BGCOLOR (uih) :
                  LIGHTGRAYCOLOR (uih));
      }
      if (uih->palette->type & BITMAPS)
      xprint (uih->image, uih->font,
            filex + filewidth / 2 + 2 * BORDERWIDTH, ypos,
            sdirs[i + dirstart],
            i + dirstart == selecteddir ? FGCOLOR (uih) : BGCOLOR (uih),
            BGCOLOR (uih), TEXT_PRESSED);
      else
      xprint (uih->image, uih->font,
            filex + filewidth / 2 + 2 * BORDERWIDTH, ypos,
            sdirs[i + dirstart], (i + dirstart) == selecteddir
            && active == ADIRLIST ? SELCOLOR (uih) : FGCOLOR (uih),
            BGCOLOR (uih), 0);
      ypos += h;
    }
  if (ndirs)
    {
      int xstart = (dirstart) * (LISTEND - LISTSTART) / ndirs;
      int xend = (dirstart + NVISIBLE) * (LISTEND - LISTSTART) / ndirs;
      if (xstart > (LISTEND - LISTSTART - 2 * BORDERHEIGHT))
      xstart = LISTEND - LISTSTART - 2 * BORDERHEIGHT;
      if (xend > (LISTEND - LISTSTART - 2 * BORDERHEIGHT))
      xend = LISTEND - LISTSTART - 2 * BORDERHEIGHT;
      uih_drawborder (uih, filex + filewidth / 2 + LISTWIDTH + 3 * BORDERWIDTH, LISTSTART + xstart + BORDERHEIGHT, SCROLLWIDTH, xend - xstart,  /*1|BORDER_LIGHT */
                  0);
    }
  ui_drawtext (filename, active == AFILE);
  ui_drawtext (dir, active == ADIR);
}

static void
setname (int name)
{
  ui_closetext (filename);
  filename =
    ui_opentext (filex + 2 * BORDERWIDTH, FILESTART + BORDERHEIGHT,
             filewidth - 4 * BORDERWIDTH, names[name]);
}

#ifdef _WIN32
#define DRIVES
#endif
#ifdef DJGPP
#define DRIVES
#endif
static void
setdir (int name)
{
  char *dirstring = dirs[name];
  char *s = NULL;
  if (dirstring[0] == '.' && !dirstring[1])
    {
      /*do nothing */
      s = mystrdup (currdir);
    }
  else if (dirstring[0] && dirstring[1] && dirstring[0] == '.'
         && dirstring[1] == '.' && !dirstring[2])
    {
      int i = (int) strlen (currdir);
      s =
      (char *) malloc ((int) strlen (dirstring) + (int) strlen (currdir) +
                   2);
      strcpy (s, currdir);
      for (; i >= 0 && s[i] != '/' && s[i] != '\\' && s[i] != XIO_PATHSEP;
         i--);
      if (i < 0)
      free (s), s = NULL;
      else
      s[i] = 0;
    }
  if (s == NULL)
    {
      int i = (int) strlen (currdir);
      s =
      (char *) malloc ((int) strlen (dirstring) + (int) strlen (currdir) +
                   2);
      strcpy (s, currdir);
      if (currdir[i - 1] != '/' && currdir[i - 1] != '\\'
        && currdir[i - 1] != XIO_PATHSEP)
      strcat (s, XIO_PATHSEPSTR);
      strcat (s, dirstring);
      if (!s[0])
      s[0] = XIO_PATHSEP, s[1] = 0;
    }
  free (currdir);
#ifdef DRIVES
  if (strlen (s) == 2
      && ((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z'))
      && s[1] == ':')
    s[2] = XIO_PATHSEP, s[3] = 0;
#endif
  currdir = s;
  ui_closetext (dir);
  dir =
    ui_opentext (filex + 2 * BORDERWIDTH, DIRSTART + BORDERHEIGHT,
             filewidth - 4 * BORDERWIDTH, currdir);
  ui_freenames ();
  ui_buildnames (LISTWIDTH);
  dirstart = 0;
  selecteddir = 0;
  namestart = 0;
  selectedname = 0;
  uih->display = 1;
}
static void
setexactdir (CONST char *dirstring)
{
  free (currdir);
  currdir = mystrdup (dirstring);
  ui_closetext (dir);
  dir =
    ui_opentext (filex + 2 * BORDERWIDTH, DIRSTART + BORDERHEIGHT,
             filewidth - 4 * BORDERWIDTH, currdir);
  ui_freenames ();
  ui_buildnames (LISTWIDTH);
  dirstart = 0;
  selecteddir = 0;
  namestart = 0;
  selectedname = 0;
  uih->display = 1;
}

int
ui_keyfilesel (int k)
{
  if (!filevisible)
    return 0;
  if (k == UIKEY_ESC)
    ui_closefilesel (0);
  else
    switch (active)
      {
      default:
      active = AFILE;
      uih->display = 1;
      break;
      case ADIR:
      if (ui_textkey (dir, k))
        break;
      if (k == '\n' || k == 13)
        {
          active = AFILE;
          setexactdir (dir->text);
          uih->display = 1;
        }
      if (k == UIKEY_UP)
        {
          active = AOK;
          uih->display = 1;
          activebutton = 1;
        }
      if (k == '\t' || k == UIKEY_DOWN)
        {
          active++;
          uih->display = 1;
        }
      break;
      case AFILELIST:
      switch (k)
        {
        case '\t':
        case UIKEY_RIGHT:
          uih->display = 1;
          active = ADIRLIST;
          break;
        case UIKEY_LEFT:
          uih->display = 1;
          active = ADIR;
          break;
        case UIKEY_UP:
          if (selectedname)
            {
            uih->display = 1;
            selectedname--;
            if (selectedname < namestart)
              namestart = selectedname;
            }
          break;
        case UIKEY_DOWN:
          if (selectedname < nnames - 1)
            {
            uih->display = 1;
            selectedname++;
            if (selectedname >= namestart + NVISIBLE)
              namestart = selectedname - NVISIBLE + 1;
            }
          break;
        case UIKEY_HOME:
          if (selectedname)
            {
            uih->display = 1;
            selectedname = namestart = 0;
            }
          break;
        case UIKEY_END:
          if (selectedname < nnames - 1)
            {
            uih->display = 1;
            selectedname = nnames - 1;;
            if (selectedname >= namestart + NVISIBLE)
              namestart = selectedname - NVISIBLE + 1;
            }
          break;
        case '\n':
        case 13:
          setname (selectedname);
          uih->display = 1;
          active = AFILE;
          break;
        }
      break;
      case ADIRLIST:
      switch (k)
        {
        case '\t':
        case UIKEY_RIGHT:
          uih->display = 1;
          active = AFILE;
          break;
        case UIKEY_LEFT:
          uih->display = 1;
          active = AFILELIST;
          break;
        case UIKEY_UP:
          if (selecteddir)
            {
            uih->display = 1;
            selecteddir--;
            if (selecteddir < dirstart)
              dirstart = selecteddir;
            }
          break;
        case UIKEY_DOWN:
          if (selecteddir < ndirs - 1)
            {
            uih->display = 1;
            selecteddir++;
            if (selecteddir >= dirstart + NVISIBLE)
              dirstart = selecteddir - NVISIBLE + 1;
            }
          break;
        case UIKEY_HOME:
          if (selecteddir)
            {
            uih->display = 1;
            selecteddir = dirstart = 0;
            }
          break;
        case UIKEY_END:
          if (selecteddir < ndirs - 1)
            {
            uih->display = 1;
            selecteddir = ndirs - 1;;
            if (selecteddir >= dirstart + NVISIBLE)
              dirstart = selecteddir - NVISIBLE + 1;
            }
          break;
        case '\n':
        case 13:
          setdir (selecteddir);
          uih->display = 1;
          break;
        }
      break;
      case AFILE:
      if (ui_textkey (filename, k))
        break;
      if (k == '\t' || k == UIKEY_DOWN)
        {
          active++;
          uih->display = 1;
          activebutton = 0;
        }
      if (k == UIKEY_UP)
        {
          active--;
          uih->display = 1;
        }

      if (k == '\n' || k == 13)
        {
          ui_closefilesel (1);
        }
      break;
      case AOK:
      if (k == '\n' || k == 13)
        ui_closefilesel (!activebutton);
      if (k == '\t' || k == UIKEY_RIGHT || k == UIKEY_DOWN)
        {
          uih->display = 1;
          activebutton++;
          if (activebutton > 2)
            {
            activebutton = 0;
            active = ADIR;
            }
        }
      if (k == UIKEY_LEFT || k == UIKEY_UP)
        {
          uih->display = 1;
          activebutton--;
          if (activebutton < 0)
            {
            activebutton = 0;
            active = AFILE;
            }
        }
      }
  return 1;
}

int
ui_mousefilesel (int x, int y, int buttons, int flags)
{
  static int grabbed = -1;
  if (!filevisible)
    return 0;
  if (grabbed >= 0 && (flags & MOUSE_DRAG))
    {
      if (!grabbed)
      {
        int pos;
        pos =
          (y - LISTSTART) * nnames / (LISTEND - LISTSTART -
                              2 * BORDERHEIGHT);
        if (pos >= nnames - NVISIBLE)
          pos = nnames - NVISIBLE;
        if (pos < 0)
          pos = 0;
        if (pos != namestart)
          {
            namestart = pos;
            uih->display = 1;
            if (selectedname < pos)
            selectedname = pos;
            if (selectedname >= pos + NVISIBLE)
            selectedname = pos + NVISIBLE - 1;
          }
      }
      else
      {
        int pos;
        pos =
          (y - LISTSTART) * ndirs / (LISTEND - LISTSTART -
                               2 * BORDERHEIGHT);
        if (pos < 0)
          pos = 0;
        if (pos >= ndirs - NVISIBLE)
          pos = ndirs - NVISIBLE;
        if (pos != dirstart)
          {
            dirstart = pos;
            uih->display = 1;
            if (selecteddir < pos)
            selecteddir = pos;
            if (selecteddir >= pos + NVISIBLE)
            selecteddir = pos + NVISIBLE - 1;
          }
      }
    }
  else
    grabbed = -1;
  if (x < filex || y < filey || x > filex + filewidth
      || y > filex + fileheight)
    {
      if (flags & MOUSE_PRESS)
      ui_closefilesel (0);
      return 1;
    }
  if (y < LISTSTART)
    {
      if (pressedbutton != -1)
      pressedbutton = -1, uih->display = 1;
      if ((flags & MOUSE_MOVE) && active != ADIR)
      active = ADIR, uih->display = 1;
      if (flags & MOUSE_PRESS)
      ui_textmouse (dir, x, y);
    }
  else if (y < LISTEND)
    {
      int mouseat = 0;
      if (pressedbutton != -1)
      pressedbutton = -1, uih->display = 1;
      if (x > filex + filewidth / 2)
      mouseat = 1, x -= filewidth / 2;
      x -= filex;
      if (flags & MOUSE_MOVE)
      {
        if (!mouseat && active != AFILELIST)
          active = AFILELIST, uih->display = 1;
        if (mouseat && active != ADIRLIST)
          active = ADIRLIST, uih->display = 1;
      }
      if (x > LISTWIDTH && (flags & MOUSE_PRESS))
      grabbed = mouseat;
      else
      {
        if (flags & MOUSE_PRESS)
          {
            int atitem =
            (y - LISTSTART - BORDERHEIGHT) / xtextheight (uih->font);
            if (atitem < 0)
            atitem = 0;
            if (!mouseat)
            {
              atitem += namestart;
              if (atitem < nnames)
                {
                  if (atitem == selectedname
                    && !strcmp (names[selectedname], filename->text))
                  {
                    ui_closefilesel (1);
                  }
                  else
                  {
                    selectedname = atitem;
                    uih->display = 1;
                    setname (selectedname);
                  }
                }
            }
            else
            {
              atitem += dirstart;
              if (atitem < ndirs)
                {
                  selecteddir = atitem;
                  uih->display = 1;
                  setdir (selecteddir);
                }
            }
          }
      }
    }
  else if (y < OKSTART)
    {
      if (pressedbutton != -1)
      pressedbutton = -1, uih->display = 1;
      /*exit(1); */
      if ((flags & MOUSE_MOVE) && active != AFILE)
      active = AFILE, uih->display = 1;
      if (flags & MOUSE_PRESS)
      ui_textmouse (filename, x, y);
    }
  else
    {
      int mouseat = 0;
      if (x > filex + filewidth / 2)
      mouseat = 1;
      if (flags & MOUSE_PRESS)
      {
        if (active != AOK)
          active = AOK, uih->display = 1;
        if (activebutton != mouseat || pressedbutton != mouseat)
          activebutton = pressedbutton = mouseat, uih->display = 1;
      }
      if ((flags & MOUSE_MOVE) && pressedbutton != mouseat)
      uih->display = 1, pressedbutton = -1, active = AOK, activebutton =
        mouseat;
      if ((flags & MOUSE_RELEASE) && pressedbutton == mouseat)
      ui_closefilesel (!mouseat);
    }
  return 1;
}

void
ui_buildfilesel (CONST char *f, CONST char *m, void (*c) (CONST char *, int))
{
  if (filevisible)
    {
      x_fatalerror ("Internal error!");
    }
  pressedbutton = activebutton = active = -1;
  if (lastdir[0] == 0)
    getcwd (lastdir, 256);
  lastdir[255] = 0;
  currdir = mystrdup (lastdir);
  callback = c;
  active = AFILE;
  filex = 0;
  filey = 0;
  filewidth = uih->image->width;
  fileheight = uih->image->height;
  namestart = dirstart = 0;
  mask = m;
  dir =
    ui_opentext (filex + 2 * BORDERWIDTH, DIRSTART + BORDERHEIGHT,
             filewidth - 4 * BORDERWIDTH, lastdir);
  filename =
    ui_opentext (filex + 2 * BORDERWIDTH, FILESTART + BORDERHEIGHT,
             filewidth - 4 * BORDERWIDTH, f);
  filevisible = 1;
  ui_buildnames (LISTWIDTH);
  filew = uih_registerw (uih, filepos, drawfile, 0, DRAWBORDER);
}
#endif

Generated by  Doxygen 1.6.0   Back to index