1 /*
2 khwin.cc Hypertext Window
3 Copyright (c) 1997-8,2000,2002,2003,2004,2007,2009 Kriang Lerdsuwanakij
4 email: lerdsuwa@users.sourceforge.net
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "khwin.h"
22 #include "cstrlib.h"
23
24 /*************************************************************************
25 khGeometryManager
26 *************************************************************************/
27
28 bool khGeometryManager::disableScrollBar = false;
29
SetWinRect(int id,NCRect & rect)30 void khGeometryManager::SetWinRect(int id, NCRect &rect)
31 {
32 if (mode == modeNoScroll || disableScrollBar) {
33 switch(id) {
34 case idHyperWindow:
35 rect.SetX(0);
36 rect.SetY(0);
37 rect.SetRow(LINES-2);
38 rect.SetCol(COLS);
39 break;
40 case idStatWindow:
41 rect.SetX(0);
42 rect.SetY(LINES-2);
43 rect.SetCol(COLS);
44 rect.SetRow(1);
45 break;
46 case idURLWindow:
47 rect.SetX(0);
48 rect.SetY(LINES-1);
49 rect.SetCol(COLS);
50 rect.SetRow(1);
51 break;
52 case idHScrollBar:
53 rect.SetX(COLS-20);
54 rect.SetY(LINES-2);
55 rect.SetCol(0);
56 rect.SetRow(1);
57 break;
58 case idVScrollBar:
59 rect.SetX(COLS-1);
60 rect.SetY(0);
61 rect.SetCol(1);
62 rect.SetRow(0);
63 break;
64 case idScrollBox:
65 rect.SetX(COLS-1);
66 rect.SetY(LINES-2);
67 rect.SetCol(0);
68 rect.SetRow(0);
69 break;
70 case idMoreBar:
71 rect.SetX(COLS-2);
72 rect.SetY(0);
73 rect.SetCol(1);
74 rect.SetRow(0);
75 break;
76 }
77 }
78 else if (mode == modeHScroll) {
79 switch(id) {
80 case idHyperWindow:
81 rect.SetX(0);
82 rect.SetY(0);
83 rect.SetRow(LINES-2);
84 rect.SetCol(COLS-1); // Reserve More bar
85 break;
86 case idStatWindow:
87 rect.SetX(0);
88 rect.SetY(LINES-2);
89 rect.SetCol(COLS-20);
90 rect.SetRow(1);
91 break;
92 case idURLWindow:
93 rect.SetX(0);
94 rect.SetY(LINES-1);
95 rect.SetCol(COLS);
96 rect.SetRow(1);
97 break;
98 case idHScrollBar:
99 rect.SetX(COLS-20);
100 rect.SetY(LINES-2);
101 rect.SetCol(19);
102 rect.SetRow(1);
103 break;
104 case idVScrollBar:
105 rect.SetX(COLS-1);
106 rect.SetY(0);
107 rect.SetCol(1);
108 rect.SetRow(0);
109 break;
110 case idScrollBox:
111 rect.SetX(COLS-1);
112 rect.SetY(LINES-2);
113 rect.SetCol(1);
114 rect.SetRow(1);
115 break;
116 case idMoreBar:
117 rect.SetX(COLS-1);
118 rect.SetY(0);
119 rect.SetCol(1);
120 rect.SetRow(LINES-2);
121 break;
122 }
123 }
124 else if (mode == modeVScroll) {
125 switch(id) {
126 case idHyperWindow:
127 rect.SetX(0);
128 rect.SetY(0);
129 rect.SetRow(LINES-2);
130 rect.SetCol(COLS-1); // Vertical scroll bar
131 break;
132 case idStatWindow:
133 rect.SetX(0);
134 rect.SetY(LINES-2);
135 rect.SetCol(COLS);
136 rect.SetRow(1);
137 break;
138 case idURLWindow:
139 rect.SetX(0);
140 rect.SetY(LINES-1);
141 rect.SetCol(COLS);
142 rect.SetRow(1);
143 break;
144 case idHScrollBar:
145 rect.SetX(COLS-20);
146 rect.SetY(LINES-2);
147 rect.SetCol(0);
148 rect.SetRow(1);
149 break;
150 case idVScrollBar:
151 rect.SetX(COLS-1);
152 rect.SetY(0);
153 rect.SetCol(1);
154 rect.SetRow(LINES-2);
155 break;
156 case idScrollBox:
157 rect.SetX(COLS-1);
158 rect.SetY(LINES-2);
159 rect.SetCol(0);
160 rect.SetRow(0);
161 break;
162 case idMoreBar:
163 rect.SetX(COLS-2);
164 rect.SetY(0);
165 rect.SetCol(1);
166 rect.SetRow(0);
167 break;
168 }
169 }
170 else if (mode == modeHVScroll) {
171 switch(id) {
172 case idHyperWindow:
173 rect.SetX(0);
174 rect.SetY(0);
175 rect.SetRow(LINES-2);
176 rect.SetCol(COLS-2);
177 break;
178 case idStatWindow:
179 rect.SetX(0);
180 rect.SetY(LINES-2);
181 rect.SetCol(COLS-20);
182 rect.SetRow(1);
183 break;
184 case idURLWindow:
185 rect.SetX(0);
186 rect.SetY(LINES-1);
187 rect.SetCol(COLS);
188 rect.SetRow(1);
189 break;
190 case idHScrollBar:
191 rect.SetX(COLS-20);
192 rect.SetY(LINES-2);
193 rect.SetCol(19);
194 rect.SetRow(1);
195 break;
196 case idVScrollBar:
197 rect.SetX(COLS-1);
198 rect.SetY(0);
199 rect.SetCol(1);
200 rect.SetRow(LINES-2);
201 break;
202 case idScrollBox:
203 rect.SetX(COLS-1);
204 rect.SetY(LINES-2);
205 rect.SetCol(1);
206 rect.SetRow(1);
207 break;
208 case idMoreBar:
209 rect.SetX(COLS-2);
210 rect.SetY(0);
211 rect.SetCol(1);
212 rect.SetRow(LINES-2);
213 break;
214 }
215 }
216 }
217
218 /*************************************************************************
219 khScreenManager
220 *************************************************************************/
221
222 ATTR_TYPE normalA, linkA, highlightA, barA, urlA, headerA, boldA,
223 italicA, markA, linkBoldA, linkItalicA, highlightBoldA,
224 highlightItalicA;
225 ATTR_TYPE scrollArrowA, scrollBarA, scrollBlockA;
226 entity_id scrollBarID, scrollBlockID;
227
RequestResize()228 void khScreenManager::RequestResize()
229 {
230 if (COLS < 50 || LINES < 10) {
231 lockScreen = true;
232 clear();
233 move(0, 0);
234 addstr(_("Screen too small - please resize to make it bigger."));
235 refresh();
236 }
237 else {
238 lockScreen = false;
239 NCScreenManager::RequestResize();
240 }
241 }
242
243 /* Preprocess any key pressed before passing to ProcessKey functions. */
244
ReadKeyboard()245 int khScreenManager::ReadKeyboard()
246 {
247 bool isCtrlF = false;
248 for ( ; ; ) {
249 if (!lockScreen) {
250 int c = NCScreenManager::ReadKeyboard();
251 if (c == KEY_F(8)) // Refresh screen
252 RequestRefresh();
253 // ^R or ^L
254 else if ((c == 'R'-'A'+1 && kcdConfig.cfgKey == keyBindingDefault)
255 || (c == 'L'-'A'+1 && kcdConfig.cfgKey == keyBindingVi))
256 RequestRefresh();
257 // ^F
258 else if (c == 'F'-'A'+1 && kcdConfig.cfgKey == keyBindingDefault) {
259 isCtrlF = !isCtrlF; // Toggle state
260 if (ctrlWin)
261 ctrlWin->ProcessCtrl('F', isCtrlF);
262 }
263 else if (isCtrlF) {
264 isCtrlF = false;
265 if (c >= '0' && c <= '9') {
266 if (c == '0')
267 return KEY_F(10);
268 else
269 return KEY_F(c-'0');
270 }
271 }
272 else
273 return c;
274 }
275 else {
276 // No display when window is too small
277
278 isCtrlF = false; // Clear any previous
279 // ^F
280
281 // Read and discard all input
282 NCScreenManager::ReadKeyboard();
283 }
284 }
285 }
286
InitAttr(int id,const AttrConfig & cfg,ATTR_TYPE & attr)287 void khScreenManager::InitAttr(int id, const AttrConfig &cfg, ATTR_TYPE& attr)
288 {
289 if (has_colors() == TRUE) {
290 int colorBackground = cfg.colorBackground;
291 if (colorBackground == DEFAULT_COLOR)
292 colorBackground = kcdConfig.cfgDefaultBackground;
293 init_pair(id, cfg.colorForeground, colorBackground);
294 attr = static_cast<ATTR_TYPE>(COLOR_PAIR(id) | cfg.colorAttr);
295 }
296 else
297 attr = cfg.bwAttr;
298 }
299
khScreenManager(NCGeometryManagerBase & geoMan_)300 khScreenManager::khScreenManager(NCGeometryManagerBase &geoMan_) :
301 NCScreenManager(geoMan_), lockScreen(false)
302 {
303 NCurses::InitMore(stdscr); // Set term. echo, etc. for stdscr
304
305 InitAttr(1, kcdConfig.cfgAttrNormal, normalA);
306 InitAttr(3, kcdConfig.cfgAttrLink, linkA);
307 InitAttr(5, kcdConfig.cfgAttrHighlight, highlightA);
308 InitAttr(7, kcdConfig.cfgAttrURL, urlA);
309 InitAttr(9, kcdConfig.cfgAttrHeader, headerA);
310 InitAttr(11, kcdConfig.cfgAttrBold, boldA);
311 InitAttr(13, kcdConfig.cfgAttrItalic, italicA);
312 InitAttr(15, kcdConfig.cfgAttrScrollArrow, scrollArrowA);
313 InitAttr(17, kcdConfig.cfgAttrScrollBlock, scrollBlockA);
314 InitAttr(19, kcdConfig.cfgAttrScrollBar, scrollBarA);
315 InitAttr(21, kcdConfig.cfgAttrTitle, barA);
316 InitAttr(23, kcdConfig.cfgAttrMore, markA);
317 InitAttr(25, kcdConfig.cfgAttrLinkBold, linkBoldA);
318 InitAttr(27, kcdConfig.cfgAttrLinkItalic, linkItalicA);
319 InitAttr(29, kcdConfig.cfgAttrHighlightBold, highlightBoldA);
320 InitAttr(31, kcdConfig.cfgAttrHighlightItalic, highlightItalicA);
321
322 scrollBlockID = EID_SPACE;
323 if (isACSFallBack) // No special symbols
324 scrollBarID = EID_SPACE;
325 else
326 scrollBarID = EID_CKBOARD;
327 }
328
329
330 /*************************************************************************
331 HyperWindow - the complete hypertext viewer
332 *************************************************************************/
333
GetDocRow()334 int HyperWindow::GetDocRow()
335 {
336 return Max(GetRow(), html.GetNumRow());
337 }
338
GetDocColumn()339 int HyperWindow::GetDocColumn()
340 {
341 return Max(GetCol(), html.GetNumColumn());
342 }
343
GetNumChar(int y)344 int HyperWindow::GetNumChar(int y)
345 {
346 if (y >= html.GetNumRow())
347 return 0;
348 return html.numChar[y];
349 }
350
HyperWindow(NCScreenManager & scrn_,int id_,HyperDocument & html_,StatusWindowBase & status_,StatusWindowBase & url_,ScrollBarBase & hscroll_,ScrollBarBase & vscroll_,const string & startSection_,int lockKey_,int row,int col)351 HyperWindow::HyperWindow(NCScreenManager &scrn_, int id_, HyperDocument &html_,
352 StatusWindowBase &status_, StatusWindowBase &url_,
353 ScrollBarBase &hscroll_, ScrollBarBase &vscroll_,
354 const string &startSection_, int lockKey_, int row, int col)
355 : NCWindowBase(scrn_, id_), marker(scrn_, idMoreBar),
356 html(html_), status(status_),
357 url(url_), hscroll(hscroll_), vscroll(vscroll_),
358 blankWin(NULL), newSelected("", 0, TYPE_NULL)
359 {
360 viFoundG = false;
361 viFoundZ = false;
362 viFoundCount = false;
363 viCount = 1;
364
365 emacsFoundAlt = false;
366
367 startSection = startSection_;
368 lockKey = lockKey_;
369
370 initSize = 0;
371
372 isInitScreen = 0;
373 InitObject();
374
375 if (row > 0 && col > 0) {
376 initRow = row;
377 initColumn = col;
378 initSize = 1; // Have size info
379 }
380
381 PrepareDisplay(false);
382 }
383
~HyperWindow()384 HyperWindow::~HyperWindow()
385 {
386 if (blankWin) {
387 delwin(blankWin);
388 blankWin = NULL;
389 }
390 }
391
InitObject()392 void HyperWindow::InitObject() // Clear document-dependent
393 // variables
394 {
395 anchorSelected = NULL;
396 prevHighlight = NULL;
397 }
398
Init()399 void HyperWindow::Init()
400 {
401 NCWindowBase::Init();
402 if (win) { // Free previously used pad
403 delwin(win);
404 win = NULL;
405 }
406 if (blankWin) { // Free previously used pad
407 delwin(blankWin);
408 blankWin = NULL;
409 }
410
411 int useHScroll = 0, useVScroll = 0;
412 int colLeft = COLS;
413 int rowLeft = LINES-2; // Reserve 2 rows for status & URL
414 // bar
415 if (html.GetNumRow() > rowLeft) {
416 useVScroll = 1;
417 colLeft--; // Vertical scroll bar taken
418 }
419 if (html.GetNumColumn() > colLeft) {
420 useHScroll = 1;
421 colLeft--; // More bar taken
422 }
423 scrnMan.RequestChangeMode(useVScroll*2+useHScroll);
424
425 // From now on, GetRow() and
426 // GetCol() returns correct
427 // values
428
429 hscroll.SetTotalSize(GetDocColumn());
430 hscroll.SetVisualSize(GetCol());
431 vscroll.SetTotalSize(GetDocRow());
432 vscroll.SetVisualSize(GetRow());
433
434 // Save actual columns used
435 numRealColumn = html.GetNumColumn();
436
437 // Our new pad
438 win = newpad(GetDocRow(), numRealColumn);
439 if (win == NULL)
440 throw bad_alloc();
441
442 if (win->_line == NULL) { // Some macros are broken due to
443 // different bool size
444 // Better check available ?
445 throw ErrorBadNCurses();
446 }
447
448 NCurses::InitMore(win);
449
450 if (numRealColumn < GetCol()) {
451 if (GetRow() && GetCol())
452 blankWin = newwin(GetRow(), GetCol()-numRealColumn,
453 0, numRealColumn);
454 else
455 blankWin = NULL;
456
457 // This shouldn't happen
458 if (blankWin == NULL)
459 throw bad_alloc();
460
461 wbkgd(blankWin, normalA); // Set normal attr as background
462 wattrset(blankWin, normalA); // Set normal text attr
463 werase(blankWin); // Use werase(...) instead
464 // of wclear(...) to
465 // remove flicker
466 }
467 else
468 blankWin = NULL;
469
470 wbkgd(win, normalA); // Set normal attr as background
471 wattrset(win, normalA); // Set normal text attr
472 }
473
Highlight()474 void HyperWindow::Highlight()
475 {
476 int curR, curC;
477 int row = curRow+padRow, column = curColumn+padColumn;
478 int prev = 0, next = 0; // Linked-list traverse direction
479
480 hscroll.SetPosition(padColumn);
481 vscroll.SetPosition(padRow);
482
483 int i, j;
484 for (i = padRow, j = 0; j < GetRow(); i++, j++) {
485 if (GetNumChar(i) <= padColumn + GetCol())
486 marker.Mark(j, ' '|normalA); // Use normalA so that
487 // when the text is
488 // selected (using mouse
489 // under xterm/rxvt), the
490 // attr is the same as
491 // text in dir tree
492 else
493 marker.Mark(j, '+'|markA);
494 }
495 marker.DoUpdate();
496
497 if (prevHighlight) {
498 curR = prevHighlight->rowFrom;
499 curC = prevHighlight->colFrom;
500 wmove(win, curR, curC);
501
502 wattrset(win, linkA); // wattrset required to
503 // force spaces to have the
504 // same attribute as this
505
506 while (curR < prevHighlight->rowTo ||
507 (curR == prevHighlight->rowTo &&
508 curC <= prevHighlight->colTo)) {
509
510 if (curC == GetNumChar(curR)) { // End of row
511 curC = 0;
512 curR++;
513 wmove(win, curR, curC);
514 }
515 else {
516 // Replace attribute
517 #ifdef USE_UTF8_MODE
518 if (IsUTF8Mode()) {
519 cchar_t cc;
520 win_wch(win, &cc);
521 chtype attr = cc.attr;
522 if (attr == static_cast<chtype>(highlightA)) {
523 wattrset(win, linkA);
524 cc.attr = linkA;
525 }
526 else if (attr == static_cast<chtype>(highlightBoldA)) {
527 wattrset(win, linkBoldA);
528 cc.attr = linkBoldA;
529 }
530 else if (attr == static_cast<chtype>(highlightItalicA)) {
531 wattrset(win, linkItalicA);
532 cc.attr = linkItalicA;
533 }
534
535 wadd_wch(win, &cc);
536 curC++;
537 }
538 else
539 #endif
540 {
541 chtype c, chr, attr;
542 c = winch(win);
543 attr = c & ~(A_CHARTEXT|A_ALTCHARSET);
544 chr = c & (A_CHARTEXT|A_ALTCHARSET);
545 if (attr == static_cast<chtype>(highlightA)) {
546 wattrset(win, linkA);
547 }
548 else if (attr == static_cast<chtype>(highlightBoldA)) {
549 wattrset(win, linkBoldA);
550 }
551 else if (attr == static_cast<chtype>(highlightItalicA)) {
552 wattrset(win, linkItalicA);
553 }
554
555 waddch(win, chr);
556 curC++;
557 }
558 }
559 }
560 prevHighlight = NULL;
561 }
562
563 for ( ; ; ) {
564 if (prev && next) { // Found nearest anchor
565 url.SetTitle("");
566 DoUpdate();
567 return;
568 }
569
570 if (PosAtAnchor(curAnchorIter, column, row)) {
571 /* Found */
572
573 prevHighlight = (*curAnchorIter)();
574
575 curR = prevHighlight->rowFrom;
576 curC = prevHighlight->colFrom;
577 wmove(win, curR, curC);
578
579 wattrset(win, highlightA);
580
581 while (curR < prevHighlight->rowTo ||
582 (curR == prevHighlight->rowTo &&
583 curC <= prevHighlight->colTo)) {
584
585 if (curC == GetNumChar(curR)) { // End of row
586 curC = 0;
587 curR++;
588 wmove(win, curR, curC);
589 }
590 else {
591 // Replace attribute
592 // Fixme Unicode
593 #ifdef USE_UTF8_MODE
594 if (IsUTF8Mode()) {
595 cchar_t cc;
596 win_wch(win, &cc);
597 chtype attr = cc.attr;
598 if (attr == static_cast<chtype>(linkA)) {
599 wattrset(win, highlightA);
600 cc.attr = highlightA;
601 }
602 else if (attr == static_cast<chtype>(linkBoldA)) {
603 wattrset(win, highlightBoldA);
604 cc.attr = highlightBoldA;
605 }
606 else if (attr == static_cast<chtype>(linkItalicA)) {
607 wattrset(win, highlightItalicA);
608 cc.attr = highlightItalicA;
609 }
610
611 wadd_wch(win, &cc);
612 curC++;
613 }
614 else
615 #endif
616 {
617 chtype c, chr, attr;
618 c = winch(win);
619 attr = c & ~(A_CHARTEXT|A_ALTCHARSET);
620 chr = c & (A_CHARTEXT|A_ALTCHARSET);
621 if (attr == static_cast<chtype>(linkA)) {
622 wattrset(win, highlightA);
623 }
624 else if (attr == static_cast<chtype>(linkBoldA)) {
625 wattrset(win, highlightBoldA);
626 }
627 else if (attr == static_cast<chtype>(linkItalicA)) {
628 wattrset(win, highlightItalicA);
629 }
630
631 waddch(win, chr);
632 curC++;
633 }
634 }
635 }
636 url.SetTitle((*curAnchorIter)->name);
637 DoUpdate();
638 return;
639 }
640
641 if (PosBeforeAnchor(curAnchorIter, column, row)) {
642 /* Have to use prev node of linked-list */
643 if (curAnchorIter == html.GetAnchorList().begin()) {
644 /* Ignore */
645 url.SetTitle("");
646 DoUpdate();
647 return;
648 }
649 else
650 --curAnchorIter;
651 prev = 1;
652 continue;
653 }
654
655 if (PosAfterAnchor(curAnchorIter, column, row)) {
656 /* Have to use next node of linked-list */
657 if (curAnchorIter == --(html.GetAnchorList().end())) {
658 /* Ignore */
659 url.SetTitle("");
660 DoUpdate();
661 return;
662 }
663 else
664 ++curAnchorIter;
665 next = 1;
666 continue;
667 }
668 }
669 }
670
PrepareDisplay(bool sameDocument)671 void HyperWindow::PrepareDisplay(bool sameDocument)
672 {
673 if (! sameDocument) {
674
675 InitObject(); // Clear document-dependent varialbles
676
677 InitGeometry(); // We need window size for GetRow and
678 // GetCol below
679 if (!initSize) { // No size info available
680 html.FormatDocument(NULL, LINES-2, COLS-2);
681 }
682 else {
683 initSize = 0; // size is used
684 html.SetDocumentSize(initRow, initColumn, GetRow(), GetCol());
685 }
686
687 Init(); // Allocate a new pad
688
689 // Output document
690 html.FormatDocument(win, LINES-2, COLS-2);
691
692 status.SetTitle(html.GetTitle());
693
694 }
695 else {
696 anchorSelected = NULL;
697 // Do not reset prevHighlight
698 }
699
700 padRow = 0, padColumn = 0; /* Pad position */
701 curRow = 0, curColumn = 0; /* Cursor position */
702 const Anchor *curSection = NULL;
703
704 curAnchorIter = html.GetAnchorList().begin();
705
706 if (html.GetAnchorList().size() == 0 && lockKey) {
707 throw ErrorGenericSyntax(_("no <A HREF=...> tags present\n"
708 "Do not use the `-c\' option for this file"));
709 }
710
711 if (startSection.size()) {
712 for (iterType iter = html.GetSectionList().begin();
713 iter != html.GetSectionList().end(); ++iter) {
714 if ((*iter)->name == startSection) {
715 curSection = (*iter)();
716 break;
717 }
718 }
719
720 if (curSection == NULL) {
721 throw ErrorGenericSyntax(_("cannot find <A NAME=\"%$\">"),
722 startSection);
723 }
724 }
725
726 if (lockKey || curSection) {
727 if (!lockKey) {
728 /* Put cursor at specified section */
729
730 /* Center of the screen */
731 padRow = (curSection->rowTo+curSection->rowFrom)/2 -
732 (GetRow()-1)/2;
733 padColumn = (curSection->colTo+curSection->colFrom)/2 -
734 (GetCol()-1)/2;
735
736 /* Check lower limit */
737 if (padRow < 0)
738 padRow = 0;
739 if (padColumn < 0)
740 padColumn = 0;
741
742 /* Check upper limit */
743 padRow = Min(padRow, GetDocRow()-GetRow());
744 padColumn = Min(padColumn, GetDocColumn()-GetCol());
745
746 /* Calc. cursor position */
747 curRow = curSection->rowFrom-padRow;
748 curColumn = curSection->colFrom-padColumn;
749 }
750
751 if (curSection) {
752 /* Find anchor directly after curSection */
753 for ( ; curAnchorIter != --(html.GetAnchorList().end()); ++curAnchorIter) {
754 if ((*curAnchorIter)->rowFrom > curSection->rowFrom ||
755 ((*curAnchorIter)->rowFrom == curSection->rowFrom &&
756 (*curAnchorIter)->colFrom >= curSection->colFrom))
757 break;
758 }
759
760 }
761
762 /* Found first goto/exec */
763 if (lockKey) {
764 /* Put cursor at the link directly
765 after section name */
766 CenterPad(curAnchorIter);
767
768 /* Check lower limit */
769 if (padRow < 0)
770 padRow = 0;
771 if (padColumn < 0)
772 padColumn = 0;
773
774 /* Check upper limit */
775 padRow = Min(padRow, GetDocRow()-GetRow());
776 padColumn = Min(padColumn, GetDocColumn()-GetCol());
777
778 /* Calc. cursor position */
779 curRow = (*curAnchorIter)->rowFrom-padRow;
780 curColumn = (*curAnchorIter)->colFrom-padColumn;
781
782 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
783 // Highlight bar too long - show only
784 // left portion and discard parts
785 // that go beyond the screen width
786
787 // Scroll left
788 padColumn += curColumn;
789 curColumn = 0;
790 }
791 }
792 }
793
794 if (lockKey) /* No need for cursor */
795 cursor.Hide();
796
797 Highlight();
798 scrnMan.RequestRestCursor();
799 }
800
MatchSubString(iterType & curA,const string & findText)801 bool HyperWindow::MatchSubString(iterType &curA, const string &findText)
802 {
803 if ((*curA)->linkText.find(findText) != string::npos)
804 return true; // Found
805 return false; // Not found
806 }
807
DoResize()808 void HyperWindow::DoResize()
809 {
810 InitGeometry();
811
812 if (!win) // Window not initialized yet, due to mode changing
813 // in Init(). This also prevents from infinite loop
814 // since Init() is called below.
815 return;
816
817 int curAnchorIndex = 0;
818 int cursorRow = 0;
819 int cursorColumn = 0;
820
821 // Try to preserve cursor position after screen resize
822 if (lockKey) {
823 // Save the index of current highlighted anchor
824
825 for (iterType iter = html.GetAnchorList().begin();
826 iter != curAnchorIter; ++iter) {
827 curAnchorIndex++;
828 }
829 }
830 else { // The best we can do now - may be changed later
831 cursorRow = curRow+padRow;
832 cursorColumn = curColumn+padColumn;
833 }
834
835 InitObject(); // Clear document-dependent varialbles
836
837 html.FormatDocument(NULL, LINES-2, COLS-2);
838 Init();
839 html.FormatDocument(win, LINES-2, COLS-2);
840
841 // Restore cursor position
842 if (lockKey) {
843 // Seek to current highlighted anchor
844
845 for (curAnchorIter = html.GetAnchorList().begin();
846 curAnchorIndex > 0; ++curAnchorIter) {
847 curAnchorIndex--;
848 }
849
850 /* Put cursor at the link directly
851 after section name */
852
853 /* Center of the screen */
854 CenterPad(curAnchorIter);
855
856 /* Check lower limit */
857 if (padRow < 0)
858 padRow = 0;
859 if (padColumn < 0)
860 padColumn = 0;
861
862 /* Check upper limit */
863 padRow = Min(padRow, GetDocRow()-GetRow());
864 padColumn = Min(padColumn, GetDocColumn()-GetCol());
865
866 /* Calc. cursor position */
867 curRow = (*curAnchorIter)->rowFrom-padRow;
868 curColumn = (*curAnchorIter)->colFrom-padColumn;
869
870 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
871 // Highlight bar too long - show only
872 // left portion and discard parts
873 // that go beyond the screen width
874
875 // Scroll left
876 padColumn += curColumn;
877 curColumn = 0;
878 }
879 }
880 else {
881 // Previous cursor position is no longer
882 // valid
883 if (GetDocRow() < cursorRow)
884 cursorRow = GetDocRow()-1;
885 if (GetDocColumn() < cursorColumn)
886 cursorColumn = GetDocColumn()-1;
887
888 /* Center of the screen */
889 padRow = cursorRow-(GetRow()-1)/2;
890 padColumn = cursorColumn-(GetCol()-1)/2;
891
892 /* Check lower limit */
893 if (padRow < 0)
894 padRow = 0;
895 if (padColumn < 0)
896 padColumn = 0;
897
898 /* Check upper limit */
899 padRow = Min(padRow, GetDocRow()-GetRow());
900 padColumn = Min(padColumn, GetDocColumn()-GetCol());
901
902 /* Calc. cursor position */
903 curRow = cursorRow-padRow;
904 curColumn = cursorColumn-padColumn;
905 }
906
907 Highlight();
908 scrnMan.RequestRestCursor();
909 }
910
DoUpdate()911 void HyperWindow::DoUpdate()
912 {
913 if (numRealColumn < GetCol())
914 pnoutrefresh(win, padRow, padColumn, GetY1(), GetX1(),
915 GetY2(), GetX1()+numRealColumn-1);
916 else
917 pnoutrefresh(win, padRow, padColumn, GetY1(), GetX1(),
918 GetY2(), GetX2());
919 if (blankWin)
920 wnoutrefresh(blankWin);
921 }
922
FitHighlightHorizontal(iterType & newA)923 void HyperWindow::FitHighlightHorizontal(iterType &newA)
924 {
925 // Six cases to consider
926 // Legends: | | = screen boundary, **** = highlight
927 // 1 **|** | ==> |**** |
928 // 2 **|***** | ==> *|******|
929 // 3 **|******|* ==> **|******|*
930 // 4 | **** | => | **** |
931 // 5 | **|** ==> | ****|
932 // 6 | *****|** ==> |******|*
933
934 if (curColumn < 0) {
935 if ((*newA)->colTo-(*newA)->colFrom <= GetCol()-1) {
936 // Case 1
937 // Scroll right
938 padColumn += curColumn;
939 curColumn = 0;
940 }
941 else if (curColumn+(*newA)->colTo-(*newA)->colFrom <= GetCol()-1) {
942 // Case 2
943 int diff = GetCol()-1
944 -curColumn-(*newA)->colTo+(*newA)->colFrom;
945 padColumn += diff;
946 curColumn -= diff;
947 }
948 else {
949 // Case 3
950 ;
951 }
952 }
953 else {
954 if (curColumn+(*newA)->colTo-(*newA)->colFrom <= GetCol()-1) {
955 // Case 4
956 ;
957 }
958 else if ((*newA)->colTo-(*newA)->colFrom <= GetCol()-1) {
959 // Case 5
960 // Scroll left
961 int diff = curColumn+(*newA)->colTo-(*newA)->colFrom
962 -GetCol()+1;
963 padColumn += diff;
964 curColumn -= diff;
965 }
966 else {
967 // Case 5
968 padColumn += curColumn;
969 curColumn = 0;
970 }
971 }
972 }
973
FitHighlightTop(iterType & newA)974 void HyperWindow::FitHighlightTop(iterType &newA)
975 {
976 if (curRow < 0) {
977 /* Scroll up */
978 padRow += curRow;
979 curRow = 0;
980 }
981 FitHighlightHorizontal(newA);
982 }
983
CenterRowPad(iterType & newA)984 void HyperWindow::CenterRowPad(iterType &newA)
985 {
986 /* Center of the screen */
987 padRow = ((*newA)->rowTo+(*newA)->rowFrom)/2 - (GetRow()-1)/2;
988 }
989
CenterRowPadIfScroll(iterType & newA)990 void HyperWindow::CenterRowPadIfScroll(iterType &newA)
991 {
992 if ((*newA)->rowFrom < padRow || (*newA)->rowTo > padRow+GetRow()-1)
993 CenterRowPad(newA);
994 }
995
CenterPad(iterType & newA)996 void HyperWindow::CenterPad(iterType &newA)
997 {
998 /* Center of the screen */
999 CenterRowPad(newA);
1000 padColumn = ((*newA)->colTo+(*newA)->colFrom)/2 -
1001 (GetCol()-1)/2;
1002 }
1003
FitHighlightMiddle(iterType & newA)1004 void HyperWindow::FitHighlightMiddle(iterType &newA)
1005 {
1006 /* Check lower limit */
1007 if (padRow < 0)
1008 padRow = 0;
1009
1010 /* Check upper limit */
1011 padRow = Min(padRow, GetDocRow()-GetRow());
1012
1013 /* Calc. cursor position */
1014 curRow = (*newA)->rowFrom-padRow;
1015 curColumn = (*newA)->colFrom-padColumn;
1016
1017 FitHighlightHorizontal(newA);
1018 }
1019
FitHighlightBottom(iterType & newA)1020 void HyperWindow::FitHighlightBottom(iterType &newA)
1021 {
1022 if (curRow+(*newA)->rowTo-(*newA)->rowFrom > GetRow()-1) {
1023 /* Scroll down */
1024 padRow += curRow+(*newA)->rowTo-(*newA)->rowFrom-(GetRow()-1);
1025 curRow = GetRow()-1-((*newA)->rowTo-(*newA)->rowFrom);
1026 }
1027
1028 FitHighlightHorizontal(newA);
1029 }
1030
PosBeforeAnchor(iterType & p,int x,int y)1031 bool HyperWindow::PosBeforeAnchor(iterType &p, int x, int y)
1032 {
1033 if (y < (*p)->rowFrom || (y == (*p)->rowFrom && x < (*p)->colFrom))
1034 return true;
1035 return false;
1036 }
1037
PosAfterAnchor(iterType & p,int x,int y)1038 bool HyperWindow::PosAfterAnchor(iterType &p, int x, int y)
1039 {
1040 if (y > (*p)->rowTo || (y == (*p)->rowTo && x > (*p)->colTo))
1041 return true;
1042 return false;
1043 }
1044
PosAtAnchor(iterType & p,int x,int y)1045 bool HyperWindow::PosAtAnchor(iterType &p, int x, int y)
1046 {
1047 return !(PosAfterAnchor(p, x, y) || PosBeforeAnchor(p, x, y));
1048 }
1049
ProcessCall(Anchor *)1050 Anchor HyperWindow::ProcessCall(Anchor * /*p*/)
1051 {
1052 return Anchor("", 0, TYPE_NULL); // Do nothing
1053 }
1054
1055 #ifdef NCURSES_MOUSE_VERSION
ProcessMouse(MEVENT & event)1056 void HyperWindow::ProcessMouse(MEVENT &event)
1057 {
1058 // Only accepts mouse button 1
1059 if (!(event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED
1060 | BUTTON1_TRIPLE_CLICKED | BUTTON1_RELEASED)))
1061 return;
1062
1063 iterType saveIter = curAnchorIter;
1064 if (html.GetAnchorList().empty()) // No links found
1065 return;
1066
1067 int absRow = event.y-GetY1()+padRow;
1068 int absColumn = event.x-GetX1()+padColumn;
1069 if (PosAtAnchor(curAnchorIter, absColumn, absRow)) {
1070 curRow = absRow-padRow;
1071 curColumn = absColumn-padColumn;
1072 ProcessKey('\r');
1073 }
1074 else if (PosBeforeAnchor(curAnchorIter, absColumn, absRow)) {
1075 while (curAnchorIter != html.GetAnchorList().begin()
1076 && PosBeforeAnchor(curAnchorIter, absColumn, absRow)) {
1077 --curAnchorIter;
1078 }
1079
1080 if (PosAtAnchor(curAnchorIter, absColumn, absRow)) {
1081 curRow = absRow-padRow;
1082 curColumn = absColumn-padColumn;
1083 ProcessKey('\r');
1084 }
1085 else
1086 curAnchorIter = saveIter;
1087 }
1088 else {
1089 while (curAnchorIter != --(html.GetAnchorList().end())
1090 && PosBeforeAnchor(curAnchorIter, absColumn, absRow)) {
1091 ++curAnchorIter;
1092 }
1093
1094 if (PosAtAnchor(curAnchorIter, absColumn, absRow)) {
1095 curRow = absRow-padRow;
1096 curColumn = absColumn-padColumn;
1097 ProcessKey('\r');
1098 }
1099 else
1100 curAnchorIter = saveIter;
1101 }
1102 }
1103 #endif
1104
ProcessKeySelect()1105 void HyperWindow::ProcessKeySelect()
1106 {
1107 int absRow = curRow+padRow;
1108 int absCol = curColumn+padColumn;
1109
1110 /* Look for anchor under
1111 cursor */
1112 if (html.GetAnchorList().empty())
1113 return; /* Ignore */
1114
1115 if (PosAtAnchor(curAnchorIter, absCol, absRow)) {
1116 anchorSelected = (*curAnchorIter)();
1117 }
1118 else /* Cursor not on any link */
1119 return;
1120
1121 if (anchorSelected) {
1122 if (anchorSelected->type == TYPE_CALL) {
1123 newSelected = *anchorSelected;
1124 while (newSelected.type == TYPE_CALL) {
1125 newSelected = ProcessCall(&newSelected);
1126 if (newSelected.type == TYPE_NULL)
1127 return; // Ignore
1128 }
1129 anchorSelected = &newSelected;
1130 }
1131
1132 if (anchorSelected->type == TYPE_GOTO) {
1133
1134 string newHyperFile;
1135
1136 string::size_type s = anchorSelected->name.find('#');
1137 if (s != string::npos) {
1138 startSection = string(anchorSelected->name, s+1);
1139 newHyperFile = string(anchorSelected->name, 0, s);
1140 }
1141 else {
1142 startSection = "";
1143 newHyperFile = anchorSelected->name;
1144 }
1145 anchorSelected = NULL;
1146
1147 /* Link to another file */
1148 if (newHyperFile.size()) {
1149 #ifndef TRIM_NO_DOC_FILE
1150 html.LoadDocument(newHyperFile);
1151 PrepareDisplay(false);
1152 #else
1153 ;
1154 #endif
1155 }
1156 else { // Link to the same file
1157 PrepareDisplay(true);
1158 }
1159
1160 Highlight();
1161 scrnMan.RequestRestCursor();
1162 }
1163 else if (anchorSelected->type == TYPE_EXEC) {
1164 scrnMan.SetFocus(NULL);
1165 return;
1166 }
1167 else if (anchorSelected->type == TYPE_EXIT) {
1168 scrnMan.SetFocus(NULL);
1169 return;
1170 }
1171 /* else unknown anchor type */
1172 }
1173 }
1174
ProcessKeyCenter()1175 void HyperWindow::ProcessKeyCenter()
1176 {
1177 if (html.GetAnchorList().empty())
1178 return; /* Ignore */
1179
1180 int absRow = curRow+padRow;
1181 int absCol = curColumn+padColumn;
1182
1183 if (PosAtAnchor(curAnchorIter, absCol, absRow)) {
1184 CenterRowPad(curAnchorIter);
1185 FitHighlightMiddle(curAnchorIter);
1186 Highlight();
1187 scrnMan.RequestRestCursor();
1188 }
1189 else /* Cursor not on any link */
1190 // FIXME: center screen
1191 return;
1192 }
1193
ProcessKeyNextStatus()1194 void HyperWindow::ProcessKeyNextStatus()
1195 {
1196 url.NextStatus();
1197 Highlight();
1198 scrnMan.RequestRestCursor();
1199 }
1200
ProcessKeyExit()1201 void HyperWindow::ProcessKeyExit()
1202 {
1203 scrnMan.SetFocus(NULL);
1204 }
1205
ProcessKeyPanLeft()1206 void HyperWindow::ProcessKeyPanLeft()
1207 {
1208 if (lockKey) {
1209 if ((*curAnchorIter)->rowFrom == (*curAnchorIter)->rowTo) {
1210
1211 // Highlight bar not as wide as screen
1212 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom+1 < GetCol()) {
1213
1214 // Make sure the entire
1215 // highlight bar is displayed
1216
1217 if (padColumn+GetCol()-1 > (*curAnchorIter)->colTo) {
1218 if (padColumn > 0) {
1219 padColumn--;
1220 curColumn++;
1221 }
1222 }
1223 }
1224
1225 // Highlight bar wider than screen
1226 else if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom+1 > GetCol()) {
1227 if (padColumn > (*curAnchorIter)->colFrom) {
1228 padColumn--;
1229 curColumn++;
1230 }
1231 }
1232 }
1233 else {
1234 // Multi-line highlight
1235
1236 if (padColumn > 0) {
1237 padColumn--;
1238 curColumn++;
1239 }
1240 }
1241 }
1242 else {
1243 if (padColumn > 0)
1244 padColumn--;
1245 }
1246 Highlight();
1247 scrnMan.RequestRestCursor();
1248 }
1249
ProcessKeyPanRight()1250 void HyperWindow::ProcessKeyPanRight()
1251 {
1252 if (lockKey) {
1253 if ((*curAnchorIter)->rowFrom == (*curAnchorIter)->rowTo) {
1254
1255 // Highlight bar not as wide as screen
1256 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom+1 < GetCol()) {
1257
1258 // Make sure the entire
1259 // highlight bar is displayed
1260
1261 if (padColumn < (*curAnchorIter)->colFrom)
1262 if (padColumn+GetCol() < GetDocColumn()) {
1263 padColumn++;
1264 curColumn--;
1265 }
1266 }
1267
1268 // Highlight bar wider than screen
1269 else if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom+1 > GetCol()) {
1270 if (padColumn+GetCol()-1 < (*curAnchorIter)->colTo) {
1271 padColumn++;
1272 curColumn--;
1273 }
1274 }
1275 }
1276 else {
1277 // Multi-line highlight
1278
1279 if (padColumn+GetCol() < GetDocColumn()) {
1280 padColumn++;
1281 curColumn--;
1282 }
1283 }
1284 }
1285 else {
1286 if (padColumn+GetCol() < GetDocColumn())
1287 padColumn++;
1288 }
1289 Highlight();
1290 scrnMan.RequestRestCursor();
1291 }
1292
ProcessKeyUp()1293 void HyperWindow::ProcessKeyUp()
1294 {
1295 if (lockKey) {
1296 iterType saveIter = curAnchorIter;
1297 if (curAnchorIter != html.GetAnchorList().begin()) {
1298 /* Skip links in current line */
1299 do {
1300 --curAnchorIter;
1301 } while (curAnchorIter != html.GetAnchorList().begin()
1302 && ((*curAnchorIter)->rowFrom == (*saveIter)->rowFrom));
1303
1304 // Initialize in case this is the
1305 // topmost anchor
1306 iterType bestAnc = html.GetAnchorList().begin();
1307 int bestDiff = INT_MAX, diff;
1308 int bestOverlap = 0, overlap, overlapRow = -1;
1309
1310 /* Now link not in current line */
1311 for ( ; ; ) {
1312 int from1 = (*curAnchorIter)->colFrom;
1313 int to1 = (*curAnchorIter)->colTo;
1314 int wrap1 = (*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom;
1315 int from2 = (*saveIter)->colFrom;
1316 int to2 = (*saveIter)->colTo;
1317 int wrap2 = (*saveIter)->rowTo-
1318 (*saveIter)->rowFrom;
1319
1320 overlap = 0;
1321
1322 if (!wrap1 && !wrap2 &&
1323 (Max(from1, from2) <= Min(to1, to2)))
1324 overlap = Min(to1, to2)-Max(from1, from2)+1;
1325 else if (wrap1 && !wrap2 &&
1326 (from2 <= to1))
1327 overlap = to1-from2+1;
1328 else if (wrap1 && !wrap2 &&
1329 (to2 >= from1))
1330 overlap = to2-from1+1;
1331 else if (!wrap1 && wrap2 &&
1332 (from1 <= to2))
1333 overlap = to2-from1+1;
1334 else if (!wrap1 && wrap2 &&
1335 (to1 >= from2))
1336 overlap = to1-from2+1;
1337 else if (wrap1 && wrap2)
1338 overlap = Min(to1, to2)+1+
1339 (GetCol()-Max(from1, from2)+1);
1340
1341 if (overlap) {
1342 /* Found */
1343 bestDiff = 0;
1344 if (overlapRow == -1)
1345 overlapRow = (*curAnchorIter)->rowFrom;
1346
1347 if (overlap > bestOverlap) {
1348
1349 /* Already have an overlap, ignore anchors in
1350 further lines. */
1351 if (overlapRow != (*curAnchorIter)->rowFrom)
1352 break;
1353
1354 bestOverlap = overlap;
1355 bestAnc = curAnchorIter;
1356 }
1357 }
1358 else {
1359 if (bestDiff == 0)
1360 break;
1361
1362 diff = Min(abs(from2-to1),
1363 abs(from1-to2));
1364 if (diff < bestDiff) {
1365 bestDiff = diff;
1366 bestAnc = curAnchorIter;
1367 }
1368 }
1369
1370 if (curAnchorIter == html.GetAnchorList().begin())
1371 break;
1372
1373 --curAnchorIter;
1374 }
1375 /* Cannot find links aligned */
1376 curAnchorIter = bestAnc;
1377
1378 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1379 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1380 FitHighlightTop(curAnchorIter);
1381 }
1382 }
1383 else {
1384 if (curRow+padRow > 0) {
1385 curRow--;
1386 if (curRow < 0) {
1387 curRow = 0;
1388 padRow--;
1389 }
1390 }
1391 else
1392 return;
1393 }
1394
1395 Highlight();
1396 scrnMan.RequestRestCursor();
1397 }
1398
ProcessKeyDown()1399 void HyperWindow::ProcessKeyDown()
1400 {
1401 if (lockKey) {
1402 iterType saveIter = curAnchorIter;
1403 if (curAnchorIter != --(html.GetAnchorList().end())) {
1404
1405 /* Skip links in current line */
1406 do {
1407 ++curAnchorIter;
1408 } while (curAnchorIter != --(html.GetAnchorList().end())
1409 && ((*curAnchorIter)->rowFrom == (*saveIter)->rowFrom));
1410
1411 // Initialize in case this is the
1412 // bottommost anchor
1413 iterType bestAnc = --(html.GetAnchorList().end());
1414 int bestDiff = INT_MAX, diff;
1415 int bestOverlap = 0, overlap, overlapRow = -1;
1416 /* Now link not in current line */
1417 for ( ; ; ) {
1418 int from1 = (*curAnchorIter)->colFrom;
1419 int to1 = (*curAnchorIter)->colTo;
1420 int wrap1 = (*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom;
1421 int from2 = (*saveIter)->colFrom;
1422 int to2 = (*saveIter)->colTo;
1423 int wrap2 = (*saveIter)->rowTo-
1424 (*saveIter)->rowFrom;
1425
1426 overlap = 0;
1427
1428 if (!wrap1 && !wrap2 &&
1429 (Max(from1, from2) <= Min(to1, to2)))
1430 overlap = Min(to1, to2)-Max(from1, from2)+1;
1431 else if (wrap1 && !wrap2 &&
1432 (from2 <= to1))
1433 overlap = to1-from2+1;
1434 else if (wrap1 && !wrap2 &&
1435 (to2 >= from1))
1436 overlap = to2-from1+1;
1437 else if (!wrap1 && wrap2 &&
1438 (from1 <= to2))
1439 overlap = to2-from1+1;
1440 else if (!wrap1 && wrap2 &&
1441 (to1 >= from2))
1442 overlap = to1-from2+1;
1443 else if (wrap1 && wrap2)
1444 overlap = Min(to1, to2)+1+
1445 (GetCol()-Max(from1, from2)+1);
1446
1447 if (overlap) {
1448 /* Found */
1449 bestDiff = 0;
1450 if (overlapRow == -1)
1451 overlapRow = (*curAnchorIter)->rowFrom;
1452
1453 if (overlap > bestOverlap) {
1454
1455 /* Already have an overlap, ignore anchors in
1456 further lines. */
1457 if (overlapRow != (*curAnchorIter)->rowFrom)
1458 break;
1459
1460 bestOverlap = overlap;
1461 bestAnc = curAnchorIter;
1462 }
1463 }
1464 else {
1465 if (bestDiff == 0)
1466 break;
1467
1468 diff = Min(abs(from2-to1),
1469 abs(from1-to2));
1470 if (diff < bestDiff) {
1471 bestDiff = diff;
1472 bestAnc = curAnchorIter;
1473 }
1474 }
1475
1476 if (curAnchorIter == --(html.GetAnchorList().end()))
1477 break;
1478
1479 ++curAnchorIter;
1480
1481 }
1482
1483 /* Cannot find links aligned */
1484 curAnchorIter = bestAnc;
1485
1486 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1487 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1488 FitHighlightBottom(curAnchorIter);
1489 }
1490 }
1491 else {
1492 if (curRow+padRow < GetDocRow()-1) {
1493 curRow++;
1494 if (curRow >= GetRow()) {
1495 curRow = GetRow()-1;
1496 padRow++;
1497 }
1498 }
1499 else
1500 return;
1501 }
1502
1503 Highlight();
1504 scrnMan.RequestRestCursor();
1505 }
1506
ProcessKeyFirstLine()1507 void HyperWindow::ProcessKeyFirstLine()
1508 {
1509 if (lockKey) {
1510 iterType saveIter = curAnchorIter;
1511 if (curAnchorIter != html.GetAnchorList().begin()) {
1512
1513 /* Skip links till the first row of screen */
1514 do {
1515 --curAnchorIter;
1516 } while (curAnchorIter != html.GetAnchorList().begin()
1517 && ((*curAnchorIter)->rowFrom == (*saveIter)->rowFrom
1518 || (*curAnchorIter)->rowFrom > padRow));
1519 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1520 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1521 FitHighlightTop(curAnchorIter);
1522 }
1523 }
1524 else {
1525 if (curRow+padRow > 0) {
1526 curRow--;
1527 if (curRow < 0) {
1528 curRow = 0;
1529 padRow--;
1530 }
1531 }
1532 else
1533 return;
1534 }
1535
1536 Highlight();
1537 scrnMan.RequestRestCursor();
1538 }
1539
ProcessKeyLastLine()1540 void HyperWindow::ProcessKeyLastLine()
1541 {
1542 if (lockKey) {
1543 iterType saveIter = curAnchorIter;
1544 if (curAnchorIter != --(html.GetAnchorList().end())) {
1545
1546 /* Skip links till the last row of screen */
1547 do {
1548 ++curAnchorIter;
1549 } while (curAnchorIter != --(html.GetAnchorList().end())
1550 && ((*curAnchorIter)->rowFrom == (*saveIter)->rowFrom
1551 || (*curAnchorIter)->rowFrom < padRow+GetRow()-1));
1552
1553 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1554 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1555 FitHighlightBottom(curAnchorIter);
1556 }
1557 }
1558 else {
1559 if (curRow+padRow < GetDocRow()-1) {
1560 curRow++;
1561 if (curRow >= GetRow()) {
1562 curRow = GetRow()-1;
1563 padRow++;
1564 }
1565 }
1566 else
1567 return;
1568 }
1569
1570 Highlight();
1571 scrnMan.RequestRestCursor();
1572 }
1573
ProcessKeyScrollUpLines(size_t lines)1574 void HyperWindow::ProcessKeyScrollUpLines(size_t lines)
1575 {
1576 if (!lines)
1577 return;
1578 if (lockKey) {
1579 iterType saveIter = curAnchorIter;
1580 if (curAnchorIter != html.GetAnchorList().begin()) {
1581 do {
1582 --curAnchorIter;
1583
1584 if ((*curAnchorIter)->rowFrom <= (*saveIter)->rowFrom-static_cast<int>(lines)) {
1585 padRow -= lines;
1586 if (padRow < 0)
1587 padRow = 0;
1588 break;
1589 }
1590 } while(curAnchorIter != html.GetAnchorList().begin());
1591
1592 if (curAnchorIter == html.GetAnchorList().begin())
1593 padRow = 0;
1594
1595 curRow = (*curAnchorIter)->rowFrom-padRow;
1596 curColumn = (*curAnchorIter)->colFrom-padColumn;
1597
1598 if (curRow < 0) {
1599 /* Scroll up */
1600 padRow += curRow;
1601 curRow = 0;
1602 }
1603 if (curRow+(*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom > GetRow()-1) {
1604 /* Scroll down */
1605 padRow += curRow+(*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom-
1606 (GetRow()-1);
1607 curRow = GetRow()-1-((*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom);
1608 }
1609 if (curColumn < 0) {
1610 /* Scroll left */
1611 padColumn += curColumn;
1612 curColumn = 0;
1613 }
1614 if (curColumn+(*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
1615 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
1616 // Highlight bar too long - show only
1617 // left portion and discard parts
1618 // that go beyond the screen width
1619
1620 // Scroll left
1621 padColumn += curColumn;
1622 curColumn = 0;
1623 }
1624 else { // Can fit highlight on the screen
1625 /* Scroll right */
1626 padColumn += curColumn+(*curAnchorIter)->colTo
1627 -(*curAnchorIter)->colFrom-(GetCol()-1);
1628 curColumn = GetCol()-1-((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom);
1629 }
1630 }
1631 }
1632 }
1633 else {
1634 if (curRow+padRow > 0) {
1635 padRow -= lines;
1636 if (padRow < 0) {
1637 padRow = 0;
1638 curRow = 0;
1639 }
1640 }
1641 else
1642 return;
1643 }
1644
1645 Highlight();
1646 scrnMan.RequestRestCursor();
1647 }
1648
ProcessKeyScrollDownLines(size_t lines)1649 void HyperWindow::ProcessKeyScrollDownLines(size_t lines)
1650 {
1651 if (!lines)
1652 return;
1653 if (lockKey) {
1654 iterType saveIter = curAnchorIter;
1655 if (curAnchorIter != --(html.GetAnchorList().end())) {
1656 do {
1657 ++curAnchorIter;
1658
1659 if ((*curAnchorIter)->rowFrom >= (*saveIter)->rowFrom+static_cast<int>(lines)) {
1660 padRow += lines;
1661 if (padRow+GetRow() > GetDocRow())
1662 padRow = GetDocRow()-GetRow();
1663 break;
1664 }
1665 } while(curAnchorIter != --(html.GetAnchorList().end()));
1666
1667 if (curAnchorIter == --(html.GetAnchorList().end()))
1668 padRow = GetDocRow()-GetRow();
1669
1670 curRow = (*curAnchorIter)->rowFrom-padRow;
1671 curColumn = (*curAnchorIter)->colFrom-padColumn;
1672
1673 if (curRow+(*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom > GetRow()-1) {
1674 /* Scroll down */
1675 padRow += curRow+(*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom-
1676 (GetRow()-1);
1677 curRow = GetRow()-1-((*curAnchorIter)->rowTo-(*curAnchorIter)->rowFrom);
1678 }
1679 if (curRow < 0) {
1680 /* Scroll up */
1681 padRow += curRow;
1682 curRow = 0;
1683 }
1684 if (padRow+GetRow() > GetDocRow()) {
1685 /* Scroll down */
1686 padRow = GetDocRow()-GetRow();
1687 curRow = (*curAnchorIter)->rowFrom-padRow;
1688 }
1689 if (curColumn < 0) {
1690 /* Scroll left */
1691 padColumn += curColumn;
1692 curColumn = 0;
1693 }
1694 if (curColumn+(*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
1695 if ((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom > GetCol()-1) {
1696 // Highlight bar too long - show only
1697 // left portion and discard parts
1698 // that go beyond the screen width
1699
1700 // Scroll left
1701 padColumn += curColumn;
1702 curColumn = 0;
1703 }
1704 else { // Can fit highlight on the screen
1705 /* Scroll right */
1706 padColumn += curColumn+(*curAnchorIter)->colTo
1707 -(*curAnchorIter)->colFrom-(GetCol()-1);
1708 curColumn = GetCol()-1-((*curAnchorIter)->colTo-(*curAnchorIter)->colFrom);
1709 }
1710 }
1711 }
1712 }
1713 else {
1714 if (curRow+padRow < GetDocRow()-1) {
1715 padRow += lines;
1716 if (padRow+GetRow() > GetDocRow()) {
1717 curRow += padRow+GetRow()-GetDocRow();
1718 padRow = GetDocRow()-GetRow();
1719 }
1720 curRow = Min(curRow, GetRow()-1);
1721 }
1722 else
1723 return;
1724 }
1725
1726 Highlight();
1727 scrnMan.RequestRestCursor();
1728 }
1729
ProcessKeyFirstPage()1730 void HyperWindow::ProcessKeyFirstPage()
1731 {
1732 if (lockKey) {
1733 if (curAnchorIter != html.GetAnchorList().begin()) {
1734 curAnchorIter = html.GetAnchorList().begin();
1735
1736 padRow = 0;
1737 padColumn = 0;
1738 curRow = (*curAnchorIter)->rowFrom-padRow;
1739 curColumn = (*curAnchorIter)->colFrom-padColumn;
1740 FitHighlightTop(curAnchorIter);
1741 }
1742 }
1743 else {
1744 padRow = 0;
1745 padColumn = 0;
1746 curRow = 0;
1747 curColumn = 0;
1748 }
1749
1750 Highlight();
1751 scrnMan.RequestRestCursor();
1752 }
1753
ProcessKeyLastPage()1754 void HyperWindow::ProcessKeyLastPage()
1755 {
1756 if (lockKey) {
1757 if (curAnchorIter != --(html.GetAnchorList().end())) {
1758 curAnchorIter = html.GetAnchorList().end();
1759 --curAnchorIter;
1760
1761 padRow = GetDocRow()-GetRow();
1762 padColumn = 0;
1763 curRow = (*curAnchorIter)->rowFrom-padRow;
1764 curColumn = (*curAnchorIter)->colFrom-padColumn;
1765 FitHighlightTop(curAnchorIter);
1766 }
1767 }
1768 else {
1769 padRow = GetDocRow()-GetRow();
1770 padColumn = 0;
1771 curRow = GetRow()-1;
1772 curColumn = 0;
1773 }
1774
1775 Highlight();
1776 scrnMan.RequestRestCursor();
1777 }
1778
ProcessKeyPrev()1779 void HyperWindow::ProcessKeyPrev()
1780 {
1781 if (lockKey) {
1782 iterType saveIter = curAnchorIter;
1783 if (curAnchorIter != html.GetAnchorList().begin()) {
1784 --curAnchorIter;
1785 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1786 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1787 FitHighlightTop(curAnchorIter);
1788 }
1789 }
1790 else {
1791 if (curColumn+padColumn > 0) {
1792 curColumn--;
1793 if (curColumn < 0) {
1794 curColumn = 0;
1795 padColumn--;
1796 }
1797 }
1798 else /* Already reach left limit */
1799 return;
1800 }
1801
1802 Highlight();
1803 scrnMan.RequestRestCursor();
1804 }
1805
ProcessKeyNext()1806 void HyperWindow::ProcessKeyNext()
1807 {
1808 if (lockKey) {
1809 iterType saveIter = curAnchorIter;
1810 ++curAnchorIter;
1811 if (curAnchorIter != html.GetAnchorList().end()) {
1812 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1813 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1814 FitHighlightBottom(curAnchorIter);
1815 }
1816 else /* Do not update curAnchorIter */
1817 curAnchorIter = saveIter;
1818 }
1819 else {
1820 if (curColumn+padColumn < GetDocColumn()-1) {
1821 curColumn++;
1822 if (curColumn >= GetCol()) {
1823 curColumn = GetCol()-1;
1824 padColumn++;
1825 }
1826 }
1827 else /* Already reach right limit */
1828 return;
1829 }
1830
1831 Highlight();
1832 scrnMan.RequestRestCursor();
1833 }
1834
ProcessKeyBeginLine()1835 void HyperWindow::ProcessKeyBeginLine()
1836 {
1837 if (lockKey) {
1838 iterType saveIter = curAnchorIter;
1839 while (curAnchorIter != html.GetAnchorList().begin()
1840 && (*curAnchorIter)->rowFrom == (*saveIter)->rowFrom)
1841 --curAnchorIter;
1842
1843 if ((*curAnchorIter)->rowFrom != (*saveIter)->rowFrom)
1844 ++curAnchorIter;
1845
1846 if (curAnchorIter != saveIter) {
1847 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1848 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1849 FitHighlightTop(curAnchorIter);
1850 }
1851 }
1852 else {
1853 if (curColumn+padColumn > 0) {
1854 curColumn = 0;
1855 padColumn = 0;
1856 }
1857 else /* Already reach left limit */
1858 return;
1859 }
1860
1861 Highlight();
1862 scrnMan.RequestRestCursor();
1863 }
1864
ProcessKeyEndLine()1865 void HyperWindow::ProcessKeyEndLine()
1866 {
1867 if (lockKey) {
1868 iterType saveIter = curAnchorIter;
1869 while (curAnchorIter != html.GetAnchorList().end()
1870 && (*curAnchorIter)->rowFrom == (*saveIter)->rowFrom)
1871 ++curAnchorIter;
1872
1873 // Rewind always required
1874 // because html.GetAnchorList().end()
1875 // is not valid
1876 --curAnchorIter;
1877
1878 if (curAnchorIter != saveIter) {
1879 curRow -= (*saveIter)->rowFrom - (*curAnchorIter)->rowFrom;
1880 curColumn -= (*saveIter)->colFrom - (*curAnchorIter)->colFrom;
1881 FitHighlightBottom(curAnchorIter);
1882 }
1883 }
1884 else {
1885 int diff = GetDocColumn()-1-curColumn-padColumn;
1886 if (diff > 0) {
1887 curColumn += diff;
1888 if (curColumn >= GetCol()) {
1889 curColumn = GetCol()-1;
1890 padColumn += diff;
1891 }
1892 }
1893 else /* Already reach right limit */
1894 return;
1895 }
1896
1897 Highlight();
1898 scrnMan.RequestRestCursor();
1899 }
1900
1901
ProcessKey(int ch)1902 void HyperWindow::ProcessKey(int ch)
1903 {
1904 // Key shared for all key binding
1905
1906 if (ch == ' ' || ch == '\r' || ch == '\n')
1907 ProcessKeySelect();
1908 else if (ch == KEY_B2) // Center of keypad
1909 ProcessKeyCenter();
1910 else if (ch == KEY_F(9))
1911 ProcessKeyNextStatus();
1912 else if (ch == KEY_F(10) || ch == 'C'-'A'+1)
1913 ProcessKeyExit();
1914 // comma when shifted is `<'
1915 else if (ch == ',' || ch == KEY_SLEFT)
1916 ProcessKeyPanLeft();
1917 // stop when shifted is `>'
1918 else if (ch == '.' || ch == KEY_SRIGHT)
1919 ProcessKeyPanRight();
1920 else if (ch == KEY_UP || ch == KEY_SR)
1921 ProcessKeyUp();
1922 else if (ch == KEY_DOWN || ch == KEY_SF)
1923 ProcessKeyDown();
1924 else if (ch == KEY_SR)
1925 ProcessKeyFirstLine();
1926 else if (ch == KEY_SF)
1927 ProcessKeyLastLine();
1928 else if (ch == KEY_PPAGE)
1929 ProcessKeyPrevPage();
1930 else if (ch == KEY_NPAGE)
1931 ProcessKeyNextPage();
1932 else if (ch == KEY_HOME)
1933 ProcessKeyFirstPage();
1934 else if (ch == KEY_END)
1935 ProcessKeyLastPage();
1936 else if (ch == KEY_LEFT)
1937 ProcessKeyPrev();
1938 else if (ch == KEY_RIGHT)
1939 ProcessKeyNext();
1940
1941 else if (kcdConfig.cfgKey == keyBindingVi) {
1942 bool processG = false;
1943 bool processZ = false;
1944 bool processCount = false;
1945
1946 if (ch >= '1' && ch <= '9') {
1947 if (viFoundCount)
1948 viCount = viCount*10 + ch-'0';
1949 else {
1950 viFoundCount = true;
1951 viCount = ch-'0';
1952 }
1953 processCount = true;
1954 }
1955 else if (ch == '0' && viFoundCount) {
1956 viCount = viCount*10;
1957 processCount = true;
1958 }
1959 else if (ch == 'q' || ch == 'Q') // q, ZQ
1960 ProcessKeyExit();
1961 else if (ch == 'h' || ch == 'b' || ch == 'B') {
1962 for (size_t i = 0; i < viCount; ++i)
1963 ProcessKeyPrev();
1964 }
1965 else if (ch == 'l' || ch == 'w' || ch == 'W') {
1966 for (size_t i = 0; i < viCount; ++i)
1967 ProcessKeyNext();
1968 }
1969 else if (ch == '0' || ch == '^')
1970 ProcessKeyBeginLine();
1971 else if (ch == '$')
1972 ProcessKeyEndLine();
1973 else if (ch == 'k' || ch == '-') {
1974 for (size_t i = 0; i < viCount; ++i)
1975 ProcessKeyUp();
1976 }
1977 else if (ch == 'j' || ch == '+' || ch == '_') {
1978 for (size_t i = 0; i < viCount; ++i)
1979 ProcessKeyDown();
1980 }
1981 else if (ch == 'B'-'A'+1) { // ^B
1982 for (size_t i = 0; i < viCount; ++i)
1983 ProcessKeyPrevPage();
1984 }
1985 else if (ch == 'F'-'A'+1) { // ^F
1986 for (size_t i = 0; i < viCount; ++i)
1987 ProcessKeyNextPage();
1988 }
1989 else if (ch == 'U'-'A'+1) { // ^U
1990 if (viFoundCount)
1991 ProcessKeyScrollUpLines(viCount);
1992 else
1993 ProcessKeyScrollUpLines(GetRow()/2-1);
1994 }
1995 else if (ch == 'D'-'A'+1) { // ^D
1996 if (viFoundCount)
1997 ProcessKeyScrollDownLines(viCount);
1998 else
1999 ProcessKeyScrollDownLines(GetRow()/2-1);
2000 }
2001 else if (ch == 'E'-'A'+1) { // ^E
2002 if (viCount) {
2003 if (viCount > static_cast<size_t>(curRow)) {
2004 ProcessKeyScrollDownLines(viCount-curRow);
2005 viCount = curRow;
2006 }
2007
2008 curRow -= viCount;
2009 padRow += viCount;
2010 Highlight();
2011 scrnMan.RequestRestCursor();
2012 }
2013 }
2014 else if (ch == 'Y'-'A'+1) { // ^Y
2015 if (viCount) {
2016 if (viCount > static_cast<size_t>(GetRow()-1-curRow)) {
2017 ProcessKeyScrollUpLines(viCount-(GetRow()-1-curRow));
2018 viCount = GetRow()-1-curRow;
2019 }
2020
2021 curRow += viCount;
2022 padRow -= viCount;
2023 Highlight();
2024 scrnMan.RequestRestCursor();
2025 }
2026 }
2027 else if (ch == 'g') {
2028 processG = true;
2029 if (viFoundG) // gg
2030 ProcessKeyFirstPage();
2031 else
2032 viFoundG = true;
2033 }
2034 else if (ch == 'G')
2035 ProcessKeyLastPage();
2036 else if (ch == 'Z') {
2037 processZ = true;
2038 if (viFoundZ)
2039 ProcessKeyExit();
2040 else
2041 viFoundZ = true;
2042 }
2043
2044 // FIXME: Maybe add zh, zl, zH, zL
2045
2046 if (!processG) // Ignore the `g' in `gX'
2047 // key sequence where X is
2048 // not `g'
2049 viFoundG = false;
2050 if (!processZ)
2051 viFoundZ = false;
2052 if (!processCount) {
2053 viFoundCount = false;
2054 viCount = 1;
2055 }
2056 }
2057 else if (kcdConfig.cfgKey == keyBindingEmacs) {
2058 bool processAlt = false;
2059
2060 if (ch == 27) { // Esc, M-
2061 emacsFoundAlt = !emacsFoundAlt;
2062 processAlt = true;
2063 }
2064 else if (ch == 'A'-'A'+1) // C-a
2065 ProcessKeyBeginLine();
2066 else if (ch == 'E'-'A'+1) // C-e
2067 ProcessKeyEndLine();
2068 else if (ch == 'B'-'A'+1 || (ch == 'b' && emacsFoundAlt)) // C-b, M-b
2069 ProcessKeyPrev();
2070 else if (ch == 'F'-'A'+1 || (ch == 'f' && emacsFoundAlt)) // C-f, M-f
2071 ProcessKeyNext();
2072 else if (ch == 'P'-'A'+1) // C-p
2073 ProcessKeyUp();
2074 else if (ch == 'N'-'A'+1) // C-n
2075 ProcessKeyDown();
2076 else if (ch == 'v' && emacsFoundAlt) // M-v
2077 ProcessKeyPrevPage();
2078 else if (ch == 'V'-'A'+1) // C-v
2079 ProcessKeyNextPage();
2080 // FIXME: Emulate ^X^S, ^X^C
2081
2082 if (!processAlt)
2083 emacsFoundAlt = false;
2084 }
2085 }
2086
KeyboardLoop()2087 void HyperWindow::KeyboardLoop()
2088 {
2089 NCWindowBase::KeyboardLoop();
2090
2091 // Exit keyboard loop
2092
2093 if (win) { // Delete windows
2094 delwin(win);
2095 win = NULL;
2096 }
2097 if (blankWin) {
2098 delwin(blankWin);
2099 blankWin = NULL;
2100 }
2101
2102 // Exit program, don't have
2103 // to delete other windows
2104
2105 clear(); // Clear screen
2106 refresh();
2107 cursor.Restore();
2108
2109 NCurses::End();
2110
2111 startSection = ""; // No longer used
2112
2113 if (anchorSelected) {
2114 if (anchorSelected->type == TYPE_EXEC) {
2115 k_system(anchorSelected->name);
2116 return;
2117 }
2118 }
2119 }
2120
DoRestCursor()2121 void HyperWindow::DoRestCursor()
2122 {
2123 if (win == NULL)
2124 return;
2125
2126 // blankWin must be refreshed first
2127 // to avoid interfering the cursor
2128 // position
2129 if (blankWin)
2130 wnoutrefresh(blankWin);
2131
2132 if (lockKey)
2133 wmove(win, padRow+GetRow()-1, padColumn+GetCol()-1);
2134 else
2135 wmove(win, padRow+curRow, padColumn+curColumn);
2136
2137 // win's cursor position will be
2138 // used by doupdate().
2139 if (numRealColumn < GetCol())
2140 pnoutrefresh(win, padRow, padColumn, GetY1(), GetX1(),
2141 GetY2(), GetX1()+numRealColumn-1);
2142 else
2143 pnoutrefresh(win, padRow, padColumn, GetY1(), GetX1(),
2144 GetY2(), GetX2());
2145 }
2146
CursorMode()2147 int khHyperWindowWithFind::CursorMode()
2148 {
2149 if (lockKey)
2150 return 1;
2151 else
2152 return 0;
2153 }
2154
FindText(const string & text,bool find_backward)2155 void khHyperWindowWithFind::FindText(const string &text, bool find_backward)
2156 {
2157 if (text.size() == 0)
2158 return;
2159
2160 iterType newAnchorIter = curAnchorIter;
2161
2162 #ifdef CLIB_HAVE_REGEX
2163 string str = MakeString(text);
2164 regex_t *reg = MakePathRegex(text);
2165 #endif
2166
2167 do {
2168 if (MatchSubString(newAnchorIter, text)
2169 #ifdef CLIB_HAVE_REGEX
2170 || (MatchStr(str, (*newAnchorIter)->name)
2171 && MatchPathRegex(reg, (*newAnchorIter)->name))
2172 #endif
2173 ) {
2174 CenterRowPadIfScroll(newAnchorIter);
2175 FitHighlightMiddle(newAnchorIter);
2176 curAnchorIter = newAnchorIter;
2177 break;
2178 }
2179 if (find_backward)
2180 prev_loop(html.GetAnchorList(), newAnchorIter);
2181 else
2182 next_loop(html.GetAnchorList(), newAnchorIter);
2183
2184 } while (newAnchorIter != curAnchorIter); /* Loop not repeated */
2185
2186 Highlight();
2187 scrnMan.RequestRestCursor();
2188
2189 #ifdef CLIB_HAVE_REGEX
2190 if (reg)
2191 regfree(reg);
2192 #endif
2193 }
2194
FindPrev(const string & text)2195 void khHyperWindowWithFind::FindPrev(const string &text)
2196 {
2197 iterType newAnchorIter = curAnchorIter;
2198
2199 prev_loop(html.GetAnchorList(), newAnchorIter);
2200
2201 #ifdef CLIB_HAVE_REGEX
2202 string str = MakeString(text);
2203 regex_t *reg = MakePathRegex(text);
2204 #endif
2205
2206 do {
2207 if (MatchSubString(newAnchorIter, text)
2208 #ifdef CLIB_HAVE_REGEX
2209 || (MatchStr(str, (*newAnchorIter)->name)
2210 && MatchPathRegex(reg, (*newAnchorIter)->name))
2211 #endif
2212 ) {
2213 CenterRowPadIfScroll(newAnchorIter);
2214 FitHighlightMiddle(newAnchorIter);
2215 curAnchorIter = newAnchorIter;
2216 break;
2217 }
2218 prev_loop(html.GetAnchorList(), newAnchorIter);
2219
2220 } while (newAnchorIter != curAnchorIter); /* Loop not repeated */
2221
2222 Highlight();
2223 scrnMan.RequestRestCursor();
2224
2225 #ifdef CLIB_HAVE_REGEX
2226 if (reg)
2227 regfree(reg);
2228 #endif
2229 }
2230
FindNext(const string & text)2231 void khHyperWindowWithFind::FindNext(const string &text)
2232 {
2233 iterType newAnchorIter = curAnchorIter;
2234
2235 next_loop(html.GetAnchorList(), newAnchorIter);
2236
2237 #ifdef CLIB_HAVE_REGEX
2238 string str = MakeString(text);
2239 regex_t *reg = MakePathRegex(text);
2240 #endif
2241
2242 do {
2243 if (MatchSubString(newAnchorIter, text)
2244 #ifdef CLIB_HAVE_REGEX
2245 || (MatchStr(str, (*newAnchorIter)->name)
2246 && MatchPathRegex(reg, (*newAnchorIter)->name))
2247 #endif
2248 ) {
2249 CenterRowPadIfScroll(newAnchorIter);
2250 FitHighlightMiddle(newAnchorIter);
2251 curAnchorIter = newAnchorIter;
2252 break;
2253 }
2254 next_loop(html.GetAnchorList(), newAnchorIter);
2255
2256 } while (newAnchorIter != curAnchorIter); /* Loop not repeated */
2257
2258 Highlight();
2259 scrnMan.RequestRestCursor();
2260
2261 #ifdef CLIB_HAVE_REGEX
2262 if (reg)
2263 regfree(reg);
2264 #endif
2265 }
2266
SelectText(const string &)2267 void khHyperWindowWithFind::SelectText(const string & /*text*/)
2268 {
2269 HyperWindow::ProcessKey('\n');
2270 }
2271
FindProcessKey(int ch)2272 void khHyperWindowWithFind::FindProcessKey(int ch)
2273 {
2274 if (ch == KEY_F(10) || ch == KEY_F(9) || ch == 'C'-'A'+1)
2275 HyperWindow::ProcessKey(ch);
2276 }
2277
ProcessKey(int ch)2278 void khHyperWindowWithFind::ProcessKey(int ch)
2279 {
2280 bool start_find = false;
2281 // Non-special keys
2282
2283 if (kcdConfig.cfgKey == keyBindingDefault) {
2284 #ifdef USE_UTF8_MODE
2285 if (IsUTF8Mode()) {
2286 if ((ch <= 0x7F && isalnum(ch)) || (ch > 0x7F && ch <= 0xFF))
2287 start_find = true;
2288 }
2289 else {
2290 if (ch <= 0xFF && isalnum(ch))
2291 start_find = true;
2292 }
2293 #else
2294 if (ch <= 0xFF && isalnum(ch))
2295 start_find = true;
2296 #endif
2297
2298 if (start_find) {
2299 // Start find
2300
2301 // Pass control of keyboard & cursor to
2302 // status
2303 scrnMan.SetFocus(&status);
2304 scrnMan.SetCursor(&status);
2305
2306 status.ProcessKey(ch);
2307 }
2308 else
2309 HyperWindow::ProcessKey(ch);
2310 }
2311 else if (kcdConfig.cfgKey == keyBindingVi) {
2312
2313 // FIXME: Add *, #
2314
2315 if (ch == '/' || ch == '?') {
2316 // Pass control of keyboard & cursor to
2317 // status
2318 scrnMan.SetFocus(&status);
2319 scrnMan.SetCursor(&status);
2320
2321 status.SetCount(viCount);
2322 status.ProcessKey(ch);
2323
2324 viFoundG = false;
2325 viFoundZ = false;
2326 viFoundCount = false;
2327 viCount = 1;
2328 }
2329 else
2330 HyperWindow::ProcessKey(ch);
2331 }
2332 else if (kcdConfig.cfgKey == keyBindingEmacs) {
2333 if (ch == 'S'-'A'+1 || ch == 'R'-'A'+1) { // C-s, C-r
2334 // Pass control of keyboard & cursor to
2335 // status
2336 scrnMan.SetFocus(&status);
2337 scrnMan.SetCursor(&status);
2338 status.ProcessKey(ch);
2339
2340 emacsFoundAlt = false;
2341 }
2342 #ifdef USE_UTF8_MODE
2343 else if (IsUTF8Mode()) {
2344 if ((ch <= 0x7F && isalnum(ch)) || (ch > 0x7F && ch <= 0xFF))
2345 start_find = true;
2346 }
2347 else {
2348 if (ch <= 0xFF && isalnum(ch))
2349 start_find = true;
2350 }
2351 #else
2352 else if (ch <= 0xFF && isalnum(ch))
2353 start_find = true;
2354 #endif
2355
2356 if (start_find) {
2357 // Pass control of keyboard & cursor to
2358 // status
2359 scrnMan.SetFocus(&status);
2360 scrnMan.SetCursor(&status);
2361 status.ProcessKey('S'-'A'+1); // Assume C-s
2362 status.ProcessKey(ch);
2363
2364 emacsFoundAlt = false;
2365
2366 emacsFoundAlt = false;
2367 }
2368 else
2369 HyperWindow::ProcessKey(ch);
2370 }
2371 }
2372
ProcessCall(Anchor * p)2373 Anchor khHyperWindowWithFind::ProcessCall(Anchor *p)
2374 {
2375 extern string dirFile;
2376
2377 FILE *file;
2378
2379 file = k_fopen(dirFile, "wb");
2380 if (file == NULL) { // Cannot create or truncate
2381 // ~/.kcd.newdir
2382 throw ErrorGenericFile(_("cannot create file %$"), dirFile);
2383 }
2384
2385 // Output desired dir
2386 k_fputs(p->name, file);
2387 fclose(file);
2388
2389 return Anchor("", 0, TYPE_EXIT); // Exit immediately
2390 }
2391
khHyperWindowWithFind(NCScreenManager & scrn_,int id_,HyperDocument & html_,StatusWindowBase & status_,StatusWindowBase & url_,ScrollBarBase & hscroll_,ScrollBarBase & vscroll_,const string & startSection_,int lockKey_,int row,int col)2392 khHyperWindowWithFind::khHyperWindowWithFind(NCScreenManager &scrn_, int id_,
2393 HyperDocument &html_,
2394 StatusWindowBase &status_,
2395 StatusWindowBase &url_,
2396 ScrollBarBase &hscroll_,
2397 ScrollBarBase &vscroll_,
2398 const string &startSection_,
2399 int lockKey_, int row, int col)
2400 : HyperWindow(scrn_, id_, html_,
2401 status_, url_, hscroll_,
2402 vscroll_, startSection_,
2403 lockKey_, row, col)
2404 {
2405 }
2406
~khHyperWindowWithFind()2407 khHyperWindowWithFind::~khHyperWindowWithFind()
2408 {
2409 }
2410