00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00032
00033 #include <cxxtls/textviewer.h>
00034 #include <cxxtls/viewermanager.h>
00035 #include <fstream>
00036 #include <cxxtls/strtool.h>
00037 #include <portable_strstream.h>
00038 #include <vector>
00039 #include <portable_io.h>
00040 #include <cxxtls/cursesinterface.h>
00041
00042 namespace cxxtls
00043 {
00044
00045 struct TextViewer::impl
00046
00048
00049 {
00050 FileName filename_;
00051 std::vector<std::string> lines_;
00052 bool active_;
00053 int left_;
00054 int first_row_;
00055 size_t first_mark_;
00056 size_t last_mark_;
00057 size_t page_top_;
00058 size_t cur_;
00059 size_t col_;
00060 size_t page_left_;
00061 std::string search_;
00062
00063 void set_text_attribute(TextViewer*,
00064 viewport*,
00065 size_t line_no,
00066 bool is_bottom,
00067 bool highlight=true
00068 );
00069 void display_line(viewport*, size_t line);
00070
00071 bool find_string(size_t line_no);
00072
00073
00074 };
00075
00076 TextViewer::
00077 ~TextViewer()
00078 {
00079 }
00080
00081 TextViewer::
00082 TextViewer(ViewerManager*vm, FileName filename)
00083 : Viewer(vm),
00084 impl_(new impl)
00085 {
00086
00087
00088 impl_->filename_ = filename;
00089 impl_->active_ = false;
00090 impl_->left_ = 0;
00091 impl_->first_row_ = 1;
00092 impl_->first_mark_ = 0;
00093 impl_->last_mark_ = 0;
00094 impl_->page_top_ = 0;
00095 impl_->cur_ = 0;
00096 impl_->col_ = 0;
00097 impl_->page_left_ = 0;
00098
00099 using namespace std;
00100
00101 std::list<std::string> lines;
00102
00103 fstream file;
00104
00105 file.open(filename.c_str(), ios::in);
00106
00107 if(file.fail())
00108 {
00109 return;
00110 }
00111
00112 istreambuf_iterator<char> nc(file);
00113 istreambuf_iterator<char> lc;
00114
00115 string line;
00116
00117 size_t line_count=0;
00118
00119 while(nc != lc)
00120 {
00121 char c = *nc++;
00122
00123 if(c == '\n')
00124 {
00125 lines.push_back(StrTool::expand_tabs(line,0,'~'));
00126 line.resize(0);
00127 ++line_count;
00128 }
00129 else
00130 line += c;
00131
00132 }
00133
00134 if(line.size())
00135 {
00136 lines.push_back(StrTool::expand_tabs(line,0,'~'));
00137 ++line_count;
00138 }
00139
00140 file.close();
00141
00142 impl_->lines_.resize(line_count);
00143
00144 std::copy(lines.begin(), lines.end(), impl_->lines_.begin());
00145
00146 }
00147
00148 void
00149 TextViewer::impl::
00150 display_line(viewport *vp, size_t line)
00151 {
00152
00153 if(line >= lines_.size())
00154 {
00155 vp->fill_to_eol();
00156 return;
00157 }
00158
00159
00160 std::string const & str = lines_[line];
00161
00162 size_t width = str.size();
00163
00164 if(width >= page_left_ && line <= lines_.size() )
00165 {
00166 std::string::const_iterator start = str.begin() + page_left_,
00167 end = str.end();
00168
00169 vp->write(start, end);
00170
00171 }
00172
00173 vp->fill_to_eol();
00174
00175 }
00176
00177
00178 void
00179 TextViewer::
00180 operator() ( CursorWindow::viewport * vp,
00181 int cmd
00182 )
00184 {
00185
00186
00187 if(cmd == CursorWindow::viewport::repaint_handler::activate)
00188 impl_->active_ = true;
00189 else
00190 if(cmd == CursorWindow::viewport::repaint_handler::deactivate)
00191 impl_->active_ = false;
00192
00193
00194
00195
00196
00197 row_col size = vp->size();
00198 row_col origin = vp->origin();
00199
00200 if(origin.col_ != 0)
00201 impl_->left_ = 1;
00202 else
00203 impl_->left_ = 0;
00204
00205 int i;
00206
00207 vp->set_text_attribute(manager_->inactive_mark_att);
00208
00209 for(i=0; impl_->left_ && i < size.col_; ++i)
00210 {
00211 vp->set_curpos(i,0);
00212
00213 using namespace CursesInterface;
00214
00215 vp->write(line_chars[VL_MIDDLE]);
00216 }
00217
00218
00219
00220 vp->set_curpos(0,impl_->left_);
00221 vp->set_text_attribute( impl_->active_ ? manager_->active_title_att
00222 : manager_->inactive_title_att
00223 );
00224
00225 *vp << "Viewing " << impl_->filename_.shorten(size.col_ - 8);
00226
00227 vp->fill_to_eol();
00228
00229
00230
00231
00232
00233 int row=impl_->first_row_;
00234
00235 int displayable_rows = size.row_ - row;
00236
00237 size_t cur_line = impl_->page_top_;
00238
00239 for(i=0; i < displayable_rows; ++i)
00240 {
00241
00242
00243 if(cur_line >= impl_->lines_.size())
00244 break;
00245
00246
00247
00248 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00249
00250 vp->set_curpos(row, impl_->left_);
00251
00252 impl_->display_line(vp, cur_line);
00253
00254 ++row;
00255 ++cur_line;
00256 }
00257
00258
00259 bool first_time=true;
00260
00261 while(row < size.row_)
00262 {
00263 vp->set_curpos(row,impl_->left_);
00264
00265 if(first_time)
00266 {
00267 first_time=false;
00268
00269 vp->set_text_attribute(ViewerManager::active_title_att);
00270 vp->write("*eof*");
00271 impl_->set_text_attribute(this, vp, cur_line, false, false);
00272 }
00273 else
00274 {
00275 if(row == size.row_-1)
00276 {
00277 vp->set_text_attribute(manager_->bottom_att);
00278 }
00279 else
00280 impl_->set_text_attribute(this, vp, cur_line, false, false);
00281
00282 }
00283
00284 vp->fill_to_eol();
00285
00286 ++row;
00287 }
00288
00289 {
00290
00291
00292 size_t width = size.col_ - impl_->left_;
00293
00294 size_t cur_col = impl_->col_ - impl_->page_left_;
00295
00296 if(cur_col >= width)
00297 impl_->col_ = impl_->page_left_ + width-1;
00298
00299 }
00300
00301
00302 vp->set_curpos(impl_->first_row_ + impl_->cur_ - impl_->page_top_,
00303 impl_->left_ + (impl_->col_ - impl_->page_left_)
00304 );
00305
00306 }
00307
00308
00309 bool
00310 TextViewer::
00311 handle_event( CursorWindow::input_event const * e,
00312 CursorWindow::viewport * vp
00313 )
00315 {
00316
00317 if(e->type_ == input_event::ForceExitKey)
00318 return 2;
00319
00320
00321 if(e->type_ != input_event::FunctionKey &&
00322 e->type_ != input_event::DataKey
00323 )
00324 return false;
00325
00326 if(e->value_ == ('K' - '@'))
00327 return 2;
00328
00329 int edit_func = (*manager_->window()).func[e->value_];
00330
00331
00332
00333
00334 row_col size = vp->size();
00335 row_col origin = vp->origin();
00336
00337 if(origin.col_ != 0)
00338 impl_->left_ = 1;
00339
00340 int row=impl_->first_row_;
00341
00342 size_t cur_line = impl_->cur_;
00343
00344 row += cur_line - impl_->page_top_;
00345
00346 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1, false);
00347
00348
00349 vp->set_curpos(row, impl_->left_);
00350
00351 if(impl_->lines_.size() > cur_line)
00352 impl_->display_line(vp, cur_line);
00353
00354
00355
00356 switch(edit_func)
00357 {
00358 case CursorWindow::func_down:
00359
00360 if(impl_->lines_.size() == 0)
00361 break;
00362
00363 if(cur_line < impl_->lines_.size()-1 &&
00364 row < size.row_ - impl_->first_row_
00365 )
00366 {
00367
00368
00369 ++impl_->cur_;
00370
00371 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00372
00373
00374 vp->set_curpos(row, impl_->left_);
00375
00376 impl_->display_line(vp, cur_line);
00377
00378 ++row;
00379 ++cur_line;
00380 }
00381 else
00382 if(cur_line != impl_->lines_.size()-1)
00383 {
00384
00385
00386
00387
00388 ++cur_line;
00389 ++impl_->cur_;
00390 ++impl_->page_top_;
00391
00392 (*this)(vp,0);
00393
00394 }
00395
00396 break;
00397
00398 case CursorWindow::func_up:
00399
00400 if(impl_->lines_.size() == 0)
00401 break;
00402
00403 if(row != impl_->first_row_)
00404 {
00405
00406
00407 --impl_->cur_;
00408
00409 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00410
00411
00412 vp->set_curpos(row, impl_->left_);
00413
00414 impl_->display_line(vp, cur_line);
00415
00416 --row;
00417 --cur_line;
00418 }
00419 else
00420 if(cur_line != 0)
00421 {
00422
00423 --cur_line;
00424 --impl_->cur_;
00425 --impl_->page_top_;
00426
00427 (*this)(vp,0);
00428
00429 }
00430
00431 break;
00432
00433
00434 case CursorWindow::func_next:
00435
00436 if(impl_->lines_.size() == 0)
00437 break;
00438
00439 {
00440 int page_size = size.row_ - impl_->first_row_;
00441
00442 impl_->cur_ += page_size;
00443
00444 if(impl_->cur_ >= impl_->lines_.size())
00445 {
00446 impl_->cur_ = impl_->lines_.size() -1;
00447 }
00448
00449 if( (int)(impl_->cur_) < 0 )
00450 impl_->cur_ = 0;
00451
00452 impl_->page_top_ += page_size;
00453
00454 if(impl_->page_top_ >= impl_->cur_)
00455 impl_->page_top_ = impl_->cur_;
00456
00457 row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00458 cur_line = impl_->cur_;
00459
00460 (*this)(vp,0);
00461
00462 }
00463 break;
00464
00465
00466 case CursorWindow::func_prior:
00467
00468 if(impl_->lines_.size() == 0)
00469 break;
00470
00471 if(impl_->page_top_ == 0)
00472 {
00473 impl_->cur_ = 0;
00474
00475 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00476
00477
00478 vp->set_curpos(row, impl_->left_);
00479
00480 impl_->display_line(vp, cur_line);
00481
00482 row = impl_->first_row_;
00483 cur_line = 0;
00484 }
00485 else
00486 {
00487 int page_size = size.row_ - impl_->first_row_;
00488
00489 impl_->cur_ -= page_size;
00490
00491
00492
00493
00494 if(impl_->cur_ >= impl_->lines_.size())
00495 {
00496 impl_->cur_ = 0;
00497 }
00498
00499 if( (int)(impl_->cur_) < 0 )
00500 impl_->cur_ = 0;
00501
00502 impl_->page_top_ -= page_size;
00503
00504 if(impl_->page_top_ >= impl_->cur_)
00505 impl_->page_top_ = impl_->cur_;
00506
00507 row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00508 cur_line = impl_->cur_;
00509
00510 (*this)(vp,0);
00511
00512 }
00513 break;
00514
00515
00516 case CursorWindow::func_top:
00517
00518 if(impl_->lines_.size() == 0)
00519 break;
00520
00521 row = impl_->first_row_;
00522 cur_line = 0;
00523 impl_->cur_ = 0;
00524 impl_->page_top_ = 0;
00525
00526 (*this)(vp,0);
00527
00528 break;
00529
00530
00531 case CursorWindow::func_bottom:
00532
00533 if(impl_->lines_.size() == 0)
00534 break;
00535
00536 {
00537 int page_size = size.row_ - impl_->first_row_;
00538
00539 impl_->cur_ = impl_->lines_.size()-1;
00540
00541 impl_->page_top_ = impl_->cur_ - page_size + 1;
00542
00543 if(impl_->page_top_ > impl_->cur_ )
00544 impl_->page_top_ = 0;
00545
00546 cur_line = impl_->cur_;
00547
00548 row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00549
00550 (*this)(vp,0);
00551 }
00552
00553 break;
00554
00555 case CursorWindow::func_right:
00556 {
00557 size_t width = size.col_ - impl_->left_;
00558
00559 ++impl_->col_;
00560
00561 if(impl_->col_ - impl_->page_left_ >= width )
00562 {
00563 impl_->page_left_ += 10;
00564 impl_->col_ = impl_->page_left_ + width - 1;
00565
00566 (*this)(vp,0);
00567 }
00568
00569 }
00570 break;
00571
00572
00573 case CursorWindow::func_left:
00574 {
00575 if(impl_->col_)
00576 {
00577 --impl_->col_;
00578
00579 if(impl_->col_ < impl_->page_left_)
00580 {
00581 impl_->page_left_ -= 10;
00582
00583 if( (int)(impl_->page_left_) < 0 )
00584 impl_->page_left_ = 0;
00585
00586 (*this)(vp,0);
00587
00588 }
00589
00590 }
00591 }
00592 break;
00593
00594 case CursorWindow::func_tab:
00595 {
00596 impl_->page_left_ += 10;
00597 impl_->col_ += 10;
00598 (*this)(vp,0);
00599 }
00600 break;
00601
00602 case CursorWindow::func_btab:
00603 scroll_left:
00604 {
00605 impl_->page_left_ -= 10;
00606 impl_->col_ -= 10;
00607
00608 if( (int)(impl_->page_left_) < 0 )
00609 impl_->page_left_ = 0;
00610
00611 if( (int)(impl_->col_) < 0)
00612 impl_->col_ = 0;
00613
00614 (*this)(vp,0);
00615 }
00616 break;
00617
00618 case CursorWindow::func_home:
00619 {
00620 bool repaint = false;
00621
00622 if(impl_->page_left_)
00623 {
00624 impl_->page_left_ = 0;
00625 repaint = true;
00626 }
00627
00628 impl_->col_ = 0;
00629
00630 if(repaint)
00631 (*this)(vp,0);
00632 }
00633 break;
00634
00635
00636 case CursorWindow::func_end:
00637
00638 if(impl_->lines_.size())
00639 {
00640 size_t width = size.col_ - impl_->left_;
00641
00642 std::string const &cur = impl_->lines_[cur_line];
00643
00644 impl_->col_ = cur.size();
00645
00646 if(impl_->col_ < impl_->page_left_)
00647 {
00648 impl_->page_left_ = impl_->col_ - 10;
00649
00650 if( (int)(impl_->page_left_) < 0)
00651 {
00652 impl_->page_left_ = 0;
00653 }
00654
00655 (*this)(vp,0);
00656 }
00657 else
00658 if(impl_->col_ >= impl_->page_left_ + width)
00659 {
00660 impl_->page_left_ = impl_->col_ - 10;
00661
00662 if( (int)(impl_->page_left_) < 0)
00663 {
00664 impl_->page_left_ = 0;
00665 }
00666
00667 (*this)(vp,0);
00668 }
00669
00670 }
00671 break;
00672
00673 case CursorWindow::func_find:
00674 {
00675 CursorWindow::Dialog d("Find String");
00676
00677 d += new CursorWindow::Dialog::String("name",
00678 "String to search for",
00679 "",
00680 15
00681 );
00682
00683 if(d.popup(manager_->window()))
00684 return false;
00685
00686 impl_->search_ = d.element_value("name");
00687
00688 if(impl_->search_.size() == 0)
00689 return false;
00690
00691 if( impl_->find_string(cur_line-1) )
00692 {
00693 ensure_cursor_visible(vp);
00694
00695 row = impl_->first_row_ + impl_->cur_ - impl_->page_top_;
00696
00697 cur_line = impl_->cur_;
00698 }
00699
00700 }
00701 break;
00702
00703 case CursorWindow::func_findnxt:
00704
00705 if( impl_->find_string(cur_line) )
00706 {
00707 ensure_cursor_visible(vp);
00708
00709 row = impl_->first_row_ + impl_->cur_ - impl_->page_top_;
00710
00711 cur_line = impl_->cur_;
00712 }
00713 break;
00714
00715 case CursorWindow::func_mark:
00716 goto mark_line;
00717
00718 case CursorWindow::func_data:
00719
00720 if(impl_->lines_.size() == 0 && e->value_ != 'q' )
00721 break;
00722
00723 switch(e->value_)
00724 {
00725
00726 case 'q': return 2;
00727
00728 case 'p':
00729
00730 if(impl_->first_mark_ != impl_->last_mark_)
00731 {
00732
00733
00734 CursorWindow::FileSelector d("Put Marked lines to a file", impl_->filename_.dirname() + "*", "");
00735
00736 FileName fullname = d.popup(manager_->window(), this);
00737
00738
00739 if(fullname == "")
00740 return 0;
00741
00742
00743 FileName tmp(fullname);
00744 tmp.convert_to_absolute_path();
00745
00746 fullname = tmp;
00747
00748 {
00749 using namespace std;
00750
00751 fstream file;
00752
00753 file.open(fullname.c_str(), ios::out);
00754
00755 if(file.fail())
00756 {
00757 CursorWindow::Message m("Error");
00758
00759 m += "Sorry, could not open the target file for write";
00760 m += "";
00761 m += "Press enter to continue";
00762
00763 m.popup(manager_->window());
00764 return 0;
00765
00766 break;
00767 }
00768
00769 ostreambuf_iterator<char> nc(file);
00770
00771 size_t i;
00772
00773 for(i= impl_->first_mark_; i < impl_->last_mark_; ++i)
00774 {
00775 std::string &s = impl_->lines_[i];
00776
00777 std::copy(s.begin(), s.end(), nc);
00778
00779 nc = copy_end_of_line(nc);
00780
00781 }
00782
00783 file.close();
00784
00785 }
00786
00787
00788 }
00789 break;
00790
00791 case 'm':
00792 mark_line:
00793 {
00794 if(impl_->first_mark_ == impl_->last_mark_)
00795 {
00796
00797
00798 impl_->first_mark_ = impl_->cur_;
00799 impl_->last_mark_ = impl_->cur_ + 1;
00800 }
00801 else
00802 {
00803
00804
00805 if(impl_->last_mark_ == impl_->first_mark_ + 1)
00806 {
00807
00808
00809 if(impl_->cur_ == impl_->first_mark_)
00810 {
00811
00812
00813
00814 impl_->last_mark_ = impl_->first_mark_ = 0;
00815
00816 }
00817 else
00818 {
00819
00820
00821 if(impl_->cur_ < impl_->first_mark_)
00822 impl_->first_mark_ = impl_->cur_;
00823 else
00824 impl_->last_mark_ = impl_->cur_ + 1;
00825 }
00826
00827 }
00828 else
00829 impl_->first_mark_ = impl_->last_mark_ = 0;
00830
00831 }
00832
00833 (*this)(vp,0);
00834
00835 }
00836 break;
00837 }
00838 break;
00839
00840 default:
00841
00842 if(e->value_ == ('\\' - '@'))
00843 goto scroll_left;
00844
00845 break;
00846 }
00847
00848
00849
00850 impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00851
00852 vp->set_curpos(row, impl_->left_);
00853
00854 impl_->display_line(vp, cur_line);
00855
00856 vp->set_curpos(row,
00857 impl_->left_ + (impl_->col_ - impl_->page_left_)
00858 );
00859
00860
00861 return 0;
00862
00863 }
00864
00865 void
00866 TextViewer::
00867 help()
00868 {
00869 std::auto_ptr< std::list< std::string > >
00870 viewer_help( new std::list< std::string > );
00871
00872 viewer_help->push_back("Help for the text viewer");
00873 viewer_help->push_back("");
00874 viewer_help->push_back(" Use the normal scrolling and cursor movement keys.");
00875 viewer_help->push_back("");
00876 viewer_help->push_back(" The 'm' key toggles inclusion of the current line in");
00877 viewer_help->push_back(" marked region.");
00878 viewer_help->push_back("");
00879 viewer_help->push_back(" The 'p' key lets you saved the marked lines to a file.");
00880 viewer_help->push_back("");
00881 viewer_help->push_back(" The '^S' key lets you begin a search for a string");
00882 viewer_help->push_back("");
00883 viewer_help->push_back(" The '^N' key lets repeat a search for same string used before");
00884 viewer_help->push_back("");
00885 viewer_help->push_back(" The 'Tab' key lets scroll to the right by 10 characters");
00886 viewer_help->push_back("");
00887 viewer_help->push_back(" The 'Ctrl-\\' key lets scroll to the left by 10 characters");
00888 viewer_help->push_back("");
00889 viewer_help->push_back(" The 'shift Tab' key also lets scroll to the left by 10 characters");
00890
00891
00892
00893 manager_->help_helper(*viewer_help);
00894 }
00895
00896 Viewer*
00897 TextViewer::
00898 app(ViewerManager*vm, std::string &fullname)
00899 {
00900 if(fullname.size() == 0)
00901 {
00902
00903
00904 CursorWindow::Dialog d("File name");
00905
00906 d += new CursorWindow::Dialog::String("name",
00907 "path",
00908 "*",
00909 40
00910 );
00911
00912 if(d.popup(vm->window()))
00913 return 0;
00914
00915 fullname = d.element_value("name");
00916
00917 if(fullname == "")
00918 return 0;
00919
00920
00921 FileName tmp(fullname);
00922 tmp.convert_to_absolute_path();
00923
00924 fullname = tmp;
00925
00926 }
00927 return new TextViewer(vm,fullname);
00928
00929 }
00930
00931 std::string TextViewer::app_name = "VIEW TEXT";
00932
00933 std::string TextViewer::description() const
00934 {
00935 return impl_->filename_;
00936 }
00937
00938 void
00939 TextViewer::impl::
00940 set_text_attribute(TextViewer* viewer,
00941 viewport* vp,
00942 size_t line,
00943 bool is_bottom,
00944 bool highlight
00945 )
00946 {
00947 if(line >= first_mark_ && line < last_mark_)
00948 {
00949 if(highlight)
00950 {
00951 if(active_)
00952 {
00953 vp->set_text_attribute(ViewerManager::highlighted_att);
00954 }
00955 else
00956 vp->set_text_attribute(ViewerManager::inactive_mark_att);
00957 }
00958 else
00959 vp->set_text_attribute(ViewerManager::inactive_mark_att);
00960
00961 }
00962 else
00963 if(line == cur_)
00964 vp->set_text_attribute(active_ ? (is_bottom ? ViewerManager::bottom_att
00965 : ViewerManager::normal_att)
00966 : ViewerManager::inactive_mark_att);
00967 else
00968 if(is_bottom)
00969 vp->set_text_attribute(ViewerManager::bottom_att);
00970 else
00971 vp->set_text_attribute(ViewerManager::normal_att);
00972 }
00973
00974 struct caseless_compare
00975 {
00976 bool operator() (char a, char b)
00977 {
00978 if(a == b)
00979 return true;
00980 else
00981 {
00982
00983
00984 if( (a < 'a' && b < 'a')
00985 ||
00986 (a >= 'a' && b >= 'a')
00987 )
00988 {
00989
00990
00991
00992 return false;
00993 }
00994 else
00995 {
00996
00997
00998
00999 if(islower(a))
01000 a = toupper(a);
01001
01002 if(islower(b))
01003 b = toupper(b);
01004 }
01005 }
01006
01007 return a == b;
01008
01009 }
01010 };
01011
01012 bool
01013 TextViewer::impl::
01014 find_string(size_t line_before)
01015 {
01016 size_t line = line_before + 1;
01017
01018 while(line < lines_.size())
01019 {
01020 std::string::iterator start = std::search(lines_[line].begin(),
01021 lines_[line].end(),
01022 search_.begin(),
01023 search_.end(),
01024 caseless_compare()
01025 );
01026 if(start != lines_[line].end())
01027 {
01028 col_ = start - lines_[line].begin();
01029 break;
01030 }
01031
01032 ++line;
01033 }
01034
01035 if(line == lines_.size())
01036 return false;
01037
01038
01039
01040
01041 cur_ = line;
01042
01043 return true;
01044
01045 }
01046
01047
01048 void
01049 TextViewer::
01050 ensure_cursor_visible(viewport* vp)
01051 {
01052 row_col size = vp->size();
01053
01054 size_t usable_columns = size.col_ - impl_->left_;
01055 size_t usable_rows = size.row_ - impl_->first_row_;
01056
01057 size_t column_offset = impl_->col_ - impl_->page_left_;
01058 size_t row_offset = impl_->cur_ - impl_->page_top_;
01059
01060 if( (row_offset >= usable_rows)
01061 ||
01062 (column_offset >= usable_columns)
01063 ||
01064 (impl_->col_ < impl_->page_left_)
01065 )
01066 {
01067
01068
01069 if(row_offset >= usable_rows )
01070 {
01071 impl_->page_top_ = impl_->cur_ - size.row_/2;
01072
01073 if( (int)(impl_->page_top_) < 0)
01074 impl_->page_top_ = 0;
01075 }
01076
01077 if( impl_->col_ < impl_->page_left_
01078 ||
01079 column_offset >= usable_columns
01080 )
01081 {
01082 impl_->page_left_ = impl_->col_ - 10;
01083
01084 if( (int)(impl_->page_left_) < 0 )
01085 impl_->page_left_ = 0;
01086 }
01087
01088 (*this)(vp,0);
01089
01090 }
01091 }
01092
01093 }