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
00029
00030 #include <cxxtls/foreach.h>
00031 #include <cxxtls/cursorwindow.h>
00032 #include <cxxtls/cursesinterface.h>
00033 #include <cxxtls/strtool.h>
00034 #include <cxxtls/file.h>
00035 #include <cxxtls/viewer.h>
00036 #include <portable_io.h>
00037 #include <set>
00038
00039 namespace cxxtls
00040 {
00041
00042 using namespace CursesInterface;
00043
00044 int CursorWindow::normal_att = CursorWindow::normal;
00045 int CursorWindow::active_title_att = CursorWindow::reverse_bold;
00046 int CursorWindow::inactive_title_att= CursorWindow::bold_ul;
00047 int CursorWindow::active_mark_att = CursorWindow::reverse_ul;
00048 int CursorWindow::inactive_mark_att = CursorWindow::bold;
00049 int CursorWindow::bottom_att = CursorWindow::underlined;
00050 int CursorWindow::highlighted_att = CursorWindow::reversed;
00051 int CursorWindow::dialog_normal_att = CursorWindow::reverse_bold;
00052 int CursorWindow::dialog_title_att = CursorWindow::rev_ul_bold;
00053
00054 typedef CursorWindow::row_col row_col;
00055 typedef std::string string;
00056 typedef CursorWindow::viewport viewport;
00057
00058 const long WScale = 10000;
00059
00060
00061
00062
00063 const long WHalfCell = (WScale / 2) - 1 ;
00064
00065 struct viewport::port
00066
00068 {
00069 row_col scaled_origin_;
00070 row_col scaled_size_;
00071 row_col curpos_;
00072 CursorWindow* window_;
00073 int current_attribute_;
00074 repaint_handler* handler_;
00075 viewport::position position_;
00076
00077 port(CursorWindow* w, viewport::repaint_handler* h, viewport::position p)
00078 : curpos_(0,0),
00079 window_(w),
00080 current_attribute_(CursorWindow::normal),
00081 handler_(h),
00082 position_(p)
00083 {
00084 scaled_origin_.row_ = 0;
00085 scaled_origin_.col_ = 0;
00086
00087 scaled_size_.row_ = w->size().row_ * WScale;
00088 scaled_size_.col_ = w->size().col_ * WScale;
00089
00090 }
00091
00092 row_col size()
00095 {
00096 row_col rv(scaled_size_);
00097
00098 rv.row_ /= WScale;
00099 rv.col_ /= WScale;
00100
00101 return rv;
00102
00103 }
00104
00105 row_col origin()
00108 {
00109 row_col rv(scaled_origin_);
00110
00111 rv.row_ /= WScale;
00112 rv.col_ /= WScale;
00113
00114 return rv;
00115
00116 }
00117
00118 };
00119
00120 #define port viewport::port
00121 #define repaint_handler viewport::repaint_handler
00122
00123
00124 struct compare_port_by_row_col
00125 {
00126 bool operator() (port* a, port* b)
00127 {
00128 if(a == b)
00129 return false;
00130
00131 int a_row = a->scaled_origin_.row_;
00132 int b_row = b->scaled_origin_.row_;
00133
00134 if(a_row < b_row)
00135 return true;
00136
00137 if(a_row > b_row)
00138 return false;
00139
00140
00141
00142 int a_col = a->scaled_origin_.col_;
00143 int b_col = b->scaled_origin_.col_;
00144
00145 if(a_col < b_col)
00146 return true;
00147
00148 return false;
00149
00150
00151 }
00152 };
00153
00154 struct compare_port_by_col_row
00155 {
00156 bool operator() (port* a, port* b)
00157 {
00158 if(a == b)
00159 return false;
00160
00161 int a_col = a->scaled_origin_.col_;
00162 int b_col = b->scaled_origin_.col_;
00163
00164 if(a_col < b_col)
00165 return true;
00166
00167 if(a_col > b_col)
00168 return false;
00169
00170
00171
00172 int a_row = a->scaled_origin_.row_;
00173 int b_row = b->scaled_origin_.row_;
00174
00175 if(a_row < b_row)
00176 return true;
00177
00178 return false;
00179
00180 }
00181 };
00182
00183
00184
00185
00186
00187
00188
00189 class CursorWindow::Window
00190
00195
00196 {
00197 public:
00198
00199 int current_attribute_;
00200 row_col curpos_;
00201 row_col size_;
00202 char const * error_;
00203 bool open_;
00204 resize_handler * resize_handler_;
00205
00206 port* viewport_[100];
00207 int active_viewport_;
00208 int viewports_;
00209 int needs_resized_;
00210
00211 Window()
00212 : current_attribute_(normal),
00213 curpos_(0,0),
00214 size_(0,0),
00215 error_(0),
00216 open_(0),
00217 resize_handler_(0),
00218 active_viewport_(0),
00219 viewports_(0),
00220 needs_resized_(0)
00221 {
00222
00223 }
00224
00225 port* new_port(CursorWindow* w, repaint_handler* h, viewport::position p)
00226 {
00227 port* n = new port(w,h,p);
00228
00229 viewport_[viewports_++] = n;
00230
00231 return n;
00232
00233 }
00234
00235 void cover_hole(port* deceased)
00237 {
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 typedef std::set<port*, compare_port_by_row_col> row_major_set_type;
00355 typedef std::set<port*, compare_port_by_col_row> col_major_set_type;
00356
00357 row_major_set_type rowset;
00358 col_major_set_type colset;
00359
00360 int i;
00361
00362 for(i=0; i < viewports_; ++i)
00363 {
00364 port* p = viewport_[i];
00365
00366 if(p->position_ == viewport::tiled)
00367 {
00368 rowset.insert(p);
00369 colset.insert(p);
00370 }
00371
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 row_col origin;
00383 row_col size;
00384
00385 origin.row_ = deceased->scaled_origin_.row_ / WScale;
00386 origin.col_ = deceased->scaled_origin_.col_ / WScale;
00387 size.row_ = deceased->scaled_size_.row_ / WScale;
00388 size.col_ = deceased->scaled_size_.col_ / WScale;
00389
00390 row_major_set_type::iterator rowscan;
00391 col_major_set_type::iterator colscan;
00392
00393 for(rowscan = rowset.begin(); rowscan != rowset.end(); ++rowscan)
00394 {
00395 port *cur = *rowscan;
00396
00397 row_col curorg;
00398 row_col cursiz;
00399
00400 curorg.row_ = cur->scaled_origin_.row_ / WScale;
00401 curorg.col_ = cur->scaled_origin_.col_ / WScale;
00402 cursiz.row_ = cur->scaled_size_.row_ / WScale;
00403 cursiz.col_ = cur->scaled_size_.col_ / WScale;
00404
00405 if(curorg.row_ != origin.row_)
00406 continue;
00407
00408 if(origin.col_ == 0)
00409 {
00410
00411
00412 if(curorg.col_ == (origin.col_ + size.col_)
00413 &&
00414 cursiz.row_ == size.row_
00415 )
00416 {
00417
00418
00419
00420
00421 cur->scaled_origin_.col_ = origin.col_ * WScale;
00422 cur->scaled_size_.col_ += size.col_ * WScale;
00423
00424 return;
00425
00426 }
00427
00428 }
00429 else
00430 {
00431
00432
00433 if(origin.col_ == (curorg.col_ + cursiz.col_)
00434 &&
00435 size.row_ == cursiz.row_
00436 )
00437 {
00438
00439
00440
00441
00442 cur->scaled_size_.col_ += size.col_ * WScale;
00443
00444 return;
00445 }
00446
00447
00448 }
00449 }
00450
00451
00452
00453
00454
00455
00456 for(colscan = colset.begin(); colscan != colset.end(); ++colscan)
00457 {
00458 port *cur = *colscan;
00459
00460 row_col curorg;
00461 row_col cursiz;
00462
00463 curorg.row_ = cur->scaled_origin_.row_ / WScale;
00464 curorg.col_ = cur->scaled_origin_.col_ / WScale;
00465 cursiz.row_ = cur->scaled_size_.row_ / WScale;
00466 cursiz.col_ = cur->scaled_size_.col_ / WScale;
00467
00468 if(curorg.col_ != origin.col_)
00469 continue;
00470
00471 if(origin.row_ == 0)
00472 {
00473
00474
00475 if(curorg.row_ == (origin.row_ + size.row_)
00476 &&
00477 cursiz.col_ == size.col_
00478 )
00479 {
00480
00481
00482
00483
00484 cur->scaled_origin_.row_ = origin.row_ * WScale;
00485 cur->scaled_size_.row_ += size.row_ * WScale;
00486
00487 return;
00488
00489 }
00490
00491 }
00492 else
00493 {
00494
00495
00496 if(origin.row_ == (curorg.row_ + cursiz.row_)
00497 &&
00498 size.col_ == cursiz.col_
00499 )
00500 {
00501
00502
00503
00504
00505 cur->scaled_size_.row_ += size.row_ * WScale;
00506
00507 return;
00508 }
00509
00510
00511 }
00512 }
00513
00514
00515
00516
00517
00518 for(rowscan = rowset.begin(); rowscan != rowset.end(); ++rowscan)
00519 {
00520
00521
00522
00523
00524
00525
00526 port *cur = *rowscan;
00527
00528 row_col curorg;
00529 row_col cursiz;
00530
00531 curorg.row_ = cur->scaled_origin_.row_ / WScale;
00532 curorg.col_ = cur->scaled_origin_.col_ / WScale;
00533 cursiz.row_ = cur->scaled_size_.row_ / WScale;
00534 cursiz.col_ = cur->scaled_size_.col_ / WScale;
00535
00536 if(size_.row_ == size.row_)
00537 {
00538
00539
00540 if(origin.col_ == 0)
00541 {
00542
00543
00544 if(curorg.col_ == size.col_)
00545 {
00546 cur->scaled_origin_.col_ = 0;
00547 cur->scaled_size_.col_ += WScale * size.col_;
00548 }
00549
00550 }
00551 else
00552 {
00553
00554
00555 if(curorg.col_ + cursiz.col_ == origin.col_)
00556 {
00557 cur->scaled_size_.col_ += WScale * size.col_;
00558 }
00559
00560 }
00561 }
00562 else
00563 if(size_.col_ == size.col_)
00564 {
00565 if(origin.row_ == 0)
00566 {
00567
00568
00569 if(curorg.row_ == size.row_)
00570 {
00571 cur->scaled_origin_.row_ = 0;
00572 cur->scaled_size_.row_ += WScale * size.row_;
00573 }
00574
00575 }
00576 else
00577 {
00578
00579
00580 if(curorg.row_ + cursiz.row_ == origin.row_)
00581 {
00582 cur->scaled_size_.row_ += WScale * size.row_;
00583 }
00584
00585 }
00586 }
00587 else
00588 {
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 if( ( (curorg.row_ == origin.row_) ||
00614 (curorg.row_ + cursiz.row_) == (origin.row_ + size.row_)
00615 )
00616 &&
00617 (
00618 (curorg.col_ + cursiz.col_) == origin.col_ ||
00619 (origin.col_ + size.col_) == curorg.col_
00620 )
00621 &&
00622 (
00623 (curorg.row_ >= origin.row_) &&
00624 (curorg.row_ + cursiz.row_) <= (origin.row_ + size.row_)
00625 )
00626 )
00627 {
00628
00629
00630 if(curorg.col_ == origin.col_ + size.col_)
00631 {
00632
00633
00634 cur->scaled_origin_.col_ = origin.col_ * WScale;
00635 cur->scaled_size_.col_ += size.col_ * WScale;
00636
00637 }
00638 else
00639 {
00640 cur->scaled_size_.col_ += size.col_ * WScale;
00641 }
00642
00643 }
00644 else
00645 if( ( (curorg.col_ == origin.col_) ||
00646 (curorg.col_ + cursiz.col_) == (origin.col_ + size.col_)
00647 )
00648 &&
00649 (
00650 (curorg.row_ + cursiz.row_) == origin.row_ ||
00651 (origin.row_ + size.row_) == curorg.row_
00652 )
00653 &&
00654 (
00655 (curorg.col_ >= origin.col_) &&
00656 (curorg.col_ + cursiz.col_) <= (origin.col_ + size.col_)
00657 )
00658 )
00659 {
00660
00661
00662 if(curorg.col_ == origin.col_ + size.col_)
00663 {
00664
00665
00666 cur->scaled_origin_.row_ = origin.row_ * WScale;
00667 cur->scaled_size_.row_ += size.row_ * WScale;
00668
00669 }
00670 else
00671 {
00672 cur->scaled_size_.row_ += size.row_ * WScale;
00673 }
00674 }
00675
00676 }
00677 }
00678
00679
00680
00681 }
00682
00683 void delete_port(port* p)
00684 {
00685 int i;
00686
00687 needs_resized_ = true;
00688
00689 cover_hole(p);
00690
00691 for(i=0; i < viewports_; ++i)
00692 {
00693 if(viewport_[i] == p)
00694 {
00695
00696
00697
00698 delete p;
00699
00700 while(i < viewports_)
00701 {
00702 viewport_[i] = viewport_[i+1];
00703 ++i;
00704 }
00705
00706 --viewports_;
00707
00708 active_viewport_ = viewports_-1;
00709
00710 if(viewports_)
00711 {
00712 viewport a(viewport_[active_viewport_]);
00713
00714 port* active_port = viewport_[active_viewport_];
00715 repaint_handler* rh = active_port->handler_;
00716
00717 (*rh)(&a, repaint_handler::activate);
00718
00719 }
00720
00721 return;
00722
00723 }
00724 }
00725 }
00726
00727 void repaint_ports()
00728 {
00729 int i;
00730
00731 int resize_cmd = repaint_handler::resize;
00732
00733 for(i=0; i < viewports_; ++i)
00734 {
00735 if( i != active_viewport_ )
00736 {
00737 port* p = viewport_[i];
00738
00739 viewport v(p);
00740
00741 (*p->handler_)(&v, resize_cmd);
00742
00743 }
00744 }
00745
00746 if(i)
00747 {
00748 port* a = viewport_[active_viewport_];
00749
00750 viewport v(a);
00751
00752 (*a->handler_)(&v, resize_cmd);
00753
00754 }
00755
00756 }
00757
00758 void activate(viewport* p)
00759 {
00760 if(viewports_ && active_viewport_ >= 0)
00761 {
00762 port* a = viewport_[active_viewport_];
00763
00764 viewport v(a);
00765
00766 (*a->handler_)(&v, repaint_handler::deactivate);
00767 }
00768
00769 int i;
00770
00771 for(i=0; i < viewports_; ++i)
00772 {
00773 if(viewport_[i] == p->port_)
00774 {
00775 active_viewport_ = i;
00776 (*p->port_->handler_)(p, repaint_handler::activate);
00777 break;
00778 }
00779 }
00780
00781 }
00782
00783
00784
00785
00786 void resize_viewports(
00787 row_col const &old_size,
00788 row_col const &new_size
00789 )
00790 {
00791 long scaled_row = new_size.row_ * WScale;
00792 long scaled_col = new_size.col_ * WScale;
00793
00794
00795 for(int i = 0; i < viewports_; ++i)
00796 {
00797 port* p = viewport_[i];
00798
00799 long tmp;
00800
00801
00802
00803
00804
00805 int right_side = (p->scaled_origin_.col_ + p->scaled_size_.col_) / WScale;
00806 bool right_aligned = right_side >= old_size.col_;
00807
00808 int bottom_side = (p->scaled_origin_.row_ + p->scaled_size_.row_) / WScale;
00809 bool bottom_aligned = bottom_side >= old_size.row_;
00810
00811
00812
00813
00814 tmp = p->scaled_origin_.row_;
00815 tmp *= new_size.row_;
00816 tmp /= old_size.row_;
00817
00818 if(tmp > scaled_row)
00819 {
00820 tmp = scaled_row;
00821 }
00822
00823 p->scaled_origin_.row_ = tmp;
00824
00825 tmp = p->scaled_origin_.col_;
00826 tmp *= new_size.col_;
00827 tmp /= old_size.col_;
00828
00829 if(tmp > scaled_col)
00830 {
00831 tmp = scaled_col;
00832 }
00833 p->scaled_origin_.col_ = tmp;
00834
00835
00836
00837
00838 tmp = p->scaled_size_.row_;
00839 tmp *= new_size.row_;
00840 tmp /= old_size.row_;
00841
00842 if(tmp + p->scaled_origin_.row_ > scaled_row)
00843 {
00844 tmp = scaled_row - p->scaled_origin_.row_;
00845 }
00846 p->scaled_size_.row_ = tmp;
00847
00848 tmp = p->scaled_size_.col_;
00849 tmp *= new_size.col_;
00850 tmp /= old_size.col_;
00851
00852 if(tmp + p->scaled_origin_.col_ > scaled_col)
00853 {
00854 tmp = scaled_col - p->scaled_origin_.col_;
00855 }
00856 p->scaled_size_.col_ = tmp;
00857
00858
00859
00860 tmp = p->curpos_.row_ * WScale;
00861 tmp *= new_size.row_;
00862 tmp /= old_size.row_;
00863 p->curpos_.row_ = tmp / WScale;
00864
00865 tmp = p->curpos_.col_ * WScale;
00866 tmp *= new_size.col_;
00867 tmp /= old_size.col_;
00868 p->curpos_.col_ = tmp / WScale;
00869
00870
00871
00872
00873 if(p->position_ == viewport::floating)
00874 {
00875
00876
00877
00878
00879
00880 continue;
00881
00882 }
00883
00884 if(right_aligned)
00885 {
00886 int origin_col = p->scaled_origin_.col_ / WScale;
00887
00888 int real_width = new_size.col_ - origin_col;
00889
00890 p->scaled_size_.col_ = real_width * WScale;
00891 }
00892
00893 if(bottom_aligned)
00894 {
00895 int origin_row = p->scaled_origin_.row_ / WScale;
00896
00897 int real_height = new_size.row_ - origin_row;
00898
00899 p->scaled_size_.row_ = real_height * WScale;
00900
00901 }
00902
00903 }
00904
00905 }
00906
00907 };
00908
00909 static bool key_map_initialized = false;
00910
00911
00912 std::map<int,int> CursorWindow::func;
00913
00914 string CursorWindow::word;
00915
00916 CursorWindow::
00917 CursorWindow()
00918 {
00919 window_ = new CursorWindow::Window;
00920
00921 if(!key_map_initialized)
00922 {
00923 key_map_initialized = true;
00924
00925 func[key_up ] = func_up;
00926 func[key_down ] = func_down;
00927 func[key_left ] = func_left;
00928 func[key_right] = func_right;
00929 func[key_dc ] = func_dc;
00930 func[key_bs ] = func_dc_prev;
00931 #ifdef _MSC_VER
00932 func[0x08 ] = func_dc_prev;
00933
00934 #endif
00935
00936
00937 func[key_home ] = func_home;
00938 func[0x01 ] = func_home;
00939 func[key_end ] = func_end;
00940 func[0x05 ] = func_end;
00941 func[key_prior] = func_prior;
00942 func[0x0f ] = func_prior;
00943 func[key_next ] = func_next;
00944 func[0x04 ] = func_next;
00945 func[0x09 ] = func_tab;
00946 func[key_btab ] = func_btab;
00947 func[0x14 ] = func_top;
00948 func[0x02 ] = func_bottom;
00949 func[0x1b ] = func_esc;
00950 func[0x03 ] = func_esc;
00951 func['\r' ] = func_enter;
00952 func[0x0b ] = func_clreol;
00953 func[0x17 ] = func_nextwd;
00954 func[0x11 ] = func_prevwd;
00955 func[0x15 ] = func_upword;
00956 func[0x0c ] = func_dnword;
00957 func[0x1f ] = func_undo;
00958 func[0x12 ] = func_repl;
00959 func[0x19 ] = func_replnext;
00960 func[0x13 ] = func_find;
00961 func[0x0e ] = func_findnxt;
00962 func[0x10 ] = func_findprv;
00963 func[key_f1 ] = func_help;
00964 func[key_f3 ] = func_db;
00965 func[key_f5 ] = func_mark;
00966 func[key_f6 ] = func_clreol;
00967 func[key_f7 ] = func_paste;
00968 func[key_ic ] = func_paste;
00969
00970
00971 func[key_f8 ] = func_dl;
00972 func[key_f11 ] = func_cb;
00973 func[0x07 ] = func_goto;
00974 func[0x1c ] = func_matching;
00975 func[0x03 ] = func_dw;
00976 func[key_f4 ] = func_join;
00977 func[key_f9 ] = func_insline;
00978 func[0x1a ] = func_to_edit;
00979 func[key_f12 ] = func_switch;
00980
00981 int i;
00982
00983 for(i=' '; i < 0x7f; ++i)
00984 func[i] = func_data;
00985
00986 for(i='a'; i <= 'z'; ++i)
00987 word += char(i);
00988
00989 for(i='A'; i <= 'Z'; ++i)
00990 word += char(i);
00991
00992 word += '_';
00993 word += '$';
00994
00995
00996 }
00997
00998 }
00999
01000 string CursorWindow::func_name(int fun)
01001 {
01002 switch(fun)
01003 {
01004 case func_up: return "CUR_UP_1_LN";
01005 case func_down: return "CUR_DN_1_LN";
01006 case func_left: return "CUR_LF_1_CH";
01007 case func_right: return "CUR_RT_1_CH";
01008 case func_ic: return "~INSMODE";
01009 case func_dc: return "DEL_1_CH";
01010 case func_home: return "HOME_LINE";
01011 case func_end: return "END_LINE";
01012 case func_prior: return "PREV_PAGE";
01013 case func_next: return "NEXT_PAGE";
01014 case func_dc_prev: return "DEL_PRV_CH";
01015 case func_tab: return "TAB_RIGHT";
01016 case func_btab: return "TAB_LEFT";
01017 case func_top: return "TOP";
01018 case func_bottom: return "BOTTOM";
01019 case func_esc: return "ESCAPE";
01020 case func_enter: return "ENTER";
01021 case func_data: return "DATA";
01022 case func_clreol: return "CLR_2_EOL";
01023 case func_nextwd: return "NXT_WD";
01024 case func_prevwd: return "PRV_WD";
01025 case func_upword: return "UPCASE_WD";
01026 case func_dnword: return "DNCASE_WD";
01027 case func_undo: return "UNDO";
01028 case func_find: return "FIND";
01029 case func_findnxt: return "FIND_NEXT";
01030 case func_findprv: return "FIND_PREV";
01031 case func_repl: return "REPLACE";
01032 case func_replnext:return "REPLACE_NXT";
01033 case func_help: return "HELP";
01034 case func_mark: return "MARK (block)";
01035 case func_dl: return "DEL_1_LINE";
01036 case func_dw: return "DEL_WORD";
01037 case func_db: return "DEL_BLOCK";
01038 case func_cb: return "COPY_BLOCK";
01039 case func_paste: return "PASTE (block)";
01040 case func_join: return "JOIN (lines)";
01041 case func_insline: return "INSERT_BLANK_LINE";
01042 case func_to_edit: return "CONV VIEW TO EDIT";
01043 case func_reread: return "RE_READ_FILE";
01044 };
01045
01046 return "USER_FUNC";
01047
01048 }
01049
01050
01051
01052
01053 CursorWindow::
01054 ~CursorWindow()
01055 {
01056 if(window_->open_)
01057 close();
01058
01059 delete window_;
01060
01061 window_ = 0;
01062
01063 }
01064
01065 void
01066 CursorWindow::
01067 close()
01068 {
01069 closeCursesTerminal();
01070 window_->open_ = false;
01071 }
01072
01073
01074 bool
01075 CursorWindow::
01076 open()
01077 {
01078 if(!window_->open_)
01079 {
01080 openCursesTerminal();
01081
01082 window_->open_ = true;
01083
01084 getCursesScreenSize(&window_->size_.row_,&window_->size_.col_);
01085
01086 }
01087
01088 return false;
01089 }
01090
01091 char const *
01092 CursorWindow::
01093 error() const
01094 {
01095 return window_->error_;
01096 }
01097
01098 void
01099 CursorWindow::
01100 set_error(char const *s)
01101 {
01102 window_->error_ = s;
01103 }
01104
01105
01106 void
01107 CursorWindow::
01108 needs_resized()
01109 {
01110 window_->needs_resized_ = true;
01111 resize_requested = 1;
01112 }
01113
01114
01115 void
01116 CursorWindow::
01117 refresh()
01118 {
01119 if(window_->needs_resized_)
01120 {
01121 window_->needs_resized_ = 0;
01122 resize_requested = 0;
01123
01124 if(window_->resize_handler_)
01125 (*window_->resize_handler_)(this);
01126
01127 window_->repaint_ports();
01128
01129 }
01130 refreshCursesWindow();
01131 }
01132
01133
01134
01135 CursorWindow::input_event
01136 CursorWindow::
01137 read_input()
01138 {
01139
01140 int key;
01141
01142
01143
01144
01145
01146
01147 refresh();
01148
01149
01150 for(;;)
01151 {
01152
01153 key = CursesInterface::read_mapped_key(*this);
01154
01155 if(key == CursesInterface::ResizeEvent)
01156 {
01157 winch_occurred = 0;
01158 resize_requested = 0;
01159
01160 row_col old_size = window_->size_;
01161
01162 getCursesScreenSize(&window_->size_.row_,
01163 &window_->size_.col_
01164 );
01165
01166 row_col new_size = window_->size_;
01167
01168 if(window_->resize_handler_)
01169 {
01170 (*window_->resize_handler_)(this);
01171
01172 window_->repaint_ports();
01173
01174 winch_occurred = 0;
01175 resize_requested = 0;
01176
01177 continue;
01178 }
01179
01180
01181
01182
01183
01184
01185
01186 window_->resize_viewports(old_size, new_size);
01187
01188 window_->repaint_ports();
01189
01190 winch_occurred = 0;
01191 resize_requested = 0;
01192
01193 return input_event(input_event::ResizeKey, 0);
01194
01195 }
01196 else
01197 if(key == CursesInterface::MouseEvent)
01198 {
01199 #ifdef _MSC_VER
01200 CursesInterface::mouse_info loc = CursesInterface::read_mouse_info();
01201
01202 int buttonCode = '@' + loc.state_;
01203
01204 #if 0
01205 row_col org = origin();
01206 #else
01207 row_col org(0,0);
01208 #endif
01209
01210 return input_event(input_event::MouseEvent, buttonCode, loc.row_ - org.row_, loc.col_ - org.col_);
01211 #endif
01212 }
01213 else
01214 break;
01215 }
01216
01217
01218
01219
01220
01221 std::map<int,int>::iterator key_table_loc = func.find(key);
01222
01223 if(key_table_loc == func.end() ||
01224 key_table_loc->second == CursorWindow::func_data
01225 )
01226 {
01227 return input_event(input_event::DataKey, key);
01228 }
01229
01230
01231 return input_event(input_event::FunctionKey, key );
01232
01233 }
01234
01235 row_col
01236 CursorWindow::
01237 curpos() const
01238 {
01239 row_col rc;
01240
01241 getCursesCursor(&rc.row_, &rc.col_);
01242
01243 return rc;
01244 }
01245
01246 void
01247 CursorWindow::
01248 set_curpos(row_col rc)
01249 {
01250 moveCursesCursor(rc.row_, rc.col_);
01251 }
01252
01253 row_col
01254 CursorWindow::
01255 size() const
01256 {
01257 return window_->size_;
01258 }
01259
01260 void
01261 CursorWindow::
01262 beep()
01263 {
01264 beepCursesTerminal();
01265 }
01266
01267 void
01268 CursorWindow::
01269 write(char const *s, size_t length)
01270
01273 {
01274 row_col where = curpos();
01275
01276 if(where.row_ < 0 ||
01277 where.row_ >= window_->size_.row_ ||
01278 where.col_ >= window_->size_.col_
01279 )
01280 return;
01281
01282 if(where.col_ < 0)
01283 {
01284 int t = -where.col_ ;
01285
01286 if(t >= (int)length)
01287 {
01288 return ;
01289 }
01290
01291
01292
01293 s += t;
01294
01295 length -= t;
01296
01297
01298 where.col_ = 0;
01299
01300 }
01301
01302 paintCharString(s, length, window_->current_attribute_, where.row_, where.col_);
01303
01304 }
01305
01306 void
01307 CursorWindow::
01308 write(long c, int length)
01309
01312 {
01313 row_col where = curpos();
01314
01315 if(where.row_ < 0 ||
01316 where.row_ >= window_->size_.row_ ||
01317 where.col_ >= window_->size_.col_
01318 )
01319 return;
01320
01321 if(where.col_ < 0)
01322 {
01323 int t = -where.col_ ;
01324
01325 if(t >= (int)length)
01326 {
01327 return ;
01328 }
01329
01330
01331
01332 length -= t;
01333
01334
01335 where.col_ = 0;
01336
01337 }
01338
01339 paintCharString(c, length, window_->current_attribute_, where.row_, where.col_);
01340
01341 }
01342
01343
01344 void
01345 CursorWindow::
01346 fill_to_eol(char c)
01347 {
01348 int remaining_length = size().col_ - curpos().col_;
01349
01350 write(c, remaining_length);
01351
01352 }
01353
01354 void
01355 CursorWindow::
01356 fill_to_eos(char c)
01357 {
01358 int i;
01359
01360 row_col where = curpos();
01361
01362 int rows = size().row_;
01363
01364 fill_to_eol(c);
01365
01366 for(i = where.row_+1; i < rows; ++i)
01367 {
01368 set_curpos(i, 0);
01369 fill_to_eol(c);
01370 }
01371
01372
01373 }
01374
01375 void
01376 CursorWindow::
01377 box(int width, int height, bool filled, char const *string, unsigned length)
01378 {
01379 using namespace CursesInterface;
01380
01381 row_col where = curpos();
01382 row_col dims = size();
01383
01384 int row = where.row_;
01385 int col = where.col_;
01386
01387 if(width + where.col_ >= dims.col_)
01388 {
01389
01390
01391 width = dims.col_ - where.col_;
01392
01393 if(width < 1)
01394 return;
01395
01396 }
01397
01398 int count=0;
01399
01400 long horz = line_chars[HL_MIDDLE];
01401 long fill = line_chars[HL_MIDDLE];
01402 long tl = line_chars[UL_CORNER];
01403 long bl = line_chars[LL_CORNER];
01404 long tr = line_chars[UR_CORNER];
01405 long br = line_chars[LR_CORNER];
01406 long bar = line_chars[VL_MIDDLE];
01407
01408 while(row < dims.row_ && count < height)
01409 {
01410
01411
01412 row_col here(row,col);
01413
01414 if(filled)
01415 {
01416 set_curpos( here );
01417
01418 if(count == height-1)
01419 fill = horz;
01420
01421 for(int i = col; i < col + width; ++i)
01422 write(fill, 1);
01423
01424 fill = ' ';
01425 }
01426
01427
01428 if(count == 0)
01429 {
01430 set_curpos( here );
01431 write(tl, 1);
01432 set_curpos( row_col(row, col + width-1));
01433 write(tr, 1);
01434 }
01435 else
01436 if(count == height-1)
01437 {
01438 set_curpos( here );
01439 write(bl, 1);
01440 set_curpos( row_col(row, col + width-1));
01441 write(br, 1);
01442 }
01443 else
01444 {
01445 set_curpos( here );
01446 write(bar, 1);
01447 set_curpos( row_col(row, col + width-1));
01448 write(bar, 1);
01449 }
01450
01451 ++row;
01452 ++count;
01453 }
01454
01455
01456 if(string)
01457 {
01458 set_curpos( row_col( where.row_, where.col_ + 2 ) );
01459
01460 write(string, length);
01461
01462 }
01463
01464
01465 }
01466
01467 int
01468 CursorWindow::
01469 text_attribute() const
01470 {
01471 return window_->current_attribute_;
01472 }
01473
01474 void
01475 CursorWindow::
01476 set_text_attribute(int a)
01477 {
01478 window_->current_attribute_ = a;
01479 }
01480
01481
01482 string
01483 CursorWindow::
01484 key_name(int curses_key)
01485 {
01486 switch(curses_key)
01487 {
01488 case CursorWindow::key_up: return "key_up";
01489 case CursorWindow::key_down: return "key_down";
01490 case CursorWindow::key_left: return "key_left";
01491 case CursorWindow::key_right: return "key_right";
01492 case CursorWindow::key_sleft: return "key_sleft";
01493 case CursorWindow::key_sright: return "key_sright";
01494 case CursorWindow::key_prior: return "key_prior";
01495 case CursorWindow::key_next: return "key_next";
01496 case CursorWindow::key_ic: return "key_ic";
01497 case CursorWindow::key_dc: return "key_dc";
01498 case CursorWindow::key_bs: return "key_bs";
01499 case CursorWindow::key_home: return "key_home";
01500 case CursorWindow::key_end: return "key_end";
01501 case CursorWindow::key_btab: return "key_btab";
01502
01503 case CursorWindow::key_f1: return "key_f1";
01504 case CursorWindow::key_f2: return "key_f2";
01505 case CursorWindow::key_f3: return "key_f3";
01506 case CursorWindow::key_f4: return "key_f4";
01507 case CursorWindow::key_f5: return "key_f5";
01508 case CursorWindow::key_f6: return "key_f6";
01509 case CursorWindow::key_f7: return "key_f7";
01510 case CursorWindow::key_f8: return "key_f8";
01511 case CursorWindow::key_f9: return "key_f9";
01512 case CursorWindow::key_f10: return "key_f10";
01513 case CursorWindow::key_f11: return "key_f11";
01514 case CursorWindow::key_f12: return "key_f12";
01515 case 0x1b: return "key_esc";
01516 case 0x1c: return "^\\";
01517 case 0x1f: return "^/ or ^_";
01518 }
01519
01520 char buffer[40];
01521
01522 if(curses_key >= ' ' && curses_key <= 0x7e)
01523 sprintf(buffer, "'%c'", curses_key);
01524 else
01525 sprintf(buffer, "^%c", '@' + curses_key);
01526
01527
01528 return buffer;
01529
01530 }
01531
01532 void
01533 CursorWindow::set_resize_handler( CursorWindow::resize_handler *h )
01534 {
01535 window_->resize_handler_ = h;
01536 }
01537
01538 void
01539 viewport::
01540 beep()
01541 {
01542 window()->beep();
01543 }
01544
01545
01546 viewport::
01547 viewport(CursorWindow* w, repaint_handler* r, viewport::position p)
01548 {
01549 port_ = w->window_->new_port(w,r,p);
01550 owned_ = true;
01551 }
01552
01553 viewport::
01554 viewport(port* p)
01555 {
01556 port_ = p;
01557 owned_ = false;
01558 }
01559
01560
01561 viewport::
01562 ~viewport()
01563 {
01564 if(owned_)
01565 port_->window_->window_->delete_port(port_);
01566
01567 port_ = 0;
01568 }
01569
01570
01571 void
01572 viewport::
01573 write(char const *s, size_t length)
01574
01577 {
01578 row_col where = curpos();
01579 row_col vsize = size();
01580
01581 if(where.row_ < 0 ||
01582 where.row_ >= port_->size().row_ ||
01583 where.col_ >= port_->size().col_
01584 )
01585 return;
01586
01587 if(where.col_ < 0)
01588 {
01589 int t = -where.col_ ;
01590
01591 if(t >= (int)length)
01592 {
01593 return ;
01594 }
01595
01596
01597
01598 s += t;
01599
01600 length -= t;
01601
01602
01603 where.col_ = 0;
01604
01605 }
01606
01607 port_->window_->set_text_attribute(port_->current_attribute_);
01608
01609
01610 port_->window_->set_curpos(where.row_ + port_->origin().row_,
01611 where.col_ + port_->origin().col_);
01612
01613
01614 if(where.col_ + length > size_t(vsize.col_) )
01615 {
01616 length = vsize.col_ - where.col_;
01617 }
01618
01619 port_->window_->write(s, length);
01620
01621 port_->curpos_.col_ += length;
01622
01623 }
01624
01625 void
01626 viewport::
01627 write(long c, int length)
01628
01631 {
01632 row_col where = curpos();
01633
01634 if(where.row_ < 0 ||
01635 where.row_ >= port_->size().row_ ||
01636 where.col_ >= port_->size().col_
01637 )
01638 return;
01639
01640 if(where.col_ < 0)
01641 {
01642 int t = -where.col_ ;
01643
01644 if(t >= (int)length)
01645 {
01646 return ;
01647 }
01648
01649
01650
01651 length -= t;
01652
01653
01654 where.col_ = 0;
01655
01656 }
01657
01658 port_->window_->set_text_attribute(port_->current_attribute_);
01659
01660 port_->window_->set_curpos(where.row_ + port_->origin().row_,
01661 where.col_ + port_->origin().col_);
01662
01663 port_->window_->write(c, length);
01664
01665 port_->curpos_.col_ += length;
01666
01667 }
01668
01669
01670 void
01671 viewport::
01672 fill_to_eol(char c)
01673 {
01674 int remaining_length = size().col_ - curpos().col_;
01675
01676 write(c, remaining_length);
01677
01678 }
01679
01680 void
01681 viewport::
01682 fill_to_eos(char c)
01683 {
01684 int i;
01685
01686 fill_to_eol(c);
01687
01688 for(i=curpos().row_ + 1; i < size().row_; ++i)
01689 {
01690 set_curpos(i, 0);
01691 fill_to_eol(c);
01692 }
01693
01694
01695 }
01696
01697 void
01698 viewport::
01699 box(int width, int height, bool filled, char const *string, unsigned length)
01700 {
01701 row_col where = curpos();
01702 row_col dims = size();
01703
01704 int row = where.row_;
01705 int col = where.col_;
01706
01707 if(width + where.col_ >= dims.col_)
01708 {
01709
01710
01711 width = dims.col_ - where.col_;
01712
01713 if(width < 1)
01714 return;
01715
01716 }
01717
01718 int count=0;
01719
01720
01721 long horz = line_chars[HL_MIDDLE];
01722 long fill = line_chars[HL_MIDDLE];
01723 long tl = line_chars[UL_CORNER];
01724 long bl = line_chars[LL_CORNER];
01725 long tr = line_chars[UR_CORNER];
01726 long br = line_chars[LR_CORNER];
01727 long bar = line_chars[VL_MIDDLE];
01728
01729 while(row < dims.row_ && count < height)
01730 {
01731
01732
01733 row_col here(row,col);
01734
01735 if(filled)
01736 {
01737 set_curpos( here );
01738
01739 if(count == height-1)
01740 fill = horz;
01741
01742 for(int i = col; i < col + width; ++i)
01743 write(fill, 1);
01744
01745 fill = ' ';
01746 }
01747
01748
01749 if(count == 0)
01750 {
01751 set_curpos( here );
01752 write(tl, 1);
01753 set_curpos( row_col(row, col + width-1));
01754 write(tr, 1);
01755 }
01756 else
01757 if(count == height-1)
01758 {
01759 set_curpos( here );
01760 write(bl, 1);
01761 set_curpos( row_col(row, col + width-1));
01762 write(br, 1);
01763 }
01764 else
01765 {
01766 set_curpos( here );
01767 write(bar, 1);
01768 set_curpos( row_col(row, col + width-1));
01769 write(bar, 1);
01770 }
01771
01772 ++row;
01773 ++count;
01774 }
01775
01776
01777 if(string)
01778 {
01779 set_curpos( row_col( where.row_, where.col_ + 2 ) );
01780
01781 write(string, length);
01782
01783 }
01784
01785
01786 }
01787
01788
01789 row_col
01790 viewport::
01791 curpos() const
01792 {
01793 return port_->curpos_;
01794 }
01795
01796 void
01797 viewport::
01798 set_curpos(row_col rc)
01799 {
01800 port_->curpos_ = rc;
01801
01802 rc.row_ += port_->origin().row_;
01803 rc.col_ += port_->origin().col_;
01804
01805
01806 port_->window_->set_curpos(rc);
01807 }
01808
01809 void
01810 viewport::
01811 restore_curpos()
01812 {
01813 set_curpos(port_->curpos_);
01814 }
01815
01816
01817 int
01818 viewport::
01819 text_attribute() const
01820 {
01821 return port_->current_attribute_;
01822 }
01823
01824 void
01825 viewport::
01826 set_text_attribute(int a)
01827 {
01828 port_->current_attribute_ = a;
01829 }
01830
01831 std::auto_ptr<viewport>
01832 CursorWindow::new_viewport(repaint_handler* h, viewport::position p)
01833 {
01834 return std::auto_ptr<viewport>(new viewport(this,h,p));
01835 }
01836
01837
01838 row_col
01839 viewport::
01840 size() const
01841 {
01842 row_col rv;
01843
01844 rv.row_ = port_->scaled_size_.row_ / WScale;
01845 rv.col_ = port_->scaled_size_.col_ / WScale;
01846
01847 return rv;
01848 }
01849
01850 row_col
01851 viewport::
01852 origin() const
01853 {
01854 row_col rv;
01855
01856 rv.row_ = port_->scaled_origin_.row_ / WScale;
01857 rv.col_ = port_->scaled_origin_.col_ / WScale;
01858
01859 return rv;
01860
01861 }
01862
01863
01864 void
01865 viewport::
01866 move( row_col origin,
01867 row_col size
01868 )
01869 {
01870 row_col port_origin;
01871
01872 port_origin.row_ = port_->scaled_origin_.row_ / WScale;
01873 port_origin.col_ = port_->scaled_origin_.col_ / WScale;
01874
01875 row_col port_size;
01876
01877 port_size.row_ = port_->scaled_size_.row_ / WScale;
01878 port_size.col_ = port_->scaled_size_.col_ / WScale;
01879
01880 if(origin == port_origin && size == port_size)
01881 return;
01882
01883
01884 port_->scaled_origin_.row_ = origin.row_ * WScale + WHalfCell;
01885 port_->scaled_origin_.col_ = origin.col_ * WScale + WHalfCell;
01886
01887 port_->scaled_size_.row_ = size.row_ * WScale + WHalfCell;
01888 port_->scaled_size_.col_ = size.col_ * WScale + WHalfCell;
01889
01890 port_->window_->needs_resized();
01891
01892 }
01893
01894 void
01895 viewport::
01896 activate()
01897 {
01898 port_->window_->window_->activate(this);
01899 }
01900
01901 void
01902 viewport::
01903 refresh()
01904 {
01905 port_->window_->refresh();
01906 }
01907
01908 CursorWindow*
01909 viewport::
01910 window()
01911 {
01912 return port_->window_;
01913 }
01914
01915
01916
01917 CursorWindow::resize_handler::
01918 ~resize_handler()
01919 {
01920 }
01921
01922 #undef repaint_handler
01923
01924 viewport::repaint_handler::
01925 ~repaint_handler()
01926 {
01927 }
01928
01929 void
01930 CursorWindow::Dialog::Ok::
01931 handle_key(viewport *v, int key)
01932 {
01933 v->beep();
01934 }
01935
01936
01937 class CursorWindow::Dialog::Impl
01938
01941 {
01942 public:
01943
01944 typedef CursorWindow::Dialog::element_list_t element_list_t;
01945 typedef element_list_t::iterator iterator;
01946
01947 string title_;
01949
01950 element_list_t elements_;
01952
01953 std::string curdir_;
01956
01957 std::string first_input_field_;
01960
01961 iterator find_element(string const &name);
01963
01964
01965 struct visible_page
01966
01969 {
01970 iterator page_top_;
01971 iterator page_bottom_;
01972 iterator current_line_;
01973 int height_;
01974 iterator last_line_;
01975
01976 int page_offset(iterator line)
01977
01978
01979
01980
01981 {
01982 iterator scan = page_top_;
01983
01984 int rv = 0;
01985
01986 while(scan != line && scan != last_line_)
01987 {
01988 ++rv;
01989 ++scan;
01990 }
01991
01992
01993 return rv;
01994 }
01995
01996 int page_offset()
01997 {
01998 return page_offset(current_line_);
01999 }
02000
02001
02002 };
02003
02004 visible_page page_;
02005
02006 int desired_width_;
02007 int desired_height_;
02008 int actual_width_;
02009 int actual_height_;
02010 int gutter_width_;
02011 int first_input_row_;
02012 int title_row_;
02013 int title_col_;
02014 int label_indent_;
02015
02016 int desired_label_width_;
02017 int desired_input_width_;
02018 int desired_input_column_;
02019 int actual_input_column_;
02020
02021 void draw_current_input_area(viewport *v, bool highlighted)
02022 {
02023
02024 int row = page_.page_offset();
02025
02026 v->set_curpos(row + first_input_row_,
02027 actual_input_column_
02028 );
02029
02030 CursorWindow::Dialog::Element* e = *page_.current_line_;
02031
02032 e->draw_input_area(v, highlighted);
02033
02034 }
02035
02036 void recompute_page_info(viewport* v)
02037 {
02038 row_col available = v->window()->size();
02039
02040 actual_input_column_ = desired_input_column_;
02041
02042 int trim = desired_width_ - available.col_;
02043
02044 if(trim >= 1)
02045 {
02046
02047
02048 actual_input_column_ -= trim;
02049
02050 actual_width_ = available.col_;
02051
02052 }
02053 else
02054 actual_width_ = desired_width_;
02055
02056 if(desired_height_ > available.row_)
02057 actual_height_ = available.row_;
02058 else
02059 actual_height_ = desired_height_;
02060
02061 int input_row;
02062
02063 int max_input_rows = actual_height_ - first_input_row_;
02064
02065 for(input_row = 0, page_.page_bottom_ = page_.page_top_;
02066 input_row < max_input_rows && page_.page_bottom_ != page_.last_line_;
02067 ++input_row, ++page_.page_bottom_
02068 );
02069
02070
02071 page_.height_ = input_row;
02072
02073
02074 row_col upper_left( (available.row_ - actual_height_)/2,
02075 (available.col_ - actual_width_)/2
02076 );
02077
02078
02079 v->move(upper_left, row_col(actual_height_,actual_width_));
02080
02081 }
02082
02083
02084 };
02085
02086
02087 void
02088 CursorWindow::Dialog::
02089 set_first_input_field(std::string const &field_name)
02090 {
02091 impl_->first_input_field_ = field_name;
02092 }
02093
02094
02095 void dumpimpl(CursorWindow::Dialog::Impl *impl_)
02096 {
02097
02098
02099
02100
02101
02102 string beg="\r";
02103
02104 string label = (*impl_->page_.page_bottom_)->label_;
02105
02106
02107 std::cout << "desired width = " << impl_->desired_width_ << beg << std::endl;
02108 std::cout << "desired height = " << impl_->desired_height_ << beg << std::endl;
02109 std::cout << "actual_width = " << impl_->actual_width_ << beg << std::endl;
02110 std::cout << "actual_height = " << impl_->actual_height_ << beg << std::endl;
02111 std::cout << "gutterwidth = " << impl_->gutter_width_ << beg << std::endl;
02112 std::cout << "first_input_row = " << impl_->first_input_row_ << beg << std::endl;
02113 std::cout << "title row = " << impl_->title_row_ << beg << std::endl;
02114 std::cout << "title col = " << impl_->title_col_ << beg << std::endl;
02115 std::cout << "label indent = " << impl_->label_indent_ << beg << std::endl;
02116 std::cout << "desired label width = " << impl_->desired_label_width_ << beg << std::endl;
02117 std::cout << "desired input widht = " << impl_->desired_input_width_ << beg << std::endl;
02118 std::cout << "desired input col = " << impl_->desired_input_column_ << beg << std::endl;
02119 std::cout << "actual input col = " << impl_->actual_input_column_ << beg << std::endl;
02120 std::cout << "page_bottom_ = " << label << beg << std::endl;
02121 std::cout << std::flush;
02122 }
02123
02124 CursorWindow::Dialog::
02125 Dialog(string title)
02126 {
02127 impl_ = new CursorWindow::Dialog::Impl;
02128 impl_->title_ = title;
02129
02130 impl_->gutter_width_ = 2;
02131 impl_->first_input_row_ = 1;
02132 impl_->title_row_ = 0;
02133 impl_->title_col_ = 0;
02134 impl_->label_indent_ = 2;
02135
02136
02137
02138 impl_->desired_width_ = 0;
02139 impl_->desired_height_ = 0;
02140 impl_->actual_width_ = 0;
02141 impl_->actual_height_ = 0;
02142 impl_->desired_input_column_ = 0;
02143 impl_->actual_input_column_ = 0;
02144 impl_->desired_label_width_ = 0;
02145 impl_->desired_input_width_ = 0;
02146
02147 impl_->page_.page_top_ = end();
02148 impl_->page_.page_bottom_ = end();
02149 impl_->page_.current_line_ = end();
02150 impl_->page_.height_ = 0;
02151 impl_->page_.last_line_ = end();
02152
02153
02154 }
02155
02156 CursorWindow::Dialog::
02157 ~Dialog()
02158 {
02159 for(iterator f = begin(), l = end(); f != l; ++f)
02160 {
02161 delete *f;
02162 }
02163
02164 delete impl_;
02165
02166 impl_ = 0;
02167 }
02168
02169 CursorWindow::Dialog&
02170 CursorWindow::Dialog::
02171 operator+= (CursorWindow::Dialog::Element *e)
02172
02174
02175 {
02176 e->dialog_ = this;
02177
02178 impl_->elements_.push_back(e);
02179
02180 return *this;
02181
02182 }
02183
02184 std::string const &
02185 CursorWindow::Dialog::
02186 completion_directory() const
02187 {
02188 return impl_->curdir_;
02189 }
02190
02191 void
02192 CursorWindow::Dialog::
02193 set_completion_directory(std::string const &s)
02194 {
02195 impl_->curdir_ = s;
02196 }
02197
02198
02199
02200 CursorWindow::Dialog::iterator
02201 CursorWindow::Dialog::
02202 begin()
02203 {
02204 return impl_->elements_.begin();
02205 }
02206
02207
02208 CursorWindow::Dialog::iterator
02209 CursorWindow::Dialog::
02210 end()
02211 {
02212 return impl_->elements_.end();
02213 }
02214
02215 void
02216 CursorWindow::Dialog::Ok::
02217 draw_input_area(viewport *v, bool highlighted)
02218 {
02219 v->set_text_attribute( highlighted ? CursorWindow::normal
02220 : CursorWindow::reversed
02221 );
02222
02223 row_col pos = v->curpos();
02224
02225 v->write("[OK]");
02226
02227 v->set_curpos(pos.row_, pos.col_ + 1);
02228
02229 }
02230
02231
02232
02233
02234 bool
02235 CursorWindow::Dialog::String::
02236 compute_actual_width(viewport *v)
02237 {
02238 bool rv = false;
02239
02240 width_ = input_width_;
02241
02242 row_col size = v->size();
02243
02244 if(input_ + width_ > size.col_)
02245 {
02246 width_ = size.col_ - input_;
02247
02248 }
02249
02250 if(col_ < 0)
02251 col_ = 0;
02252
02253 int maxlen = value_.size();
02254
02255 if(col_ > maxlen )
02256 col_ = maxlen;
02257
02258 if(col_ - offset_ >= width_ ||
02259 col_ < offset_
02260 )
02261 {
02262 offset_ = col_ - width_/2;
02263
02264 if(offset_ < 0)
02265 offset_ = 0;
02266
02267 rv = true;
02268 }
02269
02270
02271 if(offset_ > maxlen )
02272 {
02273 offset_ = maxlen;
02274
02275 rv = true;
02276 }
02277
02278 if(col_ > maxlen)
02279 col_ = maxlen;
02280
02281
02282 return rv;
02283
02284 }
02285
02286 void
02287 CursorWindow::Dialog::String::
02288 handle_paging(viewport *v)
02289 {
02290 row_col pos = v->curpos();
02291
02292 if(compute_actual_width(v))
02293 {
02294 v->set_curpos(pos.row_, input_);
02295
02296 draw_input_area(v,true);
02297
02298 }
02299
02300 v->set_curpos(pos.row_, input_ + col_ - offset_);
02301
02302
02303 }
02304
02305
02306 void
02307 CursorWindow::Dialog::String::
02308 draw_input_area(viewport *v, bool highlighted)
02309 {
02310
02311
02312
02313
02314 row_col pos = v->curpos();
02315
02316 input_ = pos.col_;
02317
02318 compute_actual_width(v);
02319
02320 int drawlen = value_.size();
02321
02322 drawlen -= offset_;
02323
02324 if(drawlen > width_)
02325 drawlen = width_;
02326
02327 v->set_text_attribute( highlighted ? CursorWindow::normal
02328 : CursorWindow::reversed
02329 );
02330
02331 if(password_)
02332 {
02333 v->write('*', drawlen);
02334 }
02335 else
02336 {
02337 v->write( string(value_.begin() + offset_,
02338 value_.begin() + offset_ + drawlen
02339 )
02340 );
02341 }
02342
02343 if(drawlen < width_)
02344 v->write(' ', width_ - drawlen);
02345
02346 v->set_curpos(pos.row_, pos.col_ + col_ - offset_);
02347
02348 }
02349
02350 void CursorWindow::Dialog::String::
02351 setColumn(int col)
02352 {
02353 col_ = (size_t(col) <= value_.size() ) ? col : 0;
02354 };
02355
02356
02357 void
02358 CursorWindow::Dialog::String::
02359 handle_key(viewport *v, int key)
02360 {
02361
02362
02363
02364 compute_actual_width(v);
02365
02366 switch(CursorWindow::func[key])
02367 {
02368 case CursorWindow::func_home:
02369 {
02370 col_ = 0;
02371
02372 handle_paging(v);
02373
02374 }
02375 break;
02376
02377 case CursorWindow::func_end:
02378 {
02379 col_ = value_.size();
02380
02381 handle_paging(v);
02382
02383 }
02384 break;
02385
02386 case CursorWindow::func_right:
02387 {
02388 ++col_;
02389
02390 handle_paging(v);
02391
02392 }
02393 break;
02394
02395
02396 case CursorWindow::func_left:
02397 {
02398 --col_;
02399
02400 handle_paging(v);
02401
02402 }
02403 break;
02404
02405 case CursorWindow::func_dc_prev:
02406
02407 if(col_ == 0)
02408 {
02409 v->beep();
02410 return;
02411 }
02412
02413 --col_;
02414 compute_actual_width(v);
02415 {
02416 row_col pos = v->curpos();
02417
02418 v->set_curpos(pos.row_, input_ + col_ - offset_);
02419
02420 }
02421
02422
02423
02424 case CursorWindow::func_dc:
02425 {
02426 int maxlen = value_.size();
02427
02428 if(col_ < maxlen)
02429 {
02430 value_.erase( value_.begin() + col_ );
02431
02432 int tail_length = maxlen - col_ - 1;
02433
02434 string tail_text(value_.begin() + col_,
02435 value_.begin() + col_ + tail_length
02436 );
02437
02438 tail_text += " ";
02439
02440 if(password_)
02441 {
02442 v->write('*', tail_text.size()-1 );
02443 v->write(' ');
02444
02445 }
02446 else
02447 v->write( tail_text );
02448
02449 handle_paging(v);
02450
02451 }
02452 else
02453 v->beep();
02454 }
02455 break;
02456
02457 case CursorWindow::func_clreol:
02458 {
02459 int maxlen = value_.size();
02460
02461 if(col_ < maxlen)
02462 {
02463 value_.erase( value_.begin() + col_, value_.end() );
02464
02465 int tail_length = maxlen - col_;
02466
02467 string tail_text(tail_length, ' ');
02468
02469 if(password_)
02470 {
02471 v->write(' ', tail_text.size());
02472
02473 }
02474 else
02475 v->write( tail_text );
02476
02477 handle_paging(v);
02478
02479 }
02480 else
02481 v->beep();
02482 }
02483 break;
02484
02485 case CursorWindow::func_tab:
02486 {
02487
02488
02489 size_t col = col_;
02490
02491 if(col > value_.size())
02492 col = value_.size();
02493
02494
02495
02496
02497 if(value_[0] == '~')
02498 {
02499
02500 FileName tmp(value_);
02501
02502 value_ = tmp.expand_tildes();
02503
02504
02505
02506 row_col pos = v->curpos();
02507
02508 v->set_curpos(pos.row_, input_);
02509
02510 v->write(' ', width_);
02511
02512
02513
02514 col_ = value_.size();
02515
02516 compute_actual_width(v);
02517
02518 v->set_curpos(pos.row_, input_);
02519
02520 draw_input_area(v,true);
02521
02522 v->set_curpos(pos.row_, input_ + col_ - offset_);
02523
02524 }
02525
02526
02527
02528 if(col != 0 &&
02529 col == value_.size()
02530 )
02531 {
02532
02533
02534
02535 if(value_[col-1] == ' ')
02536 {
02537 v->beep();
02538 break;
02539 }
02540
02541 int word_start = col;
02542
02543 while(word_start && value_[word_start-1] != ' ')
02544 --word_start;
02545
02546
02547
02548
02549 std::string last_word(value_.begin() + word_start,
02550 value_.end()
02551 );
02552
02553 FileName path(last_word);
02554
02555 if(last_word[0] != '/' &&
02556 !(last_word[1] == ':' && (last_word[2] == '\\' ||
02557 last_word[2] == '/'
02558 )
02559 )
02560 )
02561 {
02562
02563
02564
02565
02566 path = dialog_->completion_directory() + last_word;
02567 }
02568
02569 if(path.is_dir())
02570 {
02571
02572
02573 if(value_[value_.size()-1] == '/')
02574 {
02575 v->beep();
02576 break;
02577 }
02578
02579 value_ += '/';
02580 v->write('/');
02581
02582 col_ = value_.size();
02583 handle_paging(v);
02584
02585 }
02586 else
02587 {
02588 FileName::sorted_names_t matching;
02589 std::string replacement;
02590
02591 int matches = FileName::find_matching(path + "*", &matching);
02592
02593 if(matches == 0)
02594 {
02595 v->beep();
02596 break;
02597 }
02598
02599 if(matches == 1)
02600 replacement = *matching.begin();
02601 else
02602 {
02603 CursorWindow::Selection selection("pick one of the following");
02604
02605 FileName::sorted_names_t::iterator first = matching.begin(),
02606 last = matching.end();
02607
02608 while(first != last)
02609 {
02610 FileName const& cur = *first++;
02611
02612 selection += cur;
02613
02614 }
02615
02616 if(selection.popup(v->window()))
02617 break;
02618
02619 replacement = selection.selection_;
02620
02621 }
02622
02623
02624
02625 value_.erase(value_.begin() + word_start, value_.end());
02626
02627
02628
02629 row_col pos = v->curpos();
02630
02631 v->set_curpos(pos.row_, input_);
02632
02633 v->write(' ', width_);
02634
02635
02636
02637
02638
02639 value_ = path.dirname() + replacement;
02640
02641 col_ = value_.size();
02642
02643 compute_actual_width(v);
02644
02645 v->set_curpos(pos.row_, input_);
02646
02647 draw_input_area(v,true);
02648
02649 v->set_curpos(pos.row_, input_ + col_ - offset_);
02650
02651
02652 }
02653
02654
02655 }
02656 else
02657 v->beep();
02658
02659 }
02660 break;
02661
02662
02663 case CursorWindow::func_nextwd:
02664 {
02665 string::iterator start = value_.begin() + col_;
02666 string::iterator end = value_.end();
02667
02668 string::iterator word_start = word.begin();
02669 string::iterator word_end = word.end();
02670
02671 start = StrTool::find_next_word(start, end, word_start, word_end);
02672
02673 col_ = start - value_.begin();
02674
02675 handle_paging(v);
02676
02677
02678 }
02679 break;
02680
02681 case CursorWindow::func_prevwd:
02682 {
02683 string::iterator start = value_.begin() + col_;
02684 string::iterator beg = value_.begin();
02685
02686 string::iterator word_start = word.begin();
02687 string::iterator word_end = word.end();
02688
02689 start = StrTool::find_prev_word(start,
02690 beg, value_.end(),
02691 word_start, word_end
02692 );
02693
02694 col_ = start - beg;
02695
02696 handle_paging(v);
02697
02698
02699 }
02700 break;
02701
02702
02703
02704 case CursorWindow::func_data:
02705
02706 if(key < 0x100 && key > 0)
02707 {
02708 value_.insert( value_.begin() + col_, (char)(key) );
02709
02710 int maxlen = value_.size();
02711
02712 int tail_length = maxlen - col_;
02713
02714 int char_cells_in_window = width_ - (col_ - offset_);
02715
02716 if(tail_length > char_cells_in_window)
02717 tail_length = char_cells_in_window;
02718
02719 string tail_text(value_.begin() + col_,
02720 value_.begin() + (col_ + tail_length)
02721 );
02722
02723 if(password_)
02724 {
02725 v->write('*', tail_text.size());
02726 }
02727 else
02728 v->write( tail_text );
02729
02730 ++col_;
02731
02732 handle_paging(v);
02733
02734 }
02735 break;
02736
02737
02738 }
02739 }
02740
02741 struct SaveRestoreActiveWindow
02753 {
02754
02755 port* active_viewport;
02756
02757 SaveRestoreActiveWindow(CursorWindow *w)
02758 {
02759 active_viewport = w->window_->viewport_[w->window_->active_viewport_];
02760 }
02761
02762 ~SaveRestoreActiveWindow()
02763 {
02764 if(active_viewport)
02765 {
02766 CursorWindow::viewport vp(active_viewport);
02767
02768 vp.activate();
02769 }
02770 }
02771
02772
02773
02774
02775 };
02776
02777
02778 bool
02779 CursorWindow::Dialog::
02780 popup(CursorWindow *w)
02781 {
02782 SaveRestoreActiveWindow _sr(w);
02783
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800 impl_->desired_height_ = impl_->first_input_row_;
02801
02802 impl_->desired_label_width_ = 0;
02803 impl_->desired_input_width_ = 0;
02804
02805 iterator f = begin(),
02806 l = end();
02807
02808 while(f != l)
02809 {
02810 Element *e = *f;
02811
02812 int wl = e->label_.size();
02813 int wi = e->input_width_;
02814
02815 if(wl > impl_->desired_label_width_)
02816 impl_->desired_label_width_ = wl;
02817
02818 if(wi > impl_->desired_input_width_)
02819 impl_->desired_input_width_ = wi;
02820
02821 ++impl_->desired_height_;
02822 ++f;
02823
02824 }
02825
02826 impl_->desired_input_column_ = impl_->label_indent_ +
02827 impl_->desired_label_width_ +
02828 impl_->gutter_width_;
02829
02830
02831 impl_->desired_width_ = impl_->desired_input_column_ +
02832 impl_->desired_input_width_;
02833
02834 int title_width = impl_->title_.size() + impl_->title_col_;
02835
02836 if(title_width > impl_->desired_width_)
02837 impl_->desired_width_ = title_width;
02838
02839 std::auto_ptr<viewport> v(w->new_viewport(this,viewport::floating).release());
02840
02841
02842
02843 impl_->page_.page_top_ = begin();
02844 impl_->page_.current_line_= begin();
02845
02846 CursorWindow::Dialog::Impl::iterator tmp =
02847 impl_->find_element(impl_->first_input_field_);
02848
02849 if(tmp != end())
02850 impl_->page_.current_line_ = tmp;
02851
02852 impl_->first_input_field_ = "";
02853
02854 impl_->page_.last_line_ = end();
02855
02856 v->activate();
02857
02858
02859
02860
02861
02862 bool pushed_key = false;
02863 CursorWindow::input_event e;
02864
02865 for(;;)
02866 {
02867 if(pushed_key)
02868 pushed_key = false;
02869 else
02870 e = w->read_input();
02871
02872
02873
02874
02875
02876 if(e.type_ == CursorWindow::input_event::FunctionKey)
02877 {
02878 int func_key = CursorWindow::func[e.value_];
02879
02880 switch(func_key)
02881 {
02882 case CursorWindow::func_up:
02883
02884 if(impl_->page_.current_line_ != begin())
02885 {
02886
02887
02888 bool at_top_of_page = impl_->page_.current_line_ ==
02889 impl_->page_.page_top_;
02890
02891 impl_->draw_current_input_area(v.get(), false);
02892
02893 --impl_->page_.current_line_;
02894
02895 if(at_top_of_page)
02896 {
02897 impl_->page_.page_top_ = impl_->page_.current_line_;
02898 (*this)(v.get(),0);
02899 }
02900
02901 impl_->draw_current_input_area(v.get(), true);
02902
02903 }
02904 else
02905 v->beep();
02906
02907 break;
02908
02909 case CursorWindow::func_down:
02910 {
02911 CursorWindow::Dialog::iterator next_line =
02912 impl_->page_.current_line_;
02913
02914 ++next_line;
02915
02916 if(next_line != impl_->page_.last_line_)
02917 {
02918
02919
02920 impl_->draw_current_input_area(v.get(), false);
02921
02922 ++impl_->page_.current_line_;
02923
02924 if(next_line == impl_->page_.page_bottom_)
02925 {
02926
02927
02928 ++impl_->page_.page_top_;
02929
02930 if(impl_->page_.page_bottom_ != impl_->page_.last_line_)
02931 {
02932 ++impl_->page_.page_bottom_;
02933 }
02934
02935 (*this)(v.get(),0);
02936 }
02937
02938
02939 impl_->draw_current_input_area(v.get(), true);
02940 }
02941 else
02942 {
02943 return false;
02944 }
02945 break;
02946
02947 }
02948
02949 case CursorWindow::func_enter:
02950
02951 pushed_key = true;
02952 e.type_ = CursorWindow::input_event::FunctionKey;
02953 e.value_ = CursorWindow::key_down;
02954
02955 break;
02956
02957 case CursorWindow::func_esc:
02958
02959 return true;
02960
02961 default:
02962 (*impl_->page_.current_line_)->handle_key(v.get(),e.value_);
02963 break;
02964 }
02965 }
02966 else
02967 if(e.type_ == CursorWindow::input_event::DataKey)
02968 {
02969 switch(e.value_)
02970 {
02971
02972 default:
02973 (*impl_->page_.current_line_)->handle_key(v.get(),e.value_);
02974 break;
02975 }
02976 }
02977
02978 }
02979
02980 return false;
02981
02982 }
02983
02984 void
02985 CursorWindow::Dialog::
02986 operator() (viewport* v, int cmd)
02987
02988
02989 {
02990
02991
02992
02993
02994
02995
02996 impl_->recompute_page_info(v);
02997
02998 v->set_text_attribute(CursorWindow::dialog_normal_att);
02999 v->set_curpos(0,0);
03000 v->fill_to_eos();
03001
03002
03003 v->set_text_attribute(CursorWindow::dialog_title_att);
03004 v->set_curpos(impl_->title_row_, impl_->title_col_);
03005 v->write(impl_->title_);
03006
03007 int i;
03008 iterator scan;
03009 int available_label_width = impl_->actual_input_column_ -
03010 impl_->label_indent_;
03011
03012 if(available_label_width < 0)
03013 available_label_width = 0;
03014
03015 v->set_text_attribute(CursorWindow::reversed);
03016
03017
03018 for(i=0, scan=impl_->page_.page_top_;
03019 i < impl_->page_.height_;
03020 ++i, ++scan
03021 )
03022 {
03023 Element *e = *scan;
03024
03025 string label = e->label_;
03026
03027 int label_width = label.size();
03028
03029 if(label_width > available_label_width)
03030 {
03031 string temp(label.begin(), label.begin() + available_label_width);
03032
03033 label = temp;
03034 }
03035
03036 v->set_curpos(impl_->first_input_row_ + i,
03037 impl_->actual_input_column_ - impl_->gutter_width_ -
03038 label.size()
03039 );
03040
03041 v->set_text_attribute(CursorWindow::dialog_normal_att);
03042
03043 v->write(label);
03044
03045 v->write(": ");
03046
03047 e->draw_input_area(v, scan == impl_->page_.current_line_);
03048
03049 }
03050
03051 impl_->draw_current_input_area(v, true);
03052
03053 }
03054
03055 class CursorWindow::Selection::Impl
03056
03060
03061 {
03062 public:
03063
03064 typedef CursorWindow::Selection::rep_type rep_type;
03065 typedef rep_type::iterator iterator;
03066
03067 string title_;
03068
03069 int desired_width_;
03070 int desired_height_;
03071 int actual_width_;
03072 int actual_height_;
03073
03074 iterator page_top_;
03075 iterator page_bottom_;
03076
03077 iterator current_line_;
03078
03079 iterator begin_;
03080 iterator end_;
03081
03082 int title_col_;
03083 int title_row_;
03084 int input_row_;
03085 int input_col_;
03086
03087 size_t auto_complete_column_;
03088
03089
03090
03091
03092
03093
03094
03095
03096 void compute_page_info(viewport *v)
03097
03098
03099
03100
03101
03102
03103
03104
03105 {
03106 row_col size = v->window()->size();
03107
03108
03109
03110
03111 size.row_ -= 2;
03112 size.col_ -= 2;
03113
03114
03115
03116
03117
03118
03119 if(desired_height_ >= size.row_ )
03120 actual_height_ = size.row_;
03121 else
03122 actual_height_ = desired_height_;
03123
03124
03125 if(desired_width_ > size.col_)
03126 actual_width_ = size.col_;
03127 else
03128 actual_width_ = desired_width_;
03129
03130 row_col available = v->window()->size();
03131
03132 row_col upper_left( (available.row_ - actual_height_)/2,
03133 (available.col_ - actual_width_)/2
03134 );
03135
03136 v->move(upper_left, row_col(actual_height_+1, actual_width_+1));
03137
03138
03139 int page_height = input_row_;
03140
03141 iterator scan = page_top_;
03142
03143 bool current_found = false;
03144
03145 while(scan != end_ && page_height < actual_height_)
03146 {
03147 if(scan == current_line_)
03148 current_found = true;
03149
03150 ++scan;
03151 ++page_height;
03152 }
03153
03154 page_bottom_ = scan;
03155
03156 if(!current_found)
03157 current_line_ = page_top_;
03158
03159 }
03160
03161 void draw_current_line(viewport *v, bool highlighted)
03162
03163
03164
03165
03166 {
03167 int row_offset = 0;
03168 size_t avail_width = actual_width_ - input_col_;
03169
03170 iterator scan = page_top_;
03171
03172 while(scan != current_line_ && scan != page_bottom_)
03173 {
03174 ++row_offset;
03175 ++scan;
03176 }
03177
03178 v->set_curpos(input_row_ + row_offset, input_col_);
03179
03180 v->set_text_attribute(highlighted ? CursorWindow::normal :
03181 CursorWindow::dialog_normal_att);
03182
03183 if(current_line_->size() > avail_width)
03184 {
03185
03186 string avail_text(current_line_->substr(current_line_->size() - (avail_width -4),
03187 current_line_->size()
03188 )
03189 );
03190
03191 v->write(".../");
03192 v->write(avail_text);
03193
03194 }
03195 else
03196 v->write(*current_line_);
03197
03198 v->fill_to_eol();
03199 {
03200 using namespace CursesInterface;
03201 v->set_curpos(input_row_ + row_offset, actual_width_);
03202 v->write(line_chars[VL_MIDDLE],1);
03203 }
03204 v->set_curpos(input_row_ + row_offset, input_col_ + auto_complete_column_);
03205
03206 }
03207
03208 void draw_current_line(std::auto_ptr<viewport> &v, bool highlighted)
03209 {
03210 draw_current_line(v.get(), highlighted);
03211 }
03212
03213
03214 };
03215
03216 CursorWindow::Selection::
03217 Selection(string title)
03218 {
03219 selection_ = "";
03220
03221 impl_ = new Impl;
03222
03223 impl_->title_ = title;
03224
03225 impl_->title_row_ = 0;
03226 impl_->title_col_ = 0;
03227 impl_->input_row_ = 1;
03228 impl_->input_col_ = 2;
03229
03230 }
03231
03232 CursorWindow::Selection::
03233 ~Selection()
03234 {
03235 delete impl_;
03236
03237 impl_ = 0;
03238 }
03239
03240 template<class Iterator>
03241 inline
03242 int count_distance(Iterator a, Iterator b)
03243 {
03244 int rv=0;
03245
03246 while(a != b)
03247 {
03248 ++rv;
03249 ++a;
03250 }
03251
03252 return rv;
03253 }
03254
03255
03256 bool
03257 CursorWindow::Selection::
03258 popup(CursorWindow* w)
03259
03262
03263 {
03264 SaveRestoreActiveWindow _sr(w);
03265
03266 std::auto_ptr<viewport> v(w->new_viewport(this,viewport::floating).release());
03267
03268 int desired_width = 0;
03269 int desired_height= 0;
03270
03271 impl_->auto_complete_column_ = 0;
03272
03273 rep_type::iterator scan = rep_.begin(),
03274 end = rep_.end();
03275
03276 while(scan != end)
03277 {
03278 int s = scan->size();
03279
03280 ++desired_height;
03281
03282 if(s > desired_width)
03283 desired_width = s;
03284
03285 ++scan;
03286
03287 }
03288
03289 desired_height += impl_->input_row_;
03290 desired_width += impl_->input_col_;
03291
03292 if( int(impl_->title_.size())+3 > (impl_->title_col_ + desired_width) )
03293 desired_width = impl_->title_.size() + 3 + impl_->title_col_;
03294
03295 impl_->desired_width_ = desired_width;
03296 impl_->desired_height_ = desired_height;
03297 impl_->page_top_ = rep_.begin();
03298 impl_->page_bottom_ = rep_.end();
03299 impl_->current_line_ = rep_.begin();
03300 impl_->begin_ = rep_.begin();
03301 impl_->end_ = rep_.end();
03302
03303
03304 v->activate();
03305
03306 CursorWindow::input_event e;
03307
03308 selection_.resize(0);
03309
03310 for(;;)
03311 {
03312 e = w->read_input();
03313
03314 int edit_func = w->func[e.value_];
03315
03316 if(edit_func != CursorWindow::func_data)
03317 {
03318 impl_->auto_complete_column_ = 0;
03319 }
03320
03321 switch(edit_func)
03322 {
03323 case CursorWindow::func_down:
03324 if(impl_->current_line_ != impl_->page_bottom_)
03325 {
03326
03327 impl_->draw_current_line(v.get(),false);
03328 ++impl_->current_line_;
03329
03330 if(impl_->current_line_ == impl_->page_bottom_)
03331 {
03332
03333
03334 if(impl_->page_bottom_ != impl_->end_)
03335 {
03336 ++impl_->page_top_;
03337 (*this)(v.get(),0);
03338 }
03339 else
03340 --impl_->current_line_;
03341
03342 }
03343
03344 impl_->draw_current_line(v.get(),true);
03345
03346 }
03347 else
03348 if(impl_->page_bottom_ != impl_->end_)
03349 {
03350 ++impl_->page_top_;
03351 ++impl_->current_line_;
03352 (*this)(v.get(),0);
03353 impl_->draw_current_line(v.get(),true);
03354 }
03355 else
03356 w->beep();
03357 break;
03358 case CursorWindow::func_up:
03359 if(impl_->current_line_ != impl_->page_top_)
03360 {
03361 impl_->draw_current_line(v, false);
03362 --impl_->current_line_;
03363 impl_->draw_current_line(v, true);
03364 }
03365 else
03366 if(impl_->page_top_ != impl_->begin_)
03367 {
03368 --impl_->page_top_;
03369 --impl_->current_line_;
03370 (*this)(v.get(), 0);
03371 impl_->draw_current_line(v, true);
03372 }
03373 break;
03374 case CursorWindow::func_prior:
03375 {
03376 int page_height = impl_->actual_height_ - impl_->input_row_;
03377
03378 if(impl_->page_top_ == impl_->begin_)
03379 {
03380 impl_->current_line_ = impl_->page_top_;
03381 }
03382 else
03383 {
03384 while(page_height && impl_->page_top_ != impl_->begin_)
03385 {
03386 --page_height;
03387 --impl_->page_top_;
03388 --impl_->current_line_;
03389 }
03390 }
03391
03392 (*this)(v.get(),0);
03393
03394 impl_->draw_current_line(v, true);
03395
03396
03397
03398 }
03399 break;
03400 case CursorWindow::func_next:
03401 {
03402 int page_height = count_distance(impl_->page_top_, impl_->page_bottom_);
03403
03404 if(impl_->page_bottom_ == impl_->end_)
03405 {
03406 goto page_bottom;
03407 }
03408 else
03409 {
03410 while(page_height && impl_->page_bottom_ != impl_->end_)
03411 {
03412 --page_height;
03413 ++impl_->page_top_;
03414 ++impl_->current_line_;
03415 ++impl_->page_bottom_;
03416 }
03417 }
03418
03419 (*this)(v.get(),0);
03420
03421 impl_->draw_current_line(v, true);
03422
03423 }
03424 break;
03425 case CursorWindow::func_top:
03426
03427 impl_->draw_current_line(v, false);
03428
03429 impl_->page_top_ = impl_->begin_;
03430 impl_->current_line_ = impl_->begin_;
03431
03432 (*this)(v.get(),0);
03433
03434 impl_->draw_current_line(v, true);
03435
03436 break;
03437 case CursorWindow::func_bottom:
03438
03439 page_bottom:
03440
03441 impl_->draw_current_line(v, false);
03442
03443 impl_->page_top_ = impl_->end_;
03444 --impl_->page_top_;
03445
03446 impl_->current_line_ = impl_->page_top_;
03447
03448 (*this)(v.get(),0);
03449
03450 impl_->draw_current_line(v, true);
03451 break;
03452
03453 case CursorWindow::func_esc:
03454 return true;
03455
03456 case CursorWindow::func_enter:
03457
03458 if(impl_->current_line_ != impl_->end_)
03459 selection_ = *impl_->current_line_;
03460 else
03461 return true;
03462
03463 return false;
03464
03465 case CursorWindow::func_data:
03466 {
03467 rep_type::iterator cur = impl_->current_line_,
03468 end = rep_.end();
03469
03470 int count=0;
03471 bool foundit=false;
03472
03473 while(cur != end)
03474 {
03475 string const& s = *cur;
03476
03477 if(s.size() > impl_->auto_complete_column_)
03478 {
03479 if(s[impl_->auto_complete_column_] == e.value_)
03480 {
03481
03482
03483 foundit = true;
03484 break;
03485 }
03486 }
03487 else
03488 {
03489 break;
03490 }
03491
03492 ++cur;
03493 ++count;
03494 }
03495
03496 if(foundit)
03497 {
03498 impl_->draw_current_line(v, false);
03499
03500 ++impl_->auto_complete_column_;
03501
03502 while(count--)
03503 {
03504 if(impl_->current_line_ == impl_->page_bottom_)
03505 {
03506 ++impl_->current_line_;
03507
03508 int page_size = impl_->actual_height_ -
03509 impl_->input_row_;
03510
03511 while(page_size-- && impl_->page_bottom_ != rep_.end())
03512 {
03513 ++impl_->page_top_;
03514 ++impl_->page_bottom_;
03515 }
03516
03517 }
03518 else
03519 {
03520 ++impl_->current_line_;
03521 }
03522 }
03523
03524 (*this)(v.get(),0);
03525
03526 impl_->draw_current_line(v, true);
03527
03528 }
03529
03530
03531 }
03532 break;
03533
03534 default:
03535 v->beep();
03536 break;
03537 }
03538
03539 v->set_curpos(impl_->input_row_ +
03540 count_distance(impl_->page_top_, impl_->current_line_),
03541 impl_->input_col_ + impl_->auto_complete_column_
03542 );
03543
03544 }
03545
03546
03547 return true;
03548 }
03549
03550 static
03551 void
03552 output_short_string(viewport *v, string const &s, size_t maxlen)
03553 {
03554 if(s.size() <= maxlen)
03555 v->write(s);
03556 else
03557 {
03558 int siz = (int)(s.size());
03559 int ml = (int)(maxlen);
03560
03561 int index = siz - (ml - 4);
03562
03563 if(index < 0)
03564 index = 0;
03565
03566 string tmp( s.substr((size_t)(index), s.size()) );
03567
03568 v->write(".../");
03569 v->write(tmp);
03570
03571 }
03572 }
03573
03574
03575 void
03576 CursorWindow::Selection::
03577 operator() (viewport *v, int cmd)
03578 {
03579 impl_->compute_page_info(v);
03580
03581 v->set_text_attribute(CursorWindow::reversed);
03582
03583 v->set_curpos(0,0);
03584 v->box(impl_->actual_width_+1, impl_->actual_height_+1, true, impl_->title_);
03585
03586
03587 v->set_text_attribute(CursorWindow::dialog_normal_att);
03588
03589 int row = impl_->input_row_;
03590
03591 rep_type::iterator scan = impl_->page_top_,
03592 end = impl_->page_bottom_;
03593
03594 int input_row =0;
03595
03596 size_t avail_width = impl_->actual_width_ - impl_->input_col_;
03597
03598 while(scan != end)
03599 {
03600 v->set_curpos(row, impl_->input_col_);
03601
03602 if(scan == impl_->current_line_)
03603 {
03604 v->set_text_attribute(CursorWindow::normal);
03605 output_short_string(v, *scan, avail_width);
03606
03607 v->fill_to_eol();
03608
03609 {
03610 using namespace CursesInterface;
03611
03612 v->set_curpos(row, impl_->actual_width_);
03613
03614 v->write(line_chars[VL_MIDDLE], 1);
03615
03616 }
03617
03618 v->set_text_attribute(CursorWindow::dialog_normal_att);
03619
03620 input_row = row;
03621
03622 }
03623 else
03624 output_short_string(v, *scan, avail_width);
03625
03626 ++scan;
03627 ++row;
03628
03629 }
03630
03631 v->set_curpos(input_row, impl_->input_col_ + impl_->auto_complete_column_);
03632
03633
03634 }
03635
03636
03637
03638
03639 string
03640 CursorWindow::
03641 select_file(string const &title, string const &pattern, CursorWindow* w)
03642
03643
03644 {
03645
03646 FileName::sorted_names_t names;
03647
03648 int name_count = FileName::find_matching(pattern, &names);
03649
03650 if(name_count == 0)
03651 return "";
03652
03653 Selection s(title);
03654
03655 FileName::sorted_names_t::iterator scan = names.begin(),
03656 end = names.end();
03657
03658 while(scan != end)
03659 {
03660 s += *scan++;
03661 }
03662
03663 if(s.popup(w))
03664 return "";
03665
03666 return s.selection_;
03667
03668
03669 }
03670
03671 std::auto_ptr<viewport>
03672 viewport::
03673 hsplit(viewport::repaint_handler* rh)
03674 {
03675 std::auto_ptr<viewport> rv( new viewport(port_->window_, rh) );
03676
03677 row_col origin(port_->origin());
03678 row_col size (port_->size());
03679
03680 if(size.col_ > 20 && size.row_ > 3)
03681 {
03682
03683
03684 int available_width = size.col_;
03685
03686 int target_width = available_width/2;
03687
03688 int parent_width = available_width - target_width;
03689
03690 size.col_ = parent_width;
03691
03692 move(origin, size);
03693
03694 size.col_ = target_width;
03695
03696 origin.col_ += parent_width;
03697
03698 }
03699
03700 rv->move(origin, size);
03701
03702
03703 return rv;
03704 }
03705
03706 std::auto_ptr<viewport>
03707 viewport::
03708 vsplit(viewport::repaint_handler* rh)
03709 {
03710 std::auto_ptr<viewport> rv( new viewport(port_->window_, rh));
03711
03712 row_col origin(port_->origin());
03713 row_col size (port_->size());
03714
03715 if(size.col_ > 20 && size.row_ > 3)
03716 {
03717
03718
03719 int available_height = size.row_;
03720
03721 int target_height = available_height/2;
03722
03723 int parent_height = available_height - target_height;
03724
03725 size.row_ = parent_height;
03726
03727 move(origin, size);
03728
03729 size.row_ = target_height;
03730
03731 origin.row_ += parent_height;
03732
03733 }
03734
03735 rv->move(origin, size);
03736
03737 return rv;
03738
03739 }
03740
03741 int
03742 CursorWindow::
03743 get_viewports(std::list<CursorWindow::viewport> * viewports)
03744 {
03745 int rv=0;
03746
03747 while(rv < window_->viewports_)
03748 {
03749 viewports->push_back(viewport(window_->viewport_[rv]) );
03750 ++rv;
03751 }
03752
03753 return rv;
03754
03755 }
03756
03757 CursorWindow::viewport::
03758 viewport(viewport const &r)
03759 {
03760 port_ = (port*)(r.port_);
03761 owned_= false;
03762
03763 }
03764
03765 CursorWindow::viewport::repaint_handler *
03766 CursorWindow::viewport::
03767 get_repaint_handler()
03768 {
03769 return port_->handler_;
03770 }
03771
03772 void
03773 CursorWindow::viewport::
03774 set_repaint_handler(CursorWindow::viewport::repaint_handler *r)
03775 {
03776 port_->handler_ = r;
03777 }
03778
03779
03780 string
03781 CursorWindow::Dialog::
03782 element_value(string const &name)
03783 {
03784 iterator first = begin(),
03785 last = end();
03786
03787 while(first != last)
03788 {
03789 Element* e = *first++;
03790
03791 if(e->name_ == name)
03792 return e->value_;
03793
03794 }
03795
03796 return "";
03797 }
03798
03799 CursorWindow::Dialog::Impl::iterator
03800 CursorWindow::Dialog::Impl::
03801 find_element(string const &name)
03802 {
03803 iterator first = elements_.begin(),
03804 last = elements_.end();
03805
03806 while(first != last)
03807 {
03808 Element* e = *first;
03809
03810 if(e->name_ == name)
03811 return first;
03812
03813 ++first;
03814
03815 }
03816
03817 return last;
03818 }
03819
03822 class CursorWindow::Message::Impl
03823
03827
03828 {
03829 public:
03830
03831 typedef CursorWindow::Message::rep_type rep_type;
03832 typedef rep_type::iterator iterator;
03833
03834 string title_;
03835
03836 int desired_width_;
03837 int desired_height_;
03838 int actual_width_;
03839 int actual_height_;
03840
03841 iterator page_top_;
03842 iterator page_bottom_;
03843
03844 iterator current_line_;
03845
03846 iterator begin_;
03847 iterator end_;
03848
03849 int title_col_;
03850 int title_row_;
03851 int input_row_;
03852 int input_col_;
03853
03854 string search_text_;
03855
03856
03857 void compute_page_info(viewport *v)
03858
03859
03860
03861
03862
03863
03864
03865
03866 {
03867 row_col size = v->window()->size();
03868
03869 if(desired_height_ > size.row_)
03870 actual_height_ = size.row_;
03871 else
03872 actual_height_ = desired_height_;
03873
03874
03875 if(desired_width_ > size.col_)
03876 actual_width_ = size.col_;
03877 else
03878 actual_width_ = desired_width_;
03879
03880 row_col available = v->window()->size();
03881
03882 row_col upper_left( (available.row_ - actual_height_)/2,
03883 (available.col_ - actual_width_)/2
03884 );
03885
03886 v->move(upper_left, row_col(actual_height_, actual_width_));
03887
03888
03889 int page_height = input_row_;
03890
03891 iterator scan = page_top_;
03892
03893 bool current_found = false;
03894
03895 while(scan != end_ && page_height < actual_height_)
03896 {
03897 if(scan == current_line_)
03898 current_found = true;
03899
03900 ++scan;
03901 ++page_height;
03902 }
03903
03904 page_bottom_ = scan;
03905
03906 if(!current_found)
03907 current_line_ = page_top_;
03908
03909 }
03910
03911 int move_to_current_line(viewport *v)
03912
03913
03914 {
03915 int row_offset = 0;
03916
03917 iterator scan = page_top_;
03918
03919 while(scan != current_line_ && scan != page_bottom_)
03920 {
03921 ++row_offset;
03922 ++scan;
03923 }
03924
03925 v->set_curpos(input_row_ + row_offset, input_col_);
03926
03927 return row_offset;
03928 }
03929
03930
03931 void draw_current_line(viewport *v, bool highlighted)
03932
03933
03934
03935
03936 {
03937 int row_offset=0;
03938
03939 row_offset = move_to_current_line(v);
03940
03941 #if 0
03942 v->set_text_attribute(highlighted ? CursorWindow::normal :
03943 CursorWindow::dialog_normal_att
03944 );
03945 #else
03946 v->set_text_attribute(CursorWindow::dialog_normal_att);
03947 #endif
03948
03949 v->write(*current_line_);
03950 v->fill_to_eol();
03951
03952 v->set_curpos(input_row_ + row_offset, input_col_);
03953
03954
03955
03956 }
03957
03958 void draw_current_line(std::auto_ptr<viewport> &v, bool highlighted)
03959 {
03960 draw_current_line(v.get(), highlighted);
03961 }
03962
03963
03964 };
03965
03966 CursorWindow::Message::
03967 Message(string title)
03968 {
03969 impl_ = new Impl;
03970
03971 impl_->title_ = title;
03972
03973 impl_->title_row_ = 0;
03974 impl_->title_col_ = 0;
03975 impl_->input_row_ = 1;
03976 impl_->input_col_ = 2;
03977
03978 }
03979
03980 CursorWindow::Message::
03981 ~Message()
03982 {
03983 delete impl_;
03984
03985 impl_ = 0;
03986 }
03987
03988 void
03989 CursorWindow::Message::
03990 popup(CursorWindow* w)
03991
03994
03995 {
03996 SaveRestoreActiveWindow _sr(w);
03997
03998 std::auto_ptr<viewport> v(w->new_viewport(this,viewport::floating).release());
03999
04000 int desired_width = 0;
04001 int desired_height= 0;
04002
04003 rep_type::iterator scan = rep_.begin(),
04004 end = rep_.end();
04005
04006 while(scan != end)
04007 {
04008 int s = scan->size();
04009
04010 ++desired_height;
04011
04012 if(s > desired_width)
04013 desired_width = s;
04014
04015 ++scan;
04016
04017 }
04018
04019 desired_height += impl_->input_row_;
04020 desired_width += impl_->input_col_;
04021
04022 if( int(impl_->title_.size()) > (impl_->title_col_ + desired_width) )
04023 desired_width = impl_->title_.size() + impl_->title_col_;
04024
04025 impl_->desired_width_ = desired_width;
04026 impl_->desired_height_ = desired_height;
04027 impl_->page_top_ = rep_.begin();
04028 impl_->page_bottom_ = rep_.end();
04029 impl_->current_line_ = rep_.begin();
04030 impl_->begin_ = rep_.begin();
04031 impl_->end_ = rep_.end();
04032
04033 v->activate();
04034
04035
04036 CursorWindow::input_event e;
04037
04038 for(;;)
04039 {
04040
04041 {
04042
04043
04044
04045
04046
04047 w->set_curpos(0,0);
04048 w->refresh();
04049 w->set_curpos(1,1);
04050 w->refresh();
04051 }
04052
04053
04054 impl_->move_to_current_line(v.get());
04055
04056 e = w->read_input();
04057
04058 int edit_func = w->func[e.value_];
04059
04060 switch(edit_func)
04061 {
04062 case CursorWindow::func_down:
04063
04064 if(impl_->current_line_ != impl_->page_bottom_)
04065 {
04066 impl_->draw_current_line(v.get(),false);
04067 ++impl_->current_line_;
04068
04069 if(impl_->current_line_ == impl_->page_bottom_)
04070 {
04071
04072
04073 if(impl_->page_bottom_ != impl_->end_)
04074 {
04075 ++impl_->page_top_;
04076 (*this)(v.get(),0);
04077 }
04078 else
04079 --impl_->current_line_;
04080
04081 }
04082
04083 impl_->draw_current_line(v.get(),true);
04084
04085 }
04086 else
04087 if(impl_->page_bottom_ != impl_->end_)
04088 {
04089 ++impl_->page_top_;
04090 ++impl_->current_line_;
04091 (*this)(v.get(),0);
04092 impl_->draw_current_line(v.get(),true);
04093 }
04094 else
04095 w->beep();
04096 break;
04097 case CursorWindow::func_up:
04098 if(impl_->current_line_ != impl_->page_top_)
04099 {
04100 impl_->draw_current_line(v, false);
04101 --impl_->current_line_;
04102 impl_->draw_current_line(v, true);
04103 }
04104 else
04105 if(impl_->page_top_ != impl_->begin_)
04106 {
04107 --impl_->page_top_;
04108 --impl_->current_line_;
04109 (*this)(v.get(), 0);
04110 impl_->draw_current_line(v, true);
04111 }
04112 break;
04113 case CursorWindow::func_prior:
04114 {
04115 int page_height = count_distance(impl_->page_top_, impl_->page_bottom_);
04116
04117 if(page_height && impl_->page_top_ != impl_->begin_)
04118 {
04119 while(page_height && impl_->page_top_ != impl_->begin_)
04120 {
04121 --page_height;
04122 --impl_->page_top_;
04123 --impl_->current_line_;
04124 }
04125 }
04126 else
04127 {
04128 impl_->current_line_ = impl_->page_top_;
04129 }
04130
04131 (*this)(v.get(),0);
04132
04133 impl_->draw_current_line(v, true);
04134
04135
04136 }
04137 break;
04138 case CursorWindow::func_next:
04139 {
04140 int page_height = count_distance(impl_->page_top_, impl_->page_bottom_);
04141
04142 if(page_height && impl_->page_bottom_ != impl_->end_)
04143 {
04144 while(page_height && impl_->page_bottom_ != impl_->end_)
04145 {
04146 --page_height;
04147 ++impl_->page_top_;
04148 ++impl_->current_line_;
04149 ++impl_->page_bottom_;
04150 }
04151 }
04152 else
04153 {
04154 impl_->current_line_ = impl_->page_bottom_;
04155
04156 if(impl_->current_line_ == impl_->end_ && impl_->begin_ != impl_->end_)
04157 {
04158 --impl_->current_line_;
04159 }
04160
04161 }
04162
04163 (*this)(v.get(),0);
04164
04165 impl_->draw_current_line(v, true);
04166
04167 }
04168 break;
04169 case CursorWindow::func_top:
04170
04171 impl_->draw_current_line(v, false);
04172
04173 impl_->page_top_ = impl_->begin_;
04174 impl_->current_line_ = impl_->begin_;
04175
04176 (*this)(v.get(),0);
04177
04178 impl_->draw_current_line(v, true);
04179
04180 break;
04181 case CursorWindow::func_bottom:
04182
04183 impl_->draw_current_line(v, false);
04184
04185 impl_->page_top_ = impl_->end_;
04186 --impl_->page_top_;
04187
04188 impl_->current_line_ = impl_->page_top_;
04189
04190 (*this)(v.get(),0);
04191
04192 impl_->draw_current_line(v, true);
04193 break;
04194
04195 case CursorWindow::func_esc:
04196 return;
04197
04198 case CursorWindow::func_enter:
04199 return;
04200
04201
04202 case CursorWindow::func_find:
04203 {
04204 Dialog d(" Search help ");
04205
04206 d += new Dialog::String("text",
04207 " For",
04208 impl_->search_text_,
04209 20
04210 );
04211
04212 bool scrollDown = false;
04213
04214 if(!d.popup(w))
04215 {
04216 impl_->search_text_ = d.element_value("text");
04217
04218 rep_type::iterator scan = impl_->current_line_;
04219
04220 while(scan != impl_->end_)
04221 {
04222 if(scan == impl_->page_bottom_)
04223 scrollDown = true;
04224
04225 if(StrTool::find(impl_->search_text_, *scan, true) < scan->size())
04226 {
04227 break;
04228 }
04229
04230 ++scan;
04231 }
04232
04233
04234 if(scan != impl_->end_)
04235 {
04236 impl_->draw_current_line(v, false);
04237
04238 if(scrollDown)
04239 {
04240 impl_->page_top_ = scan;
04241
04242 impl_->current_line_ = impl_->page_top_;
04243
04244 (*this)(v.get(),0);
04245
04246 }
04247 else
04248 {
04249 impl_->current_line_ = scan;
04250 }
04251
04252 impl_->draw_current_line(v, true);
04253 }
04254 else
04255 w->beep();
04256
04257 }
04258
04259 }
04260 break;
04261
04262 case CursorWindow::func_findnxt:
04263 {
04264 rep_type::iterator scan = impl_->current_line_;
04265
04266 ++scan;
04267
04268 bool scrollDown = false;
04269
04270 while(scan != impl_->end_)
04271 {
04272 if(scan == impl_->page_bottom_)
04273 scrollDown = true;
04274
04275 if(StrTool::find(impl_->search_text_, *scan, true) < scan->size())
04276 {
04277 break;
04278 }
04279
04280 ++scan;
04281 }
04282
04283
04284 if(scan != impl_->end_)
04285 {
04286 impl_->draw_current_line(v, false);
04287
04288 if(scrollDown)
04289 {
04290 impl_->page_top_ = scan;
04291
04292 impl_->current_line_ = impl_->page_top_;
04293
04294 (*this)(v.get(),0);
04295
04296 }
04297 else
04298 {
04299 impl_->current_line_ = scan;
04300 }
04301
04302 impl_->draw_current_line(v, true);
04303 }
04304 else
04305 w->beep();
04306
04307
04308 }
04309 break;
04310
04311 case CursorWindow::func_data:
04312
04313
04314
04315 switch(e.value_)
04316 {
04317 case 'q':
04318 case 'Q':
04319 return;
04320 }
04321
04322 break;
04323
04324 default:
04325 v->beep();
04326 break;
04327 }
04328
04329 }
04330
04331 }
04332
04333
04334
04335
04336 void CursorWindow::Message::
04337 operator() (viewport *v, int cmd)
04338 {
04339 impl_->compute_page_info(v);
04340
04341 v->set_text_attribute(CursorWindow::dialog_normal_att);
04342
04343 v->set_curpos(0,0);
04344 v->fill_to_eos();
04345
04346 v->set_text_attribute(CursorWindow::dialog_title_att);
04347 v->set_curpos(impl_->title_row_, impl_->title_col_);
04348 v->write(impl_->title_);
04349
04350 v->set_text_attribute(CursorWindow::dialog_normal_att);
04351
04352 int row = impl_->input_row_;
04353
04354 rep_type::iterator scan = impl_->page_top_,
04355 end = impl_->page_bottom_;
04356
04357
04358 while(scan != end)
04359 {
04360 v->set_curpos(row, impl_->input_col_);
04361
04362 #if 0
04363 if(scan == impl_->current_line_)
04364 {
04365 v->set_text_attribute(CursorWindow::normal_att);
04366 v->write(*scan);
04367 v->fill_to_eol();
04368 v->set_text_attribute(CursorWindow::dialog_normal_att);
04369 }
04370 else
04371 #endif
04372 v->write(*scan);
04373
04374 ++scan;
04375 ++row;
04376
04377 }
04378
04379 }
04380
04381
04382 void
04383 CursorWindow::
04384 resize_viewports(row_col const &old_size, row_col const &new_size)
04385 {
04386 window_->resize_viewports(old_size, new_size);
04387 window_->repaint_ports();
04388 }
04389
04390
04391 CursorWindow::FileSelector::
04392 FileSelector(std::string const &title,
04393 std::string const &searchPattern,
04394 std::string const &startFile
04395 )
04396 : title_(title)
04397 , searchPattern_(searchPattern)
04398 , startFile_(startFile)
04399 , noRepaint_(false)
04400 {
04401 title_ += " (F1=help)";
04402 }
04403
04404 void
04405 CursorWindow::FileSelector::
04406 operator() ( viewport * v, int cmd )
04407 {
04408
04409 if(noRepaint_)
04410 return;
04411
04412 adaptToWindow(v);
04413
04414 paintDialogBackground(v);
04415
04416 size_t rowTextSize = rowText_.size();
04417
04418 for(int i=0; i < displayAreaHeight_; ++i)
04419 {
04420 size_t curIndex = size_t(i) + size_t(inputTopIndex_);
04421
04422 if( curIndex >= rowTextSize )
04423 break;
04424
04425 v->set_curpos(i+displayAreaRow_, displayAreaCol_);
04426
04427 std::string const &name = rowText_[curIndex];
04428
04429 if(curIndex == size_t(inputIndex_))
04430 v->set_text_attribute(CursorWindow::dialog_title_att);
04431 else
04432 v->set_text_attribute(CursorWindow::dialog_normal_att);
04433
04434 v->write(name);
04435
04436 }
04437
04438 }
04439
04440 void
04441 CursorWindow::FileSelector::
04442 adaptToWindow( viewport * v)
04443 {
04444 size_t windowWidth = v->size().col_;
04445 size_t windowHeight = v->size().row_;
04446
04447 size_t titleWidth = title_.size();
04448
04449 dialogWidth_ = (maxNameWidth_+2 > titleWidth+4) ? maxNameWidth_+2 : titleWidth+4;
04450
04451
04452
04453 if(size_t(dialogWidth_) > windowWidth -2)
04454 dialogWidth_ = windowWidth-2;
04455
04456 dialogHeight_ = rowText_.size() + 1;
04457
04458 if(size_t(dialogHeight_) > windowHeight-2)
04459 dialogHeight_ = windowHeight -2;
04460
04461 row_ = (windowHeight - dialogHeight_)/2;
04462 col_ = (windowWidth - dialogWidth_) /2;
04463
04464 row_ += v->origin().row_;
04465 col_ += v->origin().col_;
04466
04467
04468 displayAreaRow_ = row_+1;
04469 displayAreaCol_ = col_+1;
04470 displayAreaWidth_ = dialogWidth_ -3;
04471 displayAreaHeight_ = dialogHeight_ -2;
04472
04473 v->set_curpos(inputIndex_ + displayAreaRow_, displayAreaCol_);
04474
04475 if(inputIndex_ - inputTopIndex_ >= displayAreaHeight_)
04476 {
04477 inputTopIndex_ = inputIndex_;
04478 }
04479
04480 }
04481
04482
04483 void
04484 CursorWindow::FileSelector::
04485 paintDialogBackground(viewport* v)
04486 {
04487
04488
04489
04490
04491
04492 v->set_curpos(row_, col_);
04493 v->set_text_attribute(CursorWindow::dialog_normal_att);
04494
04495 v->box(dialogWidth_, dialogHeight_, true, title_.c_str());
04496
04497
04498 }
04499
04500 void
04501 CursorWindow::FileSelector::
04502 readFileInfo()
04503 {
04504
04505
04506
04507
04508 FileName::sorted_names_t names;
04509
04510 FileName tmp(searchPattern_);
04511
04512 searchDir_ = tmp.dirname();
04513
04514 if(searchDir_.empty() || searchDir_[0] == '.')
04515 {
04516
04517
04518
04519 char buffer[3000];
04520
04521 if( getcwd(buffer, sizeof(buffer)) )
04522 {
04523 searchDir_ = buffer;
04524
04525 searchDir_ += '/';
04526 }
04527
04528 }
04529
04530
04531 FileName::find_matching(searchPattern_, &names);
04532
04533 maxNameWidth_=0;
04534
04535 rowText_.clear();
04536
04537 rowText_.push_back("<ENTER A NAME>");
04538
04539 CXXTLS_FOREACH(std::string const &name, names)
04540 {
04541 size_t nameWidth = name.size();
04542
04543 if(nameWidth == 1 && name[0] == '.')
04544 {
04545 }
04546 else
04547 {
04548 if(nameWidth == 2 && (name[0] == '.' && name[1] == '.'))
04549 {
04550 }
04551 else
04552 {
04553 if(maxNameWidth_ < nameWidth)
04554 maxNameWidth_ = nameWidth;
04555
04556 rowText_.push_back(name);
04557 }
04558 }
04559 }
04560
04561 inputIndex_ = 0;
04562 inputTopIndex_ = 0;
04563
04564 if(!startFile_.empty())
04565 {
04566 for(size_t i = 0; i < rowText_.size(); ++i)
04567 {
04568 if(rowText_[i] == startFile_)
04569 {
04570 inputIndex_ = i;
04571
04572 if(i > 10)
04573 {
04574 inputTopIndex_ = i-10;
04575 }
04576
04577 break;
04578 }
04579 }
04580 }
04581
04582
04583
04584 }
04585
04586 void
04587 CursorWindow::FileSelector::
04588 paintRow(CursorWindow *w, int displayAreaRow)
04589 {
04590
04591
04592
04593
04594 int rowTextIndex = inputTopIndex_ + displayAreaRow;
04595
04596 w->set_curpos(displayAreaRow_ + displayAreaRow,
04597 displayAreaCol_);
04598
04599 if(inputIndex_ - inputTopIndex_ == displayAreaRow)
04600 w->set_text_attribute(CursorWindow::dialog_title_att);
04601 else
04602 w->set_text_attribute(CursorWindow::dialog_normal_att);
04603
04604 w->write(rowText_[rowTextIndex], displayAreaWidth_);
04605
04606 }
04607
04608
04609 std::string
04610 CursorWindow::FileSelector::
04611 handleInput(CursorWindow *w, Viewer *parent)
04612 {
04613 SaveRestoreActiveWindow _sr(w);
04614
04615 std::auto_ptr<viewport> v(w->new_viewport(this,viewport::floating).release());
04616
04617 CursorWindow::input_event e;
04618
04619 static std::string nothing;
04620
04621 v->activate();
04622
04623 for(;;)
04624 {
04625 w->set_curpos(inputIndex_ -inputTopIndex_ + displayAreaRow_, displayAreaCol_);
04626
04627 e = w->read_input();
04628
04629 int edit_func = w->func[e.value_];
04630
04631
04632 char pushBackKey=0;
04633
04634
04635 switch(edit_func)
04636 {
04637 default:
04638
04639
04640
04641 switch(e.value_)
04642 {
04643 case 0x06:
04644 {
04645
04646 eraseMe(w);
04647
04648 CursorWindow::Dialog d("Enter a different directory name");
04649
04650 d += new CursorWindow::Dialog::String("name",
04651 "Other Directory ",
04652 "",
04653 40
04654 );
04655
04656
04657 noRepaint_ = true;
04658 int rv = d.popup(w);
04659
04660
04661
04662 noRepaint_ = false;
04663
04664 if( !rv )
04665 {
04666 std::string value = d.element_value("name");
04667
04668 if(value != "")
04669 {
04670 FileName dir(value);
04671
04672 if(! dir.is_dir() )
04673 {
04674 if( !dir.exists() )
04675 {
04676 CursorWindow::Message m("That's not a valid file or directory");
04677 m += "";
04678 m += "Sorry, can't find that";
04679
04680 m.popup(w);
04681
04682 eraseMe(w);
04683
04684
04685 this->operator()(v.get(), 0);
04686 break;
04687
04688 }
04689
04690
04691
04692 startFile_=dir.basename();
04693
04694 dir = dir.dirname();
04695
04696 }
04697
04698
04699
04700 if( dir[dir.size()-1] != '/'
04701 && dir[dir.size()-1] != '\\'
04702 )
04703 {
04704 dir += '/';
04705 }
04706
04707 dir += '*';
04708
04709 searchPattern_ = dir;
04710
04711 readFileInfo();
04712
04713 eraseMe(w);
04714
04715 this->operator()(v.get(),0);
04716
04717
04718
04719
04720 }
04721
04722 }
04723
04724
04725
04726 w->set_curpos(0,0);
04727 w->refresh();
04728 w->set_curpos(1,1);
04729 w->refresh();
04730
04731
04732 }
04733 break;
04734
04735 default:
04736 v->beep();
04737 break;
04738 }
04739
04740 break;
04741
04742 case CursorWindow::func_enter:
04743
04744 if( (inputIndex_ > 1)
04745 && (size_t(inputIndex_) < rowText_.size() )
04746 )
04747 {
04748 FileName file = searchDir_ + rowText_[inputIndex_];
04749
04750 if(file.is_dir())
04751 {
04752 eraseMe(w);
04753
04754 searchPattern_ = file + "/*";
04755
04756 readFileInfo();
04757
04758 this->operator()(v.get(),0);
04759
04760 break;
04761
04762 }
04763 }
04764
04765 goto promptForName;
04766
04767
04768 case CursorWindow::func_up:
04769
04770 if(inputIndex_)
04771 {
04772
04773 if(inputIndex_ == inputTopIndex_)
04774 {
04775
04776
04777 int prev = inputTopIndex_ - 1;
04778
04779 if(prev < 0)
04780 prev = 0;
04781
04782 inputIndex_ = prev;
04783 inputTopIndex_ = prev;
04784
04785 this->operator() (v.get(),0);
04786
04787 }
04788 else
04789 {
04790 int displayOffset = inputIndex_ - inputTopIndex_;
04791
04792 --inputIndex_;
04793 paintRow(w, displayOffset);
04794 paintRow(w, displayOffset-1);
04795 }
04796
04797 }
04798 else
04799 v->beep();
04800
04801 break;
04802
04803 case CursorWindow::func_down:
04804 {
04805 int offset = inputIndex_ - inputTopIndex_;
04806
04807 int availableTextRows = int(rowText_.size()) - inputTopIndex_;
04808
04809 int lastDisplayableRow;
04810
04811 if(availableTextRows > displayAreaHeight_)
04812 lastDisplayableRow = displayAreaHeight_ -1;
04813 else
04814 lastDisplayableRow = availableTextRows -1;
04815
04816 if(offset < lastDisplayableRow)
04817 {
04818 int displayOffset = inputIndex_ - inputTopIndex_;
04819
04820 ++inputIndex_;
04821
04822 paintRow(w, displayOffset);
04823 paintRow(w, displayOffset+1);
04824
04825 }
04826 else
04827 {
04828
04829 if( int(inputTopIndex_) >= int(rowText_.size())-1 )
04830 {
04831 w->beep();
04832 }
04833 else
04834 {
04835 if( (int)(inputIndex_) >= int(rowText_.size())-1 )
04836 {
04837 w->beep();
04838 }
04839 else
04840 {
04841 ++inputTopIndex_;
04842 ++inputIndex_;
04843
04844 this->operator() (v.get(),0);
04845 }
04846 }
04847
04848 }
04849
04850 }
04851 break;
04852
04853 case CursorWindow::func_next:
04854 {
04855 int offset = inputIndex_ - inputTopIndex_;
04856
04857 int next = inputTopIndex_ + displayAreaHeight_;
04858
04859 if( next > int(rowText_.size())-1 )
04860 {
04861 v->beep();
04862 }
04863 else
04864 {
04865 inputTopIndex_ = next;
04866
04867 inputIndex_ = next + offset;
04868
04869 if(inputIndex_ > int(rowText_.size())-1 )
04870 {
04871 inputIndex_ = rowText_.size()-1;
04872 }
04873
04874 this->operator() (v.get(),0);
04875 }
04876
04877
04878 }
04879 break;
04880
04881 case CursorWindow::func_prior:
04882 if(rowText_.size() == 0)
04883 v->beep();
04884 else
04885 {
04886 int offset = inputIndex_ - inputTopIndex_;
04887
04888 int prev = inputTopIndex_ - displayAreaHeight_;
04889
04890 if( prev < 0 )
04891 {
04892 prev = 0;
04893 offset = 0;
04894 }
04895
04896
04897 inputTopIndex_ = prev;
04898
04899 inputIndex_ = prev + offset;
04900
04901 this->operator() (v.get(),0);
04902
04903 }
04904 break;
04905
04906 case CursorWindow::func_help:
04907 {
04908 CursorWindow::Message m("File selector Help");
04909
04910 m += "Select from the file list or enter a file's name.";
04911 m += "";
04912 m += " Standard arrows and paging keys are active.";
04913 m += "";
04914 m += " Other keyboard interpretation:";
04915 m += "";
04916 m += " Printable Chars Just start typing to be prompted for a file name.";
04917 m += "";
04918 m += " Enter Enter a subdirectory, OR, select the file";
04919 m += " under the cursor to be prompted for modifications ";
04920 m += " to that file name (if any).";
04921 m += "";
04922 m += " Space SELECT the directory or file under the cursor";
04923 m += "";
04924 m += " ^ Navigate up a directory level";
04925 m += "";
04926 m += " ^F Goto another directory by name";
04927 m += "";
04928
04929 m.popup(w);
04930
04931 eraseMe(w);
04932
04933 w->set_curpos(0,0);
04934 w->refresh();
04935 w->set_curpos(1,1);
04936 w->refresh();
04937
04938 }
04939 break;
04940
04941 case CursorWindow::func_data:
04942
04943
04944
04945
04946
04947
04948 switch(e.value_)
04949 {
04950 default:
04951
04952 if(e.value_ > ' ' && e.value_ <= '~' )
04953 {
04954 pushBackKey = e.value_;
04955 goto promptForName;
04956 }
04957
04958 v->beep();
04959 break;
04960
04961
04962 case 'q':
04963 case 'Q':
04964 return nothing;
04965
04966 case ' ':
04967 if( size_t(inputIndex_) < rowText_.size())
04968 {
04969 return searchDir_ + rowText_[inputIndex_];
04970 }
04971 break;
04972
04973 case '.':
04974 {
04975 promptForName:
04976 {
04977
04978 CursorWindow::Dialog d("Manually enter a file name ");
04979
04980 string startValue;
04981
04982 if(pushBackKey)
04983 {
04984 startValue += pushBackKey;
04985 }
04986 else
04987 if( (inputIndex_ > 0)
04988 && (size_t(inputIndex_) < rowText_.size())
04989 )
04990 startValue = rowText_[inputIndex_];
04991
04992
04993
04994
04995
04996 CursorWindow::Dialog::String *str;
04997
04998 d += str = new CursorWindow::Dialog::String("name",
04999 "new file name",
05000 startValue,
05001 40
05002 );
05003
05004
05005 str->setColumn( startValue.size() );
05006
05007 eraseMe(w);
05008
05009 noRepaint_ = true;
05010
05011 int rv = d.popup(w);
05012
05013 noRepaint_ = false;
05014
05015 if( !rv )
05016 {
05017 FileName value = d.element_value("name");
05018
05019 if(value != "")
05020 {
05021 if(value.is_absolute_path())
05022 return value;
05023
05024 return searchDir_ + value;
05025 }
05026
05027 }
05028
05029
05030
05031
05032
05033 this->operator()(v.get(),0);
05034
05035
05036
05037
05038 v->set_curpos(0,0);
05039 v->set_curpos(1,1);
05040 v->refresh();
05041
05042 }
05043
05044
05045
05046
05047 }
05048 break;
05049
05050
05051 case '^':
05052 {
05053
05054 FileName f(searchDir_);
05055
05056 if(f.is_root_dir())
05057 {
05058 v->beep();
05059 break;
05060 }
05061
05062 if(!f.empty())
05063 {
05064
05065
05066
05067
05068 char last = f[ f.size() - 1];
05069
05070 if(last == '/' || last == '\\')
05071 {
05072 f.erase(f.size()-1);
05073 }
05074
05075 startFile_ = f.basename();
05076 }
05077
05078 eraseMe(w);
05079
05080 w->refresh();
05081
05082 FileName file = FileName(searchDir_).dirname();
05083
05084 char last = 0;
05085
05086 if(file.size() > 1)
05087 {
05088 last = file[file.size()-1];
05089
05090 }
05091
05092 if(last == '/' || last == '\\')
05093 {
05094 file.erase(file.size()-1);
05095
05096 searchPattern_ = std::string(file.dirname()) + "*";
05097
05098 readFileInfo();
05099
05100 this->operator()(v.get(),0);
05101
05102 }
05103 else
05104 v->beep();
05105
05106 }
05107 break;
05108
05109
05110
05111
05112 }
05113
05114 break;
05115
05116 case CursorWindow::func_esc:
05117 return nothing;
05118
05119
05120 }
05121
05122 }
05123 }
05124
05125 std::string
05126 CursorWindow::FileSelector::
05127 popup(CursorWindow* w, Viewer *parent)
05128 {
05129
05130
05131 readFileInfo();
05132
05133 return handleInput(w, parent);
05134
05135 }
05136
05137 void
05138 CursorWindow::FileSelector::
05139 eraseMe(CursorWindow *w)
05140 {
05141 noRepaint_ = true;
05142 w->repaint_all();
05143 noRepaint_ = false;
05144
05145 }
05146
05147
05148 void CursorWindow::repaint_all()
05149 {
05150 row_col loc = curpos();
05151
05152 window_->repaint_ports();
05153
05154 set_curpos(0,0);
05155 set_curpos(1,1);
05156 set_curpos(loc);
05157
05158 }
05159
05160 }
05161
05162