// 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$ // ------------------------------------------------------------------ // Pick engine. // ------------------------------------------------------------------ #include #include #include #include #include #include #include // ------------------------------------------------------------------ int Picker(PInf* p, Pick* pick) { int keyok; gkey keycode, newkey; #ifdef GOLD_MOUSE gmou.HideCursor(); #endif // Open and initialize if(pick->open) pick->open(p); if(p->helpcat) whelppcat(p->helpcat); do { // Display selection bar wgotoxy(p->pos, 0); p->type = PICK_BAR; pick->disp(p); p->type = PICK_DISP; // Handle keyboard and delay function if(pick->dodelayed) pick->dodelayed(p); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif keyok = YES; do { newkey = keycode = getxchtick(); if(newkey == Key_Tick) pick->dokey(p, &keycode); } while(newkey == Key_Tick); do { #ifdef GOLD_MOUSE gmou.HideCursor(); #endif newkey = 0; switch(keycode) { case Key_Up: case Key_Dwn: case Key_PgUp: case Key_PgDn: case Key_Home: case Key_End: if(pick->precursor) pick->precursor(p); break; } switch(keycode) { case Key_Up: p->direction = -1; if(p->pos) { pick->disp(p); p->pos--; p->idx--; } else if(p->idx > p->minidx) { pick->disp(p); p->idx--; pick->scroll(p, SDOWN); } else if(p->listwrap) newkey = Key_End; break; case Key_Dwn: p->direction = 1; if(p->pos < p->maxpos) { if(p->idx < p->maxidx) { pick->disp(p); p->pos++; p->idx++; } else if(p->listwrap) newkey = Key_Home; } else if(p->idx < p->maxidx) { pick->disp(p); p->idx++; pick->scroll(p, SUP); } else if(p->listwrap) newkey = Key_Home; break; case Key_PgUp: p->direction = -1; if(p->pos) { pick->disp(p); p->idx -= p->pos; p->pos = 0; } else if(p->idx > p->minidx) { p->idx -= (p->idx >= p->maxpos) ? p->maxpos : p->idx; pick->page(p); } break; case Key_PgDn: p->direction = 1; if(p->pos < p->maxpos) { if(p->idx == p->maxidx) { if(p->maxpos < p->maxidx) { p->pos = p->maxpos; p->idx = p->maxidx; pick->page(p); } } else if(p->idx + (p->maxpos-p->pos) >= p->maxidx) { pick->disp(p); p->pos += p->maxidx-p->idx; p->idx = p->maxidx; } else if(p->pos != p->maxpos) { pick->disp(p); p->idx += p->maxpos-p->pos; p->pos = p->maxpos; } } else if(p->idx < p->maxidx) { if(p->idx+p->maxpos > p->maxidx) { p->pos = p->maxidx-p->idx; p->idx = p->maxidx; pick->page(p); } else { p->idx += p->maxpos; p->pos = p->maxpos; pick->page(p); } } break; case Key_Home: p->direction = -1; if(p->idx > p->minidx) { if((p->idx - p->pos) <= p->minidx) { pick->disp(p); p->idx = p->minidx; p->pos = 0; } else { p->pos = 0; p->idx = p->minidx; pick->page(p); } } break; case Key_End: p->direction = 1; if(p->idx < p->maxidx) { if(p->idx + (p->maxpos-p->pos) >= p->maxidx) { pick->disp(p); p->pos += p->maxidx-p->idx; p->idx = p->maxidx; } else { p->pos = (p->maxidx-p->idx) < p->maxpos ? p->maxidx-p->idx : p->maxpos; p->idx = p->maxidx; pick->page(p); } } else if(p->pos < p->maxpos) { if(p->maxpos < p->maxidx) { p->pos = p->maxpos; p->idx = p->maxidx; pick->page(p); } } break; case Key_C_Up: p->direction = -1; if(p->idx - p->pos) { p->idx--; pick->page(p); } break; case Key_C_Dwn: p->direction = 1; if(p->idx < p->maxidx) { p->idx++; pick->page(p); } break; default: keyok = pick->dokey(p, &keycode); newkey = keycode; } if(newkey) keycode = newkey; } while(newkey); } while(keyok); #ifdef GOLD_MOUSE gmou.HideCursor(); #endif // Close and clean if(p->helpcat) whelpop(); if(pick->close) pick->close(p); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif return p->retval; } // ------------------------------------------------------------------ gwinpick::gwinpick() { // memset(this, 0, sizeof(gwinpick)); WHAT!?!?! ARE YOU NUTS? key = 0; keyok = false; ypos = xpos = ylen = xlen = 0; btype = battr = wattr = tattr = sattr = hattr = loattr = sbattr = 0; title = NULL; helpcat = 0; maximum_index = minimum_index = maximum_position = index = position = 0; aborted = listwrap = false; direction = 0; } // ------------------------------------------------------------------ void gwinpick::cursor_up() { bool done; do { if(index > minimum_index) { display_line(); if(position) position--; else scroll(SDOWN); index--; if((done = is_selectable(index))==true) update_cursor(); } else { if(listwrap) cursor_last(); else if(not is_selectable(index)) cursor_down(); done = true; } } while(not done); direction = -1; } // ------------------------------------------------------------------ void gwinpick::cursor_down() { bool done; do { if(index < maximum_index) { display_line(); index++; if(position < maximum_position) position++; else scroll(SUP); if((done = is_selectable(index))!=false) update_cursor(); } else { if(listwrap) cursor_first(); else if(not is_selectable(index)) cursor_up(); done = true; } } while(not done); direction = 1; } // ------------------------------------------------------------------ void gwinpick::cursor_pageup() { uint i = index - position; while(not is_selectable(i)) i++; uint min = i + position - index; if(position > min) { display_line(); index = i; position = min; update_cursor(); } else if(index > min) { i = maximum_position - min + position; index -= (index >= i) ? i : index; position = 0; display_page(); if(not is_selectable(index)) cursor_down(); } direction = -1; } // ------------------------------------------------------------------ void gwinpick::cursor_pagedown() { uint max_index = index + maximum_position - position; if(max_index > maximum_index) max_index = maximum_index; while(not is_selectable(max_index)) --max_index; uint max_position = max_index - index + position; if(position < max_position) { if(index == max_index) { if(maximum_position < maximum_index) { position = maximum_position; index = maximum_index; display_page(); update_cursor(); } } else if(max_index >= max_position) { display_line(); position = max_position; index = max_index; update_cursor(); } else if(position != maximum_position) { display_line(); index += maximum_position-position; position = maximum_position; update_cursor(); } } else if(index < maximum_index) { if(index+maximum_position+(maximum_position - max_position)> maximum_index) { position = maximum_index - index; index = maximum_index; } else { index += maximum_position + (maximum_position - max_position); position = maximum_position; } display_page(); } if(not is_selectable(index)) cursor_up(); direction = 1; } // ------------------------------------------------------------------ void gwinpick::cursor_first() { uint min_select = minimum_index; while(not is_selectable(min_select)) min_select++; if(index > min_select) { if(index <= position) { display_line(); index = position = min_select; update_cursor(); } else { index = position = min_select; display_page(); } } direction = -1; } // ------------------------------------------------------------------ void gwinpick::cursor_last() { uint max_select = maximum_index; while(not is_selectable(max_select)) max_select--; if(index < max_select) { if(index + (maximum_position-position) >= maximum_index) { display_line(); position += max_select - index; index = max_select; update_cursor(); } else { position = (maximum_index-index) < maximum_position ? maximum_index-index : maximum_position; position -= maximum_index - max_select; index = max_select; display_page(); } } else if(position < maximum_position) { if(maximum_position < maximum_index) { position = maximum_position + max_select - maximum_index; index = max_select; display_page(); } } direction = 1; } // ------------------------------------------------------------------ void gwinpick::cursor_scroll_up() { uint oldidx = index; do { if(index - position) index--; else while((not is_selectable(index)) and (index < maximum_index)) index++; } while(not is_selectable(index)); if(index != oldidx) display_page(); direction = -1; } // ------------------------------------------------------------------ void gwinpick::cursor_scroll_down() { uint oldidx = index; do { if(index < maximum_index) index++; else while((not is_selectable(--index)) and (index > minimum_index)) ; } while(not is_selectable(index)); if(index!=oldidx) display_page(); direction = 1; } // ------------------------------------------------------------------ void gwinpick::display_line(bool bar) { print_line(index, position, bar); } // ------------------------------------------------------------------ void gwinpick::display_page() { if(index > position) index -= position; else index = 0; register uint m = maximum_index-index; uint n; for(n=0; n<=maximum_position and n<=m; n++) print_line(index+n, n, (position == n)); if(n < ylen) wputx(n, 0, battr|ACSET, _box_table(btype,1), xlen); for(++n; n maximum_position) ? 0 : (maximum_position - botroom); break; case LIST_NEARTOP: { uint room; uint toproom = index; if(toproom > (maximum_position/4)) { if(botroom > (maximum_position/4)) room = maximum_position/4; else if(botroom) room = maximum_position - botroom; else room = maximum_position; } else room = toproom; position = room; } break; case LIST_MIDDLE: { uint room; uint toproom = index; if(toproom > (maximum_position/2)) { if(botroom > (maximum_position/2)) room = maximum_position/2; else if(botroom) room = maximum_position - botroom; else room = maximum_position; } else room = toproom; position = room; } break; case LIST_NEARBOTTOM: { uint room; uint toproom = index; if(toproom > 3*(maximum_position/4)) { if(botroom > 3*(maximum_position/4)) room = 3*(maximum_position/4); else if(botroom) room = maximum_position - botroom; else room = maximum_position; } else room = toproom; position = room; } break; case LIST_BOTTOM: position = maximum_position; break; } update(); } // ------------------------------------------------------------------ int gwinpick::run_picker() { #ifdef GOLD_MOUSE gmou.HideCursor(); #endif // Open and initialize open(); if(helpcat) whelppcat(helpcat); if(not is_selectable(index)) cursor_down(); do { do_delayed(); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif keyok = true; do { key = getxchtick(); if(key == Key_Tick) handle_key(); } while(key == Key_Tick); #ifdef GOLD_MOUSE gmou.HideCursor(); #endif keyok = default_handle_key(); } while(keyok); #ifdef GOLD_MOUSE gmou.HideCursor(); #endif // Close and clean if(helpcat) whelpop(); close(); #ifdef GOLD_MOUSE gmou.ShowCursor(); #endif return 0; } // ------------------------------------------------------------------