#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 ); } } }