// This may look like C code, but it is really -*- C++ -*- // ------------------------------------------------------------------ // The Goldware Library // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alexander S. Aganichev // ------------------------------------------------------------------ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this program; if not, write to the Free // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307, USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Based on CXL by Mike Smedley. // ------------------------------------------------------------------ // Lets user pick from an array of strings. // ------------------------------------------------------------------ #include #include #include #include #include #include #include extern char m_title[]; // ------------------------------------------------------------------ int wpickstr_tag = false; // ------------------------------------------------------------------ // define record that will hold pick window info struct r_t { int numelems; int lastelem; int curr; int first; int last; int strsperline; int strsperwin; int maxstrlen; int wwidth; int wheight; int fillspaces; int gapspaces; int xtraspaces; vattr winattr; vattr barattr; int scrollbar; }; // ------------------------------------------------------------------ // this function will display the mouse // cursor if mouse cursor mode is on static void show_mouse_cursor_pck() { #ifdef GOLD_MOUSE if(gmou.FreeCursor()) { gmou.ShowCursor(); gmou.SetCursor(0,0xFFFF,((LGREY|_LGREY)<<8)); } #endif } // ------------------------------------------------------------------ // this function will hide the mouse // cursor if mouse cursor mode is on static void hide_mouse_cursor_pck() { #ifdef GOLD_MOUSE if(gmou.FreeCursor()) gmou.HideCursor(); #endif } // ------------------------------------------------------------------ // this function updates the current item by either // displaying or erasing the selection bar on it static void update_curr(char* strarr[], r_t* r, int bar) { // calculate row and column string will be displayed // at, then print out the string character-by-character int crow = (r->curr-r->first)/r->strsperline; int temp = r->curr-((crow*r->strsperline)+r->first); int ccol = (temp*r->maxstrlen)+((temp+1)*(r->gapspaces))+r->xtraspaces; wgotoxy(crow,ccol); hide_mouse_cursor_pck(); wprintns(crow, ccol, bar ? r->barattr : r->winattr, strarr[r->curr], r->maxstrlen); show_mouse_cursor_pck(); } // ------------------------------------------------------------------ static void update_line(char* strarr[], r_t* r, int wrow, int upcurr) { int nomore = false; int ccol = r->gapspaces + r->xtraspaces; int celem = (wrow*r->strsperline) + r->first; if(celem >= r->numelems) nomore = true; for(int j=0; jstrsperline; j++) { int ccolbeg = ccol; wprintns(wrow, ccolbeg, (upcurr and r->curr==celem) ? r->barattr : r->winattr, nomore ? "" : strarr[celem], r->maxstrlen); ccol += r->maxstrlen; if(++celem >= r->numelems) nomore = true; ccol += r->gapspaces; } } // ------------------------------------------------------------------ // this function will update all items in the window static void update_window(char* strarr[], r_t* r) { hide_mouse_cursor_pck(); for(int crow=0; crowwheight; crow++) update_line(strarr, r, crow, 1); show_mouse_cursor_pck(); } // ------------------------------------------------------------------ // this function will find the element number of the // first element on the same line as the given element static int e_begline(r_t* r, int elem) { return (elem/r->strsperline) * r->strsperline; } // ------------------------------------------------------------------ // this function will find the first element in a // window, using a given last element as input static int e_begwin(r_t* r, int lelem) { int beg = e_begline(r,lelem) + r->strsperline - r->strsperwin; if(beg < 0) beg = 0; return beg; } // ------------------------------------------------------------------ // this function will find the element number of the // last element on the same line as the given element static int e_endline(r_t* r, int elem) { int end = (((elem/r->strsperline)+1)*r->strsperline)-1; if(end>=r->numelems) end = r->lastelem; return end; } // ------------------------------------------------------------------ // this function will find the last element in a // window, using a given first element as input static int e_endwin(r_t* r, int felem) { int end = felem + r->strsperwin - 1; if(end > (r->lastelem)) end = r->lastelem; return end; } // ------------------------------------------------------------------ static void goto_item(r_t* r, char* strarr[], int elem) { if(elem<0 or elem>r->lastelem) elem = 0; int outside = (elemfirst or elem>r->last) ? YES : NO; if(outside == NO) update_curr(strarr,r,0); r->curr = elem; if(outside) { r->first = e_begwin(r,r->last = e_endwin(r,e_begline(r,r->curr))); update_window(strarr,r); } else { update_curr(strarr,r,1); } } // ------------------------------------------------------------------ // this function determines if the mouse cursor is on a item #ifdef GOLD_MOUSE static int mouse_on_item(r_t* r, int mcrow, int mccol) { int found = -1; int srow = gwin.active->srow; int scol = gwin.active->scol; int border = gwin.active->border; for(int i=r->first; i<=r->last; i++) { if(mcrow==(srow+border+((i-r->first)/r->strsperline))) { int start = scol+border+r->xtraspaces+r->gapspaces+((i%r->strsperline)*(r->maxstrlen+r->gapspaces)); int end = start+r->maxstrlen-1; if(mccol>=start and mccol<=end) { found = i; break; } } } if(found==-1 and r->scrollbar and mccol==gwin.active->ecol) { if(mcrow==srow+1) found=-2; else { if(mcrow==gwin.active->erow-1) found=-3; } } return found; } #endif // ------------------------------------------------------------------ static void page_down(char* strarr[], r_t* r) { if(r->curr != r->last) { r->curr = r->last; update_window(strarr, r); } else if(r->last != (r->lastelem)) { int i = r->curr-r->first; r->last = e_endwin(r,r->last+1); r->first = e_begwin(r, r->last); if((r->curr = r->first+i) > (r->lastelem)) r->curr -= r->strsperline; update_window(strarr, r); } } // ------------------------------------------------------------------ static void page_up(char* strarr[], r_t* r) { if(r->curr != r->first) { r->curr = r->first; update_window(strarr, r); } else if(r->first) { int i = r->curr-r->first; r->first = e_begwin(r,r->first-1); r->last = e_endwin(r, r->first); r->curr = r->first+i; update_window(strarr,r); } } // ------------------------------------------------------------------ static void scroll_down(char* strarr[], r_t* r, int upcurr) { if(r->first) { hide_mouse_cursor_pck(); if(upcurr) update_curr(strarr,r,0); r->first -= r->strsperline; r->last = e_endline(r,r->last-r->strsperline); if(upcurr>1) r->curr -= r->strsperline; if(r->first != e_begline(r,r->last)) wscroll(1,SDOWN); update_line(strarr, r, 0, (upcurr>2) ? 0 : upcurr); show_mouse_cursor_pck(); } } // ------------------------------------------------------------------ static void scroll_up(char* strarr[], r_t* r, int upcurr) { if(r->last!=(r->lastelem)) { hide_mouse_cursor_pck(); if(upcurr) update_curr(strarr,r,0); r->first+=r->strsperline; r->last=e_endline(r,r->last+1); if(upcurr>1) if((r->curr+r->strsperline)<=r->last) r->curr+=r->strsperline; if(r->first!=e_begline(r,r->last)) wscroll(1,SUP); update_line(strarr,r,r->wheight-1,(upcurr>2)?0:upcurr); show_mouse_cursor_pck(); } } // ------------------------------------------------------------------ // this function reads the mouse for input static gkey read_mouse(char* strarr[], r_t* r) { #ifdef GOLD_MOUSE // if free-floating mouse cursor support is on if(gmou.FreeCursor()) { // clear mouse button queue gmou.ClearEvents(); // loop until a key is pressed while(!kbxhit() and gkbd.kbuf==NULL) { // call the keyboard loop function, if defined //if(gkbd.kbloop!=NULL) //(*gkbd.kbloop)(); // see if the right button (Esc) was pressed gmou.GetRightRelease(); if(gmou.Count()) return Key_Esc; // see where mouse cursor is at - if it is on a scroll bar // or menu item, and the left button is pressed, then scroll // menu or select item gmou.GetStatus(); int i = mouse_on_item(r,gmou.Row(),gmou.Column()); switch(i) { case -1: gmou.ClearEvents(); break; case -2: if(gmou.LeftButton()) { scroll_down(strarr,r,3); if(gvid->isbios()) usleep(50); gmou.ClearEvents(); } break; case -3: if(gmou.LeftButton()) { scroll_up(strarr,r,3); if(gvid->isbios()) usleep(50); gmou.ClearEvents(); } break; default: gmou.GetLeftRelease(); if(gmou.Count()) { r->curr = i; return Key_Ent; } } } } #endif // return zero - it means a key was pressed return 0; } // ------------------------------------------------------------------ int wpickstr(int srow, int scol, int erow, int ecol, int btype, vattr bordattr, vattr winattr, vattr barattr, char* strarr[], int initelem, VfvCP open) { int i, j, maxlen, outside; gkey xch; char ch; char* p; r_t r; int quickpos = (strarr[0][0] == ' ') ? 1 : 0; // go through input array and determine the longest // string, and count the number of elements in the array maxlen = strlen(m_title); for (i = 0; strarr[i] != NULL; i++) if ((j = strlen(strarr[i])) > maxlen) maxlen = j; r.maxstrlen = maxlen; r.lastelem = ((r.numelems=i)-1); r.winattr = winattr; r.barattr = barattr; // see if window is to have a border int border = (btype==5) ? NO : YES; // if ecol == -1 then adjust it to conform to length of longest string if(ecol==-1) ecol = scol+border+r.maxstrlen+border-1; // calculate window area width and height r.wwidth = (ecol-border)-(scol+border)+1; r.wheight = (erow-border)-(srow+border)+1; // make sure longest string can fit in window if(r.maxstrlen > r.wwidth) r.maxstrlen = r.wwidth; // open window which strings will reside in hide_mouse_cursor_pck(); if(!wopen(srow,scol,erow,ecol,btype,bordattr,winattr,bordattr)) return -1; // if mouse cursor mode is on and window has a border, // display scroll indicator arrows on right window border #ifdef GOLD_MOUSE if(gmou.FreeCursor() and (btype!=5) and ((srow+2) < erow)) { vputc(srow+1,ecol,bordattr,(char) 24); vputc(erow-1,ecol,bordattr,(char) 25); r.scrollbar=true; } else { #endif r.scrollbar=false; #ifdef GOLD_MOUSE } #endif show_mouse_cursor_pck(); // if an open function has been specified, then call it if(open!=NULL) open(); // if mouse cursor mode is on, then turn on mouse cursor show_mouse_cursor_pck(); // calculate how many strings can fit into 1 window line, number of // filler spaces needed per window line, number of spaces per gap in // between strings, number of extra spaces to add to first gap, and // number of strings that can fit inside the window r.strsperline = (r.wwidth-2)/(r.maxstrlen+2); if(!r.strsperline) r.strsperline++; r.fillspaces = r.wwidth-(r.strsperline*r.maxstrlen); r.gapspaces = r.fillspaces/(r.strsperline+1); r.xtraspaces = (r.fillspaces%(r.strsperline+1))/2; r.strsperwin = r.strsperline*r.wheight; // initialize first, last, and current elements r.curr = r.first = 0; r.last = (r.numelemsr.last) scroll_up(strarr,&r,((r.curr+r.strsperline)>r.lastelem) ? 0 : 2); else { update_curr(strarr,&r,0); r.curr+=r.strsperline; update_curr(strarr,&r,1); } break; case Key_PgUp: // move up 1 page. adjust position if at 1st element page_up(strarr,&r); break; case Key_PgDn: // move down 1 page. adjust position if at last element page_down(strarr,&r); break; case Key_Home: // set position to 1st element if(r.curr) { if((outside=r.first)==NO) update_curr(strarr,&r,0); r.first=r.curr=0; if(outside) { r.last=e_endwin(&r,r.first); update_window(strarr,&r); } else { update_curr(strarr,&r,1); } } break; case Key_End: // set position to last element if(r.curr!=r.lastelem) { if((outside=(r.last<(r.lastelem))?YES:NO)==NO) update_curr(strarr,&r,0); r.last=r.curr=r.lastelem; if(outside) { r.first=e_begwin(&r,r.last); update_window(strarr,&r); } else { update_curr(strarr,&r,1); } } break; default: // if not an extended keypress, then search from current // position for the item that begins with the same ASCII // character as the keypress. If not found after current // position, search from the beginning for a match ch = (char)g_toupper((char)xch); if(!ch) break; for(i=r.curr+1; i