/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OSCROLL.CPP
//Description : Object scroll bar
#include
#include
#include
#include
#include
#include
#include
#include
//------- Define constant -----------//
#define PRESS_INT_TIME 200 // Press interval time, prevent too fast
// and uncontrollable scrolling, 200ms
#define MINI_INDICATOR_HEIGHT 10 // Minimum height of scroll bar indicator
//------ Begin of function ScrollBar::init -------//
//
// type = 1-Vertical scroll bar (VERTICAL)
// 2-Horizontal scroll bar (HORIZONTAL)
//
// x1,y1,x2,y2 = the coordination of the scroll bar
//
// pageSkipRec = no. of records when page skip up or down
// dispMaxRec = no. of records can be displayed on a page
// totalRec = total no. of records
// [int] pageType = yes or no, refered when down button is pressed
// (default : 1)
// [int] ifFlag = if call vga.d3_panel_down instead of VgaBuf::d3_panel_down
// (default: 0)
// [int] vgaFrontOnly = do all the bitmap processing on the front buffer only
// (default: 0)
void ScrollBar::init(int itype, int ix1, int iy1, int ix2, int iy2,
int pageSkipRec, int dispMaxRec, int totalRec, int pageType, int ifFlag, int vgaFrontOnly)
{
x1 = ix1;
y1 = iy1;
x2 = ix2;
y2 = iy2;
type = itype;
skip_rec_num = pageSkipRec;
disp_rec_num = dispMaxRec;
total_rec_num = totalRec;
page_type = pageType;
if_flag = ifFlag;
vga_front_only = vgaFrontOnly;
if( total_rec_num==0 ) // at must at least be 1, otherwise divided by zero error will appear
total_rec_num=1;
if( type == VERTICAL )
slot_height = y2-y1-28;
else
slot_height = x2-x1-28;
indicator_height = slot_height * disp_rec_num / total_rec_num;
if( indicator_height < MINI_INDICATOR_HEIGHT )
indicator_height = MINI_INDICATOR_HEIGHT;
next_press_time = 0;
}
//------- End of function ScrollBar::init -------//
//------- Begin of function ScrollBar::paint -------//
//
// [int] topRecNo = the top record no. (default : 1)
//
void ScrollBar::paint(int topRecNo)
{
err_when( type == -1 ); // haven't been init()
if( if_flag )
{
vga.d3_panel_down( x1, y1, x2, y2, vga_front_only ); // scroll panel
//-------- cursor button --------//
if( type == VERTICAL )
{
vga.d3_panel_up( x1+2, y1+2 , x2-2, y1+13, vga_front_only); // up button
vga.d3_panel_up( x1+2, y2-13, x2-2, y2-2 , vga_front_only); // down button
}
else
{
vga.d3_panel_up( x1+2 , y1+2, x1+13, y2-2, vga_front_only); // left button
vga.d3_panel_up( x2-13, y1+2, x2-2, y2-2 , vga_front_only); // right button
}
}
else
{
Vga::active_buf->d3_panel_down( x1, y1, x2, y2 ); // scroll panel
//-------- cursor button --------//
if( type == VERTICAL )
{
Vga::active_buf->d3_panel_up( x1+2, y1+2 , x2-2, y1+13); // up button
Vga::active_buf->d3_panel_up( x1+2, y2-13, x2-2, y2-2 ); // down button
}
else
{
Vga::active_buf->d3_panel_up( x1+2 , y1+2, x1+13, y2-2); // left button
Vga::active_buf->d3_panel_up( x2-13, y1+2, x2-2, y2-2 ); // right button
}
}
//--------- display cursor bitmap ----------//
if( type == VERTICAL )
{
image_icon.put_front( x1+4, y1+4 , "SCROLL_U" );
image_icon.put_front( x1+4, y2-11, "SCROLL_D" );
}
else
{
image_icon.put_front( x1+4 , y1+4, "SCROLL_L" );
image_icon.put_front( x2-11, y1+4, "SCROLL_R" );
}
}
//--------- End of function ScrollBar::paint ------------//
//------- Begin of function ScrollBar::refresh -------//
//
// topRecNo = the new top record no.
// [int] forceRefresh = in normal case, only refresh when new top record
// no. <> current top record no.
// but forceRefresh will force refreshing anyway
// ( default : 0)
//
// [int] pageSkipRec = no. of records when page skip up or down
// [int] dispMaxRec = no. of records can be displayed on a page
// [int] totalRec = total no. of records
// ( default: no change for the above 3 parameters )
//
void ScrollBar::refresh(int topRecNo, int forceRefresh, int pageSkipRec, int dispMaxRec, int totalRec)
{
int oldTotalRec = total_rec_num;
err_when( type == -1 ); // haven't been init()
if( pageSkipRec >= 0 )
skip_rec_num = pageSkipRec;
if( dispMaxRec >= 0 )
disp_rec_num = dispMaxRec;
if( totalRec >= 0 )
total_rec_num = totalRec;
if( total_rec_num==0 ) // at must at least be 1, otherwise divided by zero error will appear
total_rec_num=1;
if( type == VERTICAL )
slot_height = y2-y1-28;
else
slot_height = x2-x1-28;
indicator_height = slot_height * disp_rec_num / total_rec_num;
if( indicator_height < MINI_INDICATOR_HEIGHT )
indicator_height = MINI_INDICATOR_HEIGHT;
//------------- refresh display ----------------//
int newY;
if( (newY=rec_to_y(topRecNo)) != indicator_y ||
total_rec_num != oldTotalRec || forceRefresh )
{
indicator_y = newY;
if( if_flag )
{
if( type == VERTICAL )
{
if( !vga.use_back_buf && !vga_front_only )
vga.blt_buf( x1, y1+12, x2, y2-13, 0 );
Vga::active_buf->draw_d3_up_border( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
}
else
{
if( !vga.use_back_buf && !vga_front_only )
vga.blt_buf( x1+12, y1, x2-13, y2, 0 );
Vga::active_buf->draw_d3_up_border( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
}
}
else
{
if( type == VERTICAL )
{
Vga::active_buf->d3_panel_down_clear( x1, y1+12, x2, y2-13 );
Vga::active_buf->d3_panel_up( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
}
else
{
Vga::active_buf->d3_panel_down_clear( x1+12, y1, x2-13, y2 );
Vga::active_buf->d3_panel_up( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
}
}
top_rec_no = topRecNo;
}
}
//--------- End of function ScrollBar::refresh ------------//
//------- Begin of function ScrollBar::detect -------//
//
// Return : =0 if not pressed on scroll bar
// >0 the top record no.
//
int ScrollBar::detect()
{
int pos, topRecNo=top_rec_no;
top_rec_flag = 1; // whether the recno returned by detect()
// is the top_recno or only current recno, is returned by detect_is_top()
//----------- detect for pressing up button --------------//
if( type==VERTICAL && mouse.any_click( x1+2, y1+2, x2-2 , y1+13 ) ||
type==HORIZONTAL && mouse.any_click( x1+2, y1+2, x1+13, y2-2 ) )
{
if( --topRecNo < 1 )
topRecNo = 1;
top_rec_flag=0; // return by detect_is_top()
}
//----------- detect for pressing down button ------------//
if( type==VERTICAL && mouse.any_click( x1+2, y2-13, x2-2, y2-2 ) ||
type==HORIZONTAL && mouse.any_click( x2-13,y1+2 , x2-2, y2-2 ) )
{
if( page_type ) // top record can't be the last record
{
if( ++topRecNo > total_rec_num - disp_rec_num+1 )
topRecNo = total_rec_num - disp_rec_num + 1;
}
else // top record can be the last record
{
if( ++topRecNo > total_rec_num )
topRecNo = total_rec_num;
}
top_rec_flag=0;
}
//------ detect for pressing on scroll slot but not indicator -------//
if( type==VERTICAL && mouse.any_click( x1+2 , y1+14, x2-2 , y2-14 ) ||
type==HORIZONTAL && mouse.any_click( x1+14, y1+2 , x2-14, y2-2 ) ||
mouse.key_code == KEY_PGUP || mouse.key_code == KEY_PGDN )
{
if( type==VERTICAL )
pos = mouse.click_y();
else
pos = mouse.click_x();
if( pos < indicator_y || mouse.key_code == KEY_PGUP ) // page up
{
if( ( topRecNo -= skip_rec_num ) < 1 )
topRecNo = 1;
}
else if( pos >= indicator_y+indicator_height || mouse.key_code == KEY_PGDN ) // page down
{
if( (topRecNo += skip_rec_num) > total_rec_num - disp_rec_num+1 )
{
topRecNo = total_rec_num - disp_rec_num + 1;
if ( topRecNo < 1 )
topRecNo = 1;
}
}
}
//--------- check if display all needed -----------//
if( topRecNo != top_rec_no )
{
if( m.get_time() >= next_press_time ) // prevent too fast scrolling
{
refresh(topRecNo,1);
next_press_time = m.get_time() + PRESS_INT_TIME;
return topRecNo;
}
}
//-------- detect for pulling indicator ------------//
if( type==VERTICAL && mouse.any_click( x1+2 , indicator_y, x2-2, indicator_y+indicator_height-1 ) ||
type==HORIZONTAL && mouse.any_click( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 ) )
{
int lastMouseY = -1;
while( mouse.left_press )
{
sys.yield();
if( type==VERTICAL )
{
if( mouse.left_press && lastMouseY != mouse.cur_y )
{
indicator_y = mouse.cur_y-indicator_height/2;
if( indicator_y < y1+14 )
indicator_y = y1+14;
if( indicator_y > y2-14-indicator_height )
indicator_y = y2-14-indicator_height;
if( if_flag )
{
if( !vga.use_back_buf && !vga_front_only )
vga.blt_buf( x1, y1+12, x2, y2-13, 0 );
Vga::active_buf->draw_d3_up_border( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
}
else
{
Vga::active_buf->d3_panel_down_clear( x1, y1+12, x2, y2-13 ); // scroll panel
Vga::active_buf->d3_panel_down( x1+2, indicator_y, x2-2, indicator_y+indicator_height-1 );
}
lastMouseY = mouse.cur_y;
}
}
else
{
if( mouse.left_press && lastMouseY != mouse.cur_x )
{
indicator_y = mouse.cur_x-indicator_height/2;
if( indicator_y < x1+14 )
indicator_y = x1+14;
if( indicator_y > x2-14-indicator_height )
indicator_y = x2-14-indicator_height;
if( if_flag )
{
if( !vga.use_back_buf && !vga_front_only )
vga.blt_buf( x1+12, y1, x2-13, y2, 0 );
Vga::active_buf->draw_d3_up_border( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
}
else
{
Vga::active_buf->d3_panel_down_clear( x1+12, y1, x2-13, y2 );
Vga::active_buf->d3_panel_down ( indicator_y, y1+2, indicator_y+indicator_height-1, y2-2 );
}
lastMouseY = mouse.cur_x;
}
}
}
refresh(y_to_rec(indicator_y),1);
return top_rec_no;
}
//-----------------------------------------------------------//
return 0;
}
//--------- End of function ScrollBar::detect ------------//
//--------- Begin of function ScrollBar::page_up -------//
//
// Asked by client function to page up
//
// [int] skipLess - no. of record number should skip less
// (default : 0)
// (e.g. when scrolling text, want the last line of
// previous page be the first line of current page,
// then pass 1 as skipLess)
//
// return : the top recno after scrolling
//
int ScrollBar::page_up(int skipLess)
{
if( top_rec_no > 1 )
{
if( (top_rec_no-=skip_rec_num-skipLess) < 1 )
top_rec_no = 1;
refresh(top_rec_no,1);
}
return top_rec_no;
}
//--------- End of function ScrollBar::page_up ----------//
//--------- Begin of function ScrollBar::page_down -------//
//
// Asked by client function to page up
//
// [int] skipLess - no. of record number should skip less
// (default : 0)
// (e.g. when scrolling text, want the last line of
// previous page be the first line of current page,
// then pass 1 as skipLess)
//
// return : the top recno after scrolling
//
int ScrollBar::page_down(int skipLess)
{
if( top_rec_no < total_rec_num - disp_rec_num + 1 )
{
if( (top_rec_no += skip_rec_num-skipLess) > total_rec_num - disp_rec_num + 1 )
{
top_rec_no = total_rec_num - disp_rec_num + 1;
if( top_rec_no < 1 )
top_rec_no = 1;
}
refresh(top_rec_no,1);
}
return top_rec_no;
}
//--------- End of function ScrollBar::page_down ----------//
//--------- Begin of function ScrollBar::detect_top_rec -------//
//
// return whether the recno returned by detect()
// is the top_recno or only current recno
//
int ScrollBar::detect_top_rec()
{
if( top_rec_flag )
{
if( top_rec_no > total_rec_num - disp_rec_num+1 )
return total_rec_num - disp_rec_num + 1;
else
return top_rec_no;
}
else
return 0;
}
//--------- End of function ScrollBar::detect_top_rec ----------//
//--------- Begin of function ScrollBar::rec_to_y -------//
//
// Convert from record no. to y position of scroll bar indicator
//
int ScrollBar::rec_to_y(int recNo)
{
int t;
if( total_rec_num <= 1 || disp_rec_num == total_rec_num )
t = 0;
else
{
t = (slot_height-indicator_height) * (recNo-1) / (total_rec_num-disp_rec_num);
if( t+indicator_height > slot_height )
t = slot_height-indicator_height;
}
if( type == VERTICAL )
return y1 + 14 + t;
else
return x1 + 14 + t;
}
//---------- End of function ScrollBar::rec_to_y ----------//
//--------- Begin of function ScrollBar::y_to_rec -------//
//
// Convert from y position of scroll bar indicator to record no.
//
int ScrollBar::y_to_rec(int y)
{
int t;
if( total_rec_num == 0 )
return 0;
if( slot_height-indicator_height == 0 || disp_rec_num == total_rec_num )
return 1;
if( type == VERTICAL )
t = y1;
else
t = x1;
return (y-t-14) * (total_rec_num-disp_rec_num) / (slot_height-indicator_height) + 1;
}
//---------- End of function ScrollBar::y_to_rec ----------//