508 lines
11 KiB
C++
508 lines
11 KiB
C++
|
// 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 <gkbdcode.h>
|
||
|
#include <gmoubase.h>
|
||
|
#include <gtimall.h>
|
||
|
#include <gutlmisc.h>
|
||
|
#include <gwinall.h>
|
||
|
#include <gwinhelp.h>
|
||
|
#include <gwinpick.h>
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
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<ylen; n++)
|
||
|
wputx(n, 0, wattr, (vchar)' ', xlen);
|
||
|
|
||
|
index += position;
|
||
|
|
||
|
wgotoxy(position, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void gwinpick::open() { update(); }
|
||
|
void gwinpick::close() {}
|
||
|
void gwinpick::precursor() {}
|
||
|
void gwinpick::do_delayed() {}
|
||
|
void gwinpick::scroll(int direction) { wscroll(1, direction); }
|
||
|
bool gwinpick::handle_key() { return false; }
|
||
|
bool gwinpick::is_selectable(uint) { return true; }
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
bool gwinpick::default_handle_key() {
|
||
|
|
||
|
keyok = true;
|
||
|
|
||
|
switch(key) {
|
||
|
case Key_Up: precursor(); cursor_up(); break;
|
||
|
case Key_Dwn: precursor(); cursor_down(); break;
|
||
|
case Key_PgUp: precursor(); cursor_pageup(); break;
|
||
|
case Key_PgDn: precursor(); cursor_pagedown(); break;
|
||
|
case Key_Home: precursor(); cursor_first(); break;
|
||
|
case Key_End: precursor(); cursor_last(); break;
|
||
|
case Key_C_Up: precursor(); cursor_scroll_up(); break;
|
||
|
case Key_C_Dwn: precursor(); cursor_scroll_down(); break;
|
||
|
default:
|
||
|
keyok = handle_key();
|
||
|
}
|
||
|
|
||
|
return keyok;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void gwinpick::update_cursor() {
|
||
|
|
||
|
wgotoxy(position, 0);
|
||
|
display_bar();
|
||
|
// do_delayed();
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|
||
|
void gwinpick::center(int listmode) {
|
||
|
|
||
|
if(maximum_index <= maximum_position) {
|
||
|
position = index;
|
||
|
update();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint botroom = maximum_index - index;
|
||
|
|
||
|
switch(listmode) {
|
||
|
case LIST_TOP:
|
||
|
position = (botroom > 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;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------
|
||
|
|