// $Log: menu.cc,v $ // Revision 1.1.1.1 2000/12/16 20:45:46 stuart // Released TUIPeer sources // #pragma implementation "Menu.h" #pragma implementation "Array.h" #include #include #include #include #include #include #include #include // can merge with default using a default argument when we // recompile everything bmsApp::bmsApp(int bufsize) { menu = 0; Kbegin(bufsize); // make 1 unless enabling ESC if (bufsize != 1) Kdefine("\033",27); // enable bare ESC for vi emulation setfocus(this); } bmsApp::bmsApp() { menu = 0; Kbegin(1); /* Ksignal(SIGINT); */ /* Ksignal(SIGALRM); */ setfocus(this); } bmsApp::~bmsApp() { delete menu; Kend(); } void bmsApp::key(int ky) { //fprintf(stderr,"bmsApp::key = %d\n",ky); switch (ky) { case KEY_F(1): case KEY_EXIT: case 'q': case 'Q': cmd(EXIT); return; case KEY_F(10): case KEY_HELP: case '?': if (menu) menu->popupAt(Point(0,0),this); return; } Karet::key(ky); } void bmsApp::cmd(int cmd) { switch (cmd) { case EXIT: setfocus(0); } } MenuItem Menu::def; template class Array; Menu::Menu() { cursel = 0; curtype(0); } #if 0 MenuItem *&Menu::operator[](int pos) { delete m[pos]; return m[pos]; } #endif MenuItem *Menu::operator[](int pos) const { if (pos < 0 || pos >= count()) return &def; return m[pos]; } Menu &Menu::operator+(MenuItem *p) { m.add(p); return *this; } Menu::~Menu() { for (int i = 0; i < count(); ++i) delete m[i]; } SubMenu::SubMenu(const char *t,Menu &p): MenuItem(t), origin(9,9) { submenu = &p; } Menu *SubMenu::remove() { Menu *p = submenu; submenu = 0; return p; } SubMenu::~SubMenu() { delete submenu; } void MenuItem::state(State s) { switch (st = s) { case GRAY: attr = A_DIM; break; default: attr = A_NORMAL; } } void MenuItem::draw(Window *w,const Rect &r) { /* fprintf(stderr,"width=%d\r\n",r.width()); */ const char *p = title; int len = r.width(); CHTYPE *buf = (CHTYPE *)alloca(len * sizeof buf[0]); if (pfkey) { char kbuf[6]; const char *s = Kname(pfkey); if (s) { sprintf(kbuf,"(%.3s)",s); len -= 5; w->write(r.r1,r.c1 + len,5,kbuf,attr); } } for (int i = 0; i < len; ++i) { CHTYPE a = attr; if (*p == '~') { a |= A_UNDERLINE; ++p; } if (!*p) { buf[i] = ' ' | a; continue; } buf[i] = (unsigned char)*p++ | a; } w->write(r.r1,r.c1,len,buf); } bool MenuItem::match(int ky) { if (isascii(ky) && isprint(ky)) { const char *p = strchr(title,'~'); if (!p) p = title; else ++p; return toupper(ky) == toupper(*p); } return ky == pfkey; } void SubMenu::draw(Window *w,const Rect &r) { origin = w->loc.origin() + r.origin() + Point(1,0); MenuItem::draw(w,r); } // compute display dimensions Rect MenuItem::dim() const { int len = 0; if (title) { len = strlen(title); if (pfkey) len += 6; // (Fxx) } return Rect(Point(0,0),len); } void MenuItem::select() { attr |= A_REVERSE; } void MenuItem::deselect() { attr &= ~A_REVERSE; } void MenuItem::doit(Karet *app) { app->setfocus(0); } void SubMenu::doit(Karet *app) { submenu->popupAt(origin,app); } void CmdMenuItem::doit(Karet *app) { app->cmd(cmd); } Menu &Menu::insert(int pos,MenuItem *p) { int i = count(); if (i) { for (m.add(m[--i]); i && i > pos; --i) m[i] = m[i-1]; m[i] = p; } else m.add(p); return *this; } void Menu::del(int pos) { // FIXME: Shouldn't this delete the MenuItem? m.del(pos); } MenuItem *Menu::remove(int pos) { // delete menu item */ MenuItem *p = 0; if (pos >= 0 && pos < count()) p = m[pos]; m.del(pos); return p; } void PopupMenu::draw(const Rect &r) { //fprintf(stderr,"PopupMenu::draw\n"); Point pos(0,0); for (int i = 0; i < count(); ++i) { Rect item = (*this)[i]->dim() + pos; item.c2 = r.c2; Rect r1 = r.intersect(item); if (!r1.isempty()) (*this)[i]->draw(this,item); pos.row += item.height(); } } void BarMenu::draw(const Rect &r) { fill(r,' ' + A_REVERSE + A_DIM); Point pos(0,0); for (int i = 0; i < count(); ++i) { Rect item = (*this)[i]->dim() + pos; Rect r1 = r.intersect(item); if (!r1.isempty()) (*this)[i]->draw(this,r1); pos.col += item.width() + 1; } } Rect PopupMenu::dim() const { short rows = 0, cols = titlelen; for (int i = 0; i < count(); ++i) { Rect r = (*this)[i]->dim(); if (cols < r.width()) cols = r.width(); rows += r.height(); } //fprintf(stderr,"rows = %d, cols = %d\n",rows,cols); return Rect(Point(1,1),cols,rows); } Rect BarMenu::dim() const { short rows = 0, cols = screen.width(); for (int i = 0; i < count(); ++i) { Rect r = (*this)[i]->dim(); if (rows < r.height()) rows = r.height(); } //fprintf(stderr,"rows = %d, cols = %d\n",rows,cols); return Rect(Point(0,0),cols,rows); } int Menu::popupAt(Point p,Karet *a) { setfocus(this); setphys(dim() + p); if (a == 0) { app = this; run(); } else app = a; return cursel; } void Menu::losefocus() { //fprintf(stderr,"Menu::losefocus\r\n"); hide(); sync(); } void Menu::getfocus() { if (cursel >= count()) cursel = 0; if (cursel < count()) m[cursel]->select(); sync(); } void Menu::cmd(int) { setfocus(0); } void Menu::key(int ky) { int first; if (cursel >= count()) setfocus(0); else switch (ky) { case KEY_UP: case KEY_LEFT: m[cursel]->deselect(); for (first = cursel--; ; --cursel) { if (cursel < 0) cursel = count() - 1; if (cursel == first) break; if (m[cursel]->state() == MenuItem::ENABLE) break; } m[cursel]->select(); redraw(); return; case KEY_DOWN: case KEY_RIGHT: m[cursel]->deselect(); for (first = cursel++; ; ++cursel) { if (cursel >= count()) cursel = 0; if (cursel == first) break; if (m[cursel]->state() == MenuItem::ENABLE) break; } m[cursel]->select(); redraw(); return; case KEY_ENTER: if (m[cursel]->state() == MenuItem::ENABLE) m[cursel]->doit(app); return; case KEY_F(1): case KEY_OPTIONS: setfocus(0); return; default: int cnt = 0; int oldsel = cursel; for (int j = 1; j <= count(); ++j) { int i = j + oldsel; if (i >= count()) i -= count(); if (m[i]->match(ky)) { if (cnt++ == 0) { m[cursel]->deselect(); m[cursel = i]->select(); redraw(); } } } if (cnt) { if (cnt == 1 && m[cursel]->state() == MenuItem::ENABLE) m[cursel]->doit(app); return; } } //Karet::key(ky); } void BarMenu::key(int ky) { if (ky == KEY_DOWN) ky = KEY_ENTER; Menu::key(ky); } void PopupMenu::key(int ky) { switch (ky) { case KEY_LEFT: case KEY_RIGHT: Karet::key(ky); setfocus(0); return; } Menu::key(ky); } PopupMenu::PopupMenu(const char *title): FrameWin(title) { titlelen = title ? strlen(title) : 0; } MenuItem::MenuItem(const char *t) { title = t; if (t) st = ENABLE; else st = DISABLE; attr = A_NORMAL; pfkey = 0; } int Menu::pos(int cmd) const { for (int i = 0; i < m.size(); ++i) if (m[i]->id() == cmd) return i; return -1; }