Hist.cc 3.75 KiB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if unix /* but not WIN32 */
# include <alloca.h>
#else
# include "winjunk.h"
#endif
#include "FL/Fl.H"
#include "FL/Fl_Browser.H"
#include "FL/Fl_Input.H"
#include "Hist.H"
void HistInput::hist( Hist *h ) {
hist_ = h;
if(h) h->input(this);
}
int HistInput::handle( int ev ) {
if(hist_ && hist_->handle_nav(ev))
return 1;
return Fl_Input::handle(ev);
}
void HistBrowser::hist( Hist *h ) {
hist_ = h;
if(h) h->browser(this);
}
int HistBrowser::handle( int ev ) {
if(hist_ && hist_->handle_nav(ev))
return 1;
return Fl_Browser::handle(ev);
}
int Hist::handle( int ev ) {
if(handle_nav(ev))
return 1;
return Fl_Group::handle(ev);
}
int HistBrowser::selscanup( int from ) {
while(from < size() && !selected(from))
from++;
return from;
}
int HistBrowser::selscandown( int from ) {
if(from > size()) from = size()-1;
while(from > 0 && selected(from))
from--;
return from;
}
void HistBrowser::tighten_histrange() {
int i;
if(min <= 0) min = 1;
if(max > size()) max = size();
for(i = min; i <= max && !selected(i); i++)
;
min = i;
for(i = max; i >= min && !selected(i); i--)
;
max = i;
}
static char msgprefix[] = "@C2@.# ";
#define MSGPREFIXSKIP (sizeof(msgprefix) - 3) /* retain "# " */
int HistBrowser::is_cmd( int line ) {
if(line <= 0 || line > size())
return 0;
return 0!=strncmp(text(line), msgprefix, sizeof(msgprefix)-1);
}
#define MAXHISTORY 500
void HistBrowser::addline( const char *str, int as_cmd ) {
char *what = (char *)str;
if(as_cmd) {
what = (char *)alloca( strlen(str) + sizeof(msgprefix) + 1 );
strcpy(what, msgprefix);
strcpy(what+sizeof(msgprefix)-1, str);
}
if(size() >= MAXHISTORY) {
for(int hyst = 0; hyst < 5; hyst++) {
remove( 1 );
min--;
max--;
}
}
add( what, (void *)as_cmd );
middleline( size() ); // bottomline() won't do
}
int HistBrowser::find_cmd( int fromline, int incr )
{
while(fromline > 0 && fromline <= size()) {
if(is_cmd(fromline))
return fromline;
fromline += incr;
}
return 0;
}
int HistBrowser::handle_nav( int ev ) {
int incr = 1;
int line;
HistInput *inp;
if(hist_ == NULL || (inp = hist_->input()) == NULL)
return 0;
if(ev == FL_KEYBOARD || ev == FL_SHORTCUT) {
switch(Fl::event_key()) {
case FL_Up:
case FL_Page_Up:
incr = -1; /* and fall into... */
case FL_Down:
case FL_Page_Down:
tighten_histrange();
line = selected(min) ? min : size()-incr;
line = find_cmd( line+incr, incr );
if(line) {
deselect(0);
select(line, 1);
middleline( line );
min = max = line;
inp->value( text(line) );
inp->position( inp->size(), inp->size() );
}
inp->take_focus();
return 1;
}
}
return 0;
}
void HistBrowser::picked_cb( HistBrowser *brow, void * ) {
int i, which = brow->value();
if(which <= 0) return;
if(brow->min > which) brow->min = which;
if(brow->max < which) brow->max = which;
brow->tighten_histrange();
if(!Fl::event_state(FL_BUTTON1|FL_BUTTON2|FL_BUTTON3)) {
// All mouse-buttons released -- it's worth rebuilding our selection.
int pos, len = 0;
const char *s;
for(i = brow->min; i <= brow->max; i++) {
if(brow->selected(i)) {
s = brow->text(i);
if(!strncmp(s, msgprefix, sizeof(msgprefix)-1))
s += MSGPREFIXSKIP;
len += strlen(s) + 1;
}
}
if(len == 0) {
Fl::selection_owner( NULL );
} else {
char *all = (char *)alloca( len + 1 );
pos = 0;
for(i = brow->min; i <= brow->max; i++) {
if(brow->selected(i)) {
s = brow->text(i);
if(!strncmp(s, msgprefix, sizeof(msgprefix)-1))
s += MSGPREFIXSKIP;
len = strlen(s);
memcpy(&all[pos], s, len);
pos += len;
all[pos++] = '\n';
}
}
Fl::selection( *brow, all, pos );
}
}
}