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

menu.c

/*
 *    Menu selection window
 *    Copyright
 *          (C) 1992 Joseph H. Allen
 *
 *    This file is part of JOE (Joe's Own Editor)
 */
#include "types.h"

int bg_menu;

int transpose;

static void menufllw(MENU *m)
{
      if (transpose) {
            if ((m->cursor % m->lines) < m->top)
                  m->top = m->cursor % m->lines;
            else if (m->cursor % m->lines >= (m->top % m->lines) + m->h)
                  m->top = (m->cursor % m->lines) - (m->h - 1);
      } else {
            if (m->cursor < m->top)
                  m->top = m->cursor - m->cursor % m->perline;
            else if (m->cursor >= m->top+m->perline*m->h)
                  m->top = m->cursor - m->cursor % m->perline - m->perline*(m->h-1);
      }
}

static void menudisp(MENU *m)
{
      int col;
      int x;
      int y;
      int *s = m->t->t->scrn + m->x + m->y * m->t->t->co;
      int *a = m->t->t->attr + m->x + m->y * m->t->t->co;
      struct utf8_sm sm;
      int cut = m->nitems % m->lines;
      if (!cut) cut = m->lines;

      utf8_init(&sm);

      for (y = 0; y != m->h; ++y) {
            col = 0;
            if (transpose) {
                  for (x = 0; x < ((y + m->top) >= cut ? m->perline - 1 : m->perline) ; ++x) {
                        int atr;
                        int index = x * m->lines + y + m->top;
            
                        if (index == m->cursor && m->t->curwin == m->parent)
                              atr = INVERSE|BG_COLOR(bg_menu);
                        else
                              atr = BG_COLOR(bg_menu);

                        if (col == m->w)
                              break;

                        /* Generate field */
                        genfield(m->t->t,
                               s + col,
                               a + col,
                               m->x + col,
                               m->y + y,
                               0,
                               m->list[index],
                               zlen(m->list[index]),
                               atr,
                               m->width,
                               0,NULL);

                        col += m->width;

                        /* Space between columns */
                        if (col != m->w) {
                              outatr(locale_map, m->t->t, s + col, a + col, m->x + col, m->y+y, ' ', BG_COLOR(bg_menu));
                              ++col;
                        }
                  }
            } else {
                  for (x = 0; x != m->perline && y * m->perline + x + m->top < m->nitems; ++x) {
                        int atr;
                        int index = x + y * m->perline + m->top;
            
                        if (index == m->cursor && m->t->curwin==m->parent)
                              atr = INVERSE|BG_COLOR(bg_menu);
                        else
                              atr = BG_COLOR(bg_menu);

                        if (col == m->w)
                              break;

                        /* Generate field */
                        genfield(m->t->t,
                               s + col,
                               a + col,
                               m->x + col,
                               m->y + y,
                               0,
                               m->list[index],
                               zlen(m->list[index]),
                               atr,
                               m->width,
                               0,NULL);

                        col += m->width;

                        /* Space between columns */
                        if (col != m->w) {
                              outatr(locale_map, m->t->t, s + col, a + col, m->x + col, m->y+y, ' ', BG_COLOR(bg_menu));
                              ++col;
                        }
                  }
            }
            /* Clear to end of line */
            if (col != m->w)
                  eraeol(m->t->t, m->x + col, m->y + y, BG_COLOR(bg_menu));
            s += m->t->t->co;
            a += m->t->t->co;
      }
      if (transpose) {
            m->parent->cury = (m->cursor % m->lines) - m->top;
            col = txtwidth(m->list[m->cursor],zlen(m->list[m->cursor]));
            if (col < m->width)
                  m->parent->curx = (m->cursor / m->lines) * (m->width + 1) + col;
            else
                  m->parent->curx = (m->cursor / m->lines) * (m->width + 1) + m->width;
      } else {
            m->parent->cury = (m->cursor - m->top) / m->perline;
            col = txtwidth(m->list[m->cursor],zlen(m->list[m->cursor]));
            if (col < m->width)
                  m->parent->curx = ((m->cursor - m->top) % m->perline) * (m->width + 1) + col;
            else
                  m->parent->curx = ((m->cursor - m->top) % m->perline) * (m->width + 1) + m->width;
      }
}

static void menumove(MENU *m, int x, int y)
{
      m->x = x;
      m->y = y;
}

static int mlines(unsigned char **s, int w)
{
      int x;
      int lines;
      int width;
      int nitems;
      int perline;

      for (x = 0, width = 0; s[x]; ++x) {
            int d = txtwidth(s[x],zlen(s[x]));
            if (d > width)
                  width = d;
      }
      nitems = x;
      if (width > w)
            width = w - 1;
      perline = w / (width + 1);

      lines = (nitems + perline - 1) / perline;

      return lines;
}

static void mconfig(MENU *m)
{
      /* Configure menu display parameters */
      if (m->list) {
            int x;
            /* int lines; */

            m->top = 0;
            for (x = 0, m->width = 0; m->list[x]; ++x) {
                  int d = txtwidth(m->list[x],zlen(m->list[x]));
                  if (d > m->width)
                        m->width = d;
            }
            m->nitems = x;
            if (m->width > m->w)
                  m->width = m->w - 1;

            m->fitline = m->w / (m->width + 1);

            m->lines = (m->nitems + m->fitline - 1) / m->fitline;

            if (transpose)
                  m->perline = (m->nitems + m->lines - 1) / m->lines;
            else
                  m->perline = m->fitline;
      }
}

static void menuresz(MENU *m, int wi, int he)
{
      m->w = wi;
      m->h = he;
      mconfig(m);
}

int umbol(MENU *m)
{
      if (transpose)
            m->cursor %= m->lines;
      else
            m->cursor -= m->cursor % m->perline;
      return 0;
}

int umbof(MENU *m)
{
      m->cursor = 0;
      return 0;
}

int umeof(MENU *m)
{
      if (m->nitems) {
            if (transpose && (m->nitems % m->lines != 0)) {
                  m->cursor = m->lines - 1 + (m->lines * (m->perline - 2));
            } else {
                  m->cursor = m->nitems - 1;
            }
      }
      return 0;
}

int umeol(MENU *m)
{
      if (transpose) {
            int cut = m->nitems % m->lines;
            if (!cut) cut = m->lines;
            m->cursor %= m->lines;
            if (m->cursor >= cut)
                  m->cursor += m->lines * (m->perline - 2);
            else
                  m->cursor += m->lines * (m->perline - 1);
      } else {
            m->cursor -= m->cursor % m->perline;

            if (m->cursor+m->perline-1 >= m->nitems)
                  m->cursor = m->nitems - 1;
            else
                  m->cursor += m->perline - 1;
      }

      return 0;
}

int umrtarw(MENU *m)
{
      if (transpose) {
            int cut = m->nitems % m->lines;
            if (!cut) cut = m->lines;
            if (m->cursor % m->lines >= cut) {
                  if (m->cursor / m->lines != m->perline - 2) {
                        m->cursor += m->lines;
                        return 0;
                  }
            } else {
                  if (m->cursor / m->lines != m->perline - 1) {
                        m->cursor += m->lines;
                        return 0;
                  }
            }
            if ((m->cursor % m->lines) + 1 < m->lines) {
                  m->cursor = m->cursor % m->lines + 1;
                  return 0;
            }
            return -1;
      } else if (m->cursor + 1 < m->nitems) {
            ++m->cursor;
            return 0;
      } else
            return -1;
}

int umtab(MENU *m)
{
      if (m->cursor + 1 >= m->nitems)
            m->cursor = 0;
      else
            ++ m->cursor;
      return 0;
}

int umltarw(MENU *m)
{
      if (transpose && m->cursor >= m->lines) {
            m->cursor -= m->lines;
            return 0;
      } else if (transpose && m->cursor) {
            int cut = m->nitems % m->lines;
            if (!cut) cut = m->lines;
            --m->cursor;
            if (m->cursor >= cut)
                  m->cursor += (m->perline - 2) * m->lines;
            else
                  m->cursor += (m->perline - 1) * m->lines;
            return 0;
      } else if (!transpose && m->cursor) {
            --m->cursor;
            return 0;
      } else
            return -1;
}

int umuparw(MENU *m)
{
      if (transpose && (m->cursor % m->lines)) {
            --m->cursor;
            return 0;
      } else if (!transpose && m->cursor >= m->perline) {
            m->cursor -= m->perline;
            return 0;
      } else
            return -1;
}

int umdnarw(MENU *m)
{
      if (transpose) {
            if (m->cursor != m->nitems - 1 && m->cursor % m->lines != m->lines - 1) {
                  ++m->cursor;
                  return 0;
            } else {
                  return -1;
            }
      } else {
            int col = m->cursor % m->perline;

              m->cursor -= col;

            if (m->cursor + m->perline < m->nitems) {
                  m->cursor += m->perline;
                  if (m->cursor + col >= m->nitems)
                        if (m->nitems)
                              m->cursor = m->nitems - 1;
                        else
                              m->cursor = 0;
                  else
                        m->cursor += col;
                  return 0;
            } else {
                  m->cursor += col;
                  return -1;
            }
      }
}

void menujump(MENU *m,int x,int y)
{
      int pos = m->top;
      if (transpose) {
            pos += y;
            pos += (x / (m->width + 1)) * m->lines;
      } else {
            pos += y * m->perline;
            pos += x / (m->width + 1);
      }
      if (pos >= m->nitems)
            pos = m->nitems - 1;
      if (pos < 0)
            pos = 0;
      m->cursor = pos;
}

int mscrup(MENU *m,int amnt)
{
      if (transpose) {
            if (m->top >= amnt) {
                  m->top -= amnt;
                  m->cursor -= amnt;
                  return 0;
            } else if (m->top) {
                  m->cursor -= m->top;
                  m->top = 0;
                  return 0;
            } else if (m->cursor % m->lines) {
                  m->cursor -= (m->cursor % m->lines);
                  return 0;
            } else
                  return -1;
      } else {
            if (m->top >= amnt*m->perline) {
                  m->top -= amnt*m->perline;
                  m->cursor -= amnt*m->perline;
                  return 0;
            } else if (m->top) {
                  m->cursor -= m->top;
                  m->top = 0;
                  return 0;
            } else if (m->cursor >= m->perline) {
                  m->cursor = m->cursor % m->perline;
                  return 0;
            } else
                  return -1;
      }
}

int umscrup(MENU *m)
{
      return mscrup(m, 1);
}

int umpgup(MENU *m)
{
      return mscrup(m, (m->h + 1) / 2);
}

int mscrdn(MENU *m, int amnt)
{
      if (transpose) {
            int col = m->cursor / m->lines;
            int y = m->cursor % m->lines;
            int h = m->lines;
            int t = m->top;
            int cut = m->nitems % m->lines;
            if (!cut) cut = m->lines;
            m->cursor %= m->lines;

            if (t + m->h + amnt <= h) {
                  m->top += amnt;
                  m->cursor += amnt;
                  if (m->cursor >= cut && col == m->perline - 1)
                        --col;
                  m->cursor += col * m->lines;
                  return 0;
            } else if (t + m->h < h) {
                  amnt = h - (t + m->h);
                  m->top += amnt;
                  m->cursor += amnt;
                  if (m->cursor >= cut && col == m->perline - 1)
                        --col;
                  m->cursor += col * m->lines;
                  return 0;
            } else if (y + 1 != h) {
                  m->cursor = h - 1;
                  if (m->cursor >= cut && col == m->perline - 1)
                        --col;
                  m->cursor += col * m->lines;
                  return 0;
            } else {
                  m->cursor += col * m->lines;
                  return -1;
            }
      } else {
            int col = m->cursor % m->perline;
            int y = m->cursor / m->perline;
            int h = (m->nitems + m->perline - 1) / m->perline;
            int t = m->top / m->perline;
            m->cursor -= col;

            if (t + m->h + amnt <= h) {
                  m->top += amnt*m->perline;
                  m->cursor += amnt*m->perline;
                  if (m->cursor + col >= m->nitems)
                        if (m->nitems)
                              m->cursor = m->nitems - 1;
                        else
                              m->cursor = 0;
                  else
                        m->cursor += col;
                  return 0;
            } else if (t + m->h < h) {
                  amnt = h - (t + m->h);
                  m->top += amnt*m->perline;
                  m->cursor += amnt*m->perline;
                  if (m->cursor + col >= m->nitems)
                        if (m->nitems)
                              m->cursor = m->nitems - 1;
                        else
                              m->cursor = 0;
                  else
                        m->cursor += col;
                  return 0;
            } else if (y+1!=h) {
                  m->cursor = (h-1)*m->perline;
                  if (m->cursor + col >= m->nitems)
                        if (m->nitems)
                              m->cursor = m->nitems - 1;
                        else
                              m->cursor = 0;
                  else
                        m->cursor += col;
                  return 0;
            } else {
                  m->cursor += col;
                  return -1;
            }
      }
}

int umscrdn(MENU *m)
{
      return mscrdn(m, 1);
}

int umpgdn(MENU *m)
{
      return mscrdn(m, (m->h + 1) / 2);
}

static int umrtn(MENU *m)
{
      dostaupd = 1;
      if (m->func)
            return m->func(m, m->cursor, m->object, 0);
      else
            return -1;
}

int umbacks(MENU *m)
{
      if (m->backs)
            return m->backs(m, m->cursor, m->object);
      else
            return -1;
}

static int umkey(MENU *m, int c)
{
      int x;
      int n = 0;

      if (c == '0') {
            if (m->func)
                  return m->func(m, m->cursor, m->object, -1);
            else
                  return -1;
      }
      if (c == '1') {
            if (m->func)
                  return m->func(m, m->cursor, m->object, 1);
            else
                  return -1;
      }
      c &= 0x1F;
      for (x = 0; x != m->nitems; ++x)
            if ((m->list[x][0] & 0x1F) == c)
                  ++n;
      if (!n)
            return -1;
      if (n == 1)
            for (x = 0; x != m->nitems; ++x)
                  if ((m->list[x][0] & 0x1F) == c) {
                        m->cursor = x;
                        return umrtn(m);
                  }
      do {
            ++m->cursor;
            if (m->cursor == m->nitems)
                  m->cursor = 0;
      } while ((m->list[m->cursor][0] & 0x1F) != c);

      return -1;
}

static int menuabort(MENU *m)
{
      W *w = m->parent;
      int (*func) () = m->abrt;
      void *object = m->object;
      int x = m->cursor;
      W *win = w->win;

      joe_free(m);
      if (func)
            return func(win->object, x, object);
      else
            return -1;
}

WATOM watommenu = {
      USTR "menu",
      menudisp,
      menufllw,
      menuabort,
      umrtn,
      umkey,
      menuresz,
      menumove,
      NULL,
      NULL,
      TYPEMENU
};

void ldmenu(MENU *m, unsigned char **s, int cursor)
{
      m->list = s;
      m->cursor = cursor;
      mconfig(m);
}

int menu_above;

MENU *mkmenu(W *w, W *targ, unsigned char **s, int (*func) (/* ??? */), int (*abrt) (/* ??? */), int (*backs) (/* ??? */), int cursor, void *object, int *notify)
{
      W *new;
      MENU *m;
      int lines;
      int h = (w->main->h*40) / 100; /* 40% of window size */
      if (!h)
            h = 1;
      
      if (s) {
            lines = mlines(s,w->t->w-1);
            if (lines < h)
                  h = lines;
      }

      new = wcreate(w->t, &watommenu, w, targ, targ->main, h, NULL, notify);

      if (!new) {
            if (notify)
                  *notify = 1;
            return NULL;
      }
      wfit(new->t);
      new->object = (void *) (m = (MENU *) joe_malloc(sizeof(MENU)));
      m->parent = new;
      m->func = func;
      m->abrt = abrt;
      m->backs = backs;
      m->object = object;
      m->t = w->t;
      m->h = new->h;
      m->w = new->w;
      m->x = new->x;
      m->y = new->y;
      m->top = 0;
      ldmenu(m, s, cursor);
      w->t->curwin = new;
      return m;
}

static unsigned char *cull(unsigned char *a, unsigned char *b)
{
      int x;

      for (x = 0; a[x] && b[x] && a[x] == b[x]; ++x) ;
      return vstrunc(a, x);
}

unsigned char *find_longest(unsigned char **lst)
{
      unsigned char *com;
      int x;

      if (!lst || !aLEN(lst))
            return vstrunc(NULL, 0);
      com = vsncpy(NULL, 0, sv(lst[0]));
      for (x = 1; x != aLEN(lst); ++x)
            com = cull(com, lst[x]);
      return com;
}

unsigned char *mcomplete(MENU *m)
{
      unsigned char *com;
      int x;

      if (!m->nitems)
            return vstrunc(NULL, 0);
      com = vsncpy(NULL, 0, sz(m->list[0]));
      for (x = 1; x != m->nitems; ++x)
            com = cull(com, m->list[x]);
      return com;
}

Generated by  Doxygen 1.6.0   Back to index