diff --git a/ChangeLog b/ChangeLog index d44c2c9b..2e4687cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -2016-10-02 Markus Gans +2016-10-08 Markus Gans + * Add the possibility to scroll text up and down + in a virtual window + +2016-10-06 Markus Gans * The input cursor is now controlled by the virtual terminal 2016-10-02 Markus Gans diff --git a/src/fdialog.cpp b/src/fdialog.cpp index cd189a0b..9479b911 100644 --- a/src/fdialog.cpp +++ b/src/fdialog.cpp @@ -567,7 +567,7 @@ void FDialog::draw() if ( isMonochron() ) setReverse(true); - clearArea(); + clearArea (vwin); drawBorder(); drawTitleBar(); setCursorPos(2, getHeight() - 1); diff --git a/src/fmenu.cpp b/src/fmenu.cpp index 49a1e40e..067c39d3 100644 --- a/src/fmenu.cpp +++ b/src/fmenu.cpp @@ -591,7 +591,7 @@ void FMenu::draw() if ( isMonochron() ) setReverse(true); - clearArea(); + clearArea (vwin); drawBorder(); drawItems(); drawShadow(); diff --git a/src/ftcap_map.h b/src/ftcap_map.h index ca82066b..c325b2a9 100644 --- a/src/ftcap_map.h +++ b/src/ftcap_map.h @@ -60,6 +60,8 @@ static tcap_map tcap[] = { 0, "RI" }, // parm_right_cursor -> move #1 characters to the right (P*) { 0, "sc" }, // save_cursor -> save current cursor position (P) { 0, "rc" }, // restore_cursor -> restore cursor to save_cursor + { 0, "sf" }, // scroll_forward -> scroll text up (P) + { 0, "sr" }, // scroll_reverse -> scroll text down (P) { 0, "ti" }, // enter_ca_mode -> string to start programs using cup { 0, "te" }, // exit_ca_mode -> strings to end programs using cup { 0, "eA" }, // enable_acs -> enable alternate char set @@ -151,6 +153,8 @@ enum termcaps t_parm_right_cursor, t_save_cursor, t_restore_cursor, + t_scroll_forward, + t_scroll_reverse, t_enter_ca_mode, t_exit_ca_mode, t_enable_acs, diff --git a/src/fterm.cpp b/src/fterm.cpp index 51582b56..1943e8f5 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -1752,6 +1752,7 @@ void FTerm::init() // create virtual desktop area createArea (vdesktop); vdesktop->visible = true; + active_area = vdesktop; // make stdin non-blocking setNonBlockingInput(); @@ -2683,8 +2684,8 @@ bool FTerm::updateVTermCursor (FTerm::term_area* area) ax = area->widget->getTermX() - 1; ay = area->widget->getTermY() - 1; // area position - x = ax + cx - 1; - y = ay + cy - 1; + x = ax + cx; + y = ay + cy; if ( isInsideArea(cx, cy, area) && isInsideTerminal(x+1, y+1) @@ -2724,8 +2725,8 @@ void FTerm::setAreaCursor (int x, int y, bool visible, FTerm::term_area* area) if ( ! area ) return; - area->input_cursor_x = x; - area->input_cursor_y = y; + area->input_cursor_x = x - 1; + area->input_cursor_y = y - 1; area->input_cursor_visible = visible; updateVTerm (area); } @@ -2939,42 +2940,97 @@ void FTerm::putArea (int ax, int ay, FTerm::term_area* area) } //---------------------------------------------------------------------- -void FTerm::clearArea() +void FTerm::scrollAreaForward (FTerm::term_area* area) { - term_area* area; - FWindow* window; - FWidget* widget; - FOptiAttr::char_data default_char; + int total_width; + int length; + int y_max; + FOptiAttr::char_data nc; // next character + FOptiAttr::char_data* lc; // last character + FOptiAttr::char_data* sc; // source character + FOptiAttr::char_data* dc; // destination character + + if ( ! area ) + return; + + if ( area->height <= 1 ) + return; + + length = area->width; + total_width = area->width + area->right_shadow; + y_max = area->height - 1; + + for (int y=0; y < y_max; y++) + { + int pos1 = y * total_width; + int pos2 = (y+1) * total_width; + sc = &area->text[pos2]; + dc = &area->text[pos1]; + std::memcpy (dc, sc, sizeof(FOptiAttr::char_data) * unsigned(length)); + area->changes[y].xmin = 0; + area->changes[y].xmax = uInt(area->width - 1); + } + + // insert a new line below + lc = &area->text[(y_max * total_width) - area->right_shadow - 1]; + std::memcpy (&nc, lc, sizeof(FOptiAttr::char_data)); + nc.code = ' '; + dc = &area->text[y_max * total_width]; + std::fill_n (dc, area->width, nc); + area->changes[y_max].xmin = 0; + area->changes[y_max].xmax = uInt(area->width - 1); +} + +//---------------------------------------------------------------------- +void FTerm::scrollAreaReverse (FTerm::term_area* area) +{ + int total_width; + int length; + FOptiAttr::char_data nc; // next character + FOptiAttr::char_data* lc; // last character + FOptiAttr::char_data* sc; // source character + FOptiAttr::char_data* dc; // destination character + + if ( ! area ) + return; + + if ( area->height <= 1 ) + return; + + length = area->width; + total_width = area->width + area->right_shadow; + + for (int y=area->height-1; y > 0; y--) + { + int pos1 = (y-1) * total_width; + int pos2 = y * total_width; + sc = &area->text[pos1]; + dc = &area->text[pos2]; + std::memcpy (dc, sc, sizeof(FOptiAttr::char_data) * unsigned(length)); + area->changes[y].xmin = 0; + area->changes[y].xmax = uInt(area->width - 1); + } + + // insert a new line above + lc = &area->text[total_width]; + std::memcpy (&nc, lc, sizeof(FOptiAttr::char_data)); + nc.code = ' '; + dc = &area->text[0]; + std::fill_n (dc, area->width, nc); + area->changes[0].xmin = 0; + area->changes[0].xmax = uInt(area->width - 1); +} + +//---------------------------------------------------------------------- +void FTerm::clearArea (FTerm::term_area* area) +{ + FOptiAttr::char_data nc; // next character int total_width; uInt w; - default_char.code = ' '; - default_char.fg_color = next_attribute.fg_color; - default_char.bg_color = next_attribute.bg_color; - default_char.bold = next_attribute.bold; - default_char.dim = next_attribute.dim; - default_char.italic = next_attribute.italic; - default_char.underline = next_attribute.underline; - default_char.blink = next_attribute.blink; - default_char.reverse = next_attribute.reverse; - default_char.standout = next_attribute.standout; - default_char.invisible = next_attribute.invisible; - default_char.protect = next_attribute.protect; - default_char.crossed_out = next_attribute.crossed_out; - default_char.dbl_underline = next_attribute.dbl_underline; - default_char.alt_charset = next_attribute.alt_charset; - default_char.pc_charset = next_attribute.pc_charset; - default_char.transparent = next_attribute.transparent; - default_char.trans_shadow = next_attribute.trans_shadow; - default_char.inherit_bg = next_attribute.inherit_bg; - - widget = static_cast(this); - window = FWindow::getWindowWidget(widget); - - if ( window ) - area = window->getVWin(); - else - area = vdesktop; + // clear with the current attributes and space characters + std::memcpy (&nc, &next_attribute, sizeof(FOptiAttr::char_data)); + nc.code = ' '; if ( ! area ) return; @@ -2985,17 +3041,17 @@ void FTerm::clearArea() if ( area->right_shadow == 0 ) { int area_size = area->width * area->height; - std::fill_n (area->text, area_size, default_char); + std::fill_n (area->text, area_size, nc); } else { - FOptiAttr::char_data t_char = default_char; + FOptiAttr::char_data t_char = nc; t_char.transparent = true; for (int y=0; y < area->height; y++) { int pos = y * total_width; - std::fill_n (&area->text[pos], total_width, default_char); + std::fill_n (&area->text[pos], total_width, nc); std::fill_n (&area->text[pos+area->width], area->right_shadow, t_char); } @@ -3012,9 +3068,9 @@ void FTerm::clearArea() area->changes[i].xmin = 0; area->changes[i].xmax = w - 1; - if ( default_char.transparent - || default_char.trans_shadow - || default_char.inherit_bg ) + if ( nc.transparent + || nc.trans_shadow + || nc.inherit_bg ) area->changes[i].trans_count = w; else if ( area->right_shadow != 0 ) area->changes[i].trans_count = uInt(area->right_shadow); @@ -4242,6 +4298,32 @@ bool FTerm::setNonBlockingInput (bool on) return non_blocking_stdin; } +//---------------------------------------------------------------------- +bool FTerm::scrollTermForward() +{ + if ( tcap[t_scroll_forward].string ) + { + putstring (tcap[t_scroll_forward].string); + std::fflush(stdout); + return true; + } + + return false; +} + +//---------------------------------------------------------------------- +bool FTerm::scrollTermReverse() +{ + if ( tcap[t_scroll_reverse].string ) + { + putstring (tcap[t_scroll_reverse].string); + std::fflush(stdout); + return true; + } + + return false; +} + //---------------------------------------------------------------------- bool FTerm::setUTF8 (bool on) // UTF-8 (Unicode) { diff --git a/src/fterm.h b/src/fterm.h index cd55036c..48e8933b 100644 --- a/src/fterm.h +++ b/src/fterm.h @@ -313,7 +313,9 @@ class FTerm void getArea (int, int, int, int, FTerm::term_area*); void putArea (const FPoint&, FTerm::term_area*); void putArea (int, int, FTerm::term_area*); - void clearArea(); + static void scrollAreaForward (FTerm::term_area*); + static void scrollAreaReverse (FTerm::term_area*); + void clearArea (FTerm::term_area*); FOptiAttr::char_data getCharacter (int, const FPoint&, FTerm*); FOptiAttr::char_data getCharacter (int, int, int, FTerm*); FOptiAttr::char_data getCoveredCharacter (const FPoint&, FTerm*); @@ -413,6 +415,9 @@ class FTerm static bool setNonBlockingInput(); static bool unsetNonBlockingInput(); + static bool scrollTermForward(); + static bool scrollTermReverse(); + static bool setUTF8 (bool); static bool setUTF8(); static bool unsetUTF8(); @@ -424,6 +429,7 @@ class FTerm static bool unsetRawMode(); static bool setCookedMode(); static bool isRaw(); + static FString getAnswerbackMsg(); static FString getSecDA(); diff --git a/src/ftooltip.cpp b/src/ftooltip.cpp index eac66b2d..17115099 100644 --- a/src/ftooltip.cpp +++ b/src/ftooltip.cpp @@ -130,7 +130,7 @@ void FToolTip::draw() if ( getMaxColor() < 16 ) setBold(); - clearArea(); + clearArea (vwin); drawBorder(); for (int i=0; i < int(text_num_lines); i++) diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 079e458f..661a8c75 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -143,7 +143,7 @@ void FWidget::init() foreground_color = wc.term_fg; background_color = wc.term_bg; setColor(); - clearArea(); + clearArea(vdesktop); accelerator_list = new Accelerators(); } @@ -369,29 +369,31 @@ void FWidget::setColorTheme() //---------------------------------------------------------------------- FTerm::term_area* FWidget::getPrintArea() { + // returns the print area of this object if ( print_area ) return print_area; else { - FWidget* window = FWindow::getWindowWidget(this); + FWidget* obj = static_cast(this); + FWidget* p_obj = static_cast(obj->getParent()); - if ( window ) + while ( ! obj->vwin && p_obj ) { - term_area* area = window->getVWin(); - - if ( area ) - { - print_area = area; - return area; - } - else - return 0; + obj = p_obj; + p_obj = static_cast(p_obj->getParent()); + } + + if ( obj->vwin ) + { + print_area = obj->vwin; + return print_area; } - else - return 0; } + + return vdesktop; } + // protected methods of FWidget //---------------------------------------------------------------------- void FWidget::adjustSize() @@ -1227,7 +1229,7 @@ void FWidget::redraw() terminal_updates = false; // clean desktop setColor (wc.term_fg, wc.term_bg); - clearArea(); + clearArea (vdesktop); } else if ( ! visible ) return; diff --git a/src/fwidget.h b/src/fwidget.h index 0e486cf2..64156db9 100644 --- a/src/fwidget.h +++ b/src/fwidget.h @@ -506,6 +506,7 @@ class FWidget : public FObject, public FTerm void printPos (const FPoint&); void printPos (register int, register int); + FPoint getPrintPos() const; static void setNormal(); @@ -937,6 +938,15 @@ inline void FWidget::printPos (register int x, register int y) offset.getY1() + adjust_wsize.getY() - 1 + y ); } +//---------------------------------------------------------------------- +inline FPoint FWidget::getPrintPos() const +{ + int cx = cursor->getX(); + int cy = cursor->getY(); + return FPoint ( cx - offset.getX1() - adjust_wsize.getX() + 1 + , cy - offset.getY1() - adjust_wsize.getY() + 1 ); +} + //---------------------------------------------------------------------- inline void FWidget::setNormal() { diff --git a/test/keyboard.cpp b/test/keyboard.cpp index fc5454ed..b3bf114d 100644 --- a/test/keyboard.cpp +++ b/test/keyboard.cpp @@ -34,7 +34,23 @@ keyboard::keyboard (FWidget* parent) void keyboard::onKeyPress (FKeyEvent* ev) { int key_id = ev->key(); - std::printf("Key %s (id %d)\n\r", getKeyName(key_id).c_str(), key_id); + bool is_last_line = false; + + if ( getPrintPos().getY() == getLineNumber() ) + is_last_line = true; + + printf ("Key %s (id %d)\n", getKeyName(key_id).c_str(), key_id); + + + if ( is_last_line ) + { + scrollAreaForward (vdesktop); + + if ( ! scrollTermForward() ) + putArea (getTermPos(), vdesktop); + } + + setAreaCursor (1, getPrintPos().getY(), true, vdesktop); } //---------------------------------------------------------------------- @@ -49,12 +65,12 @@ void keyboard::draw() { setNormal(); setColor(fc::Default, fc::Default); - clearArea(); + clearArea (vdesktop); printPosTerm (1,1); print ("---------------\n"); print ("Press Q to quit\n"); print ("---------------\n"); - setCursorPos (1,5); + setAreaCursor (1, 4, true, vdesktop); } //---------------------------------------------------------------------- diff --git a/test/timer.cpp b/test/timer.cpp index 5d3cc5e7..be7559ce 100644 --- a/test/timer.cpp +++ b/test/timer.cpp @@ -39,7 +39,24 @@ timer::timer (FWidget* parent) //---------------------------------------------------------------------- void timer::onTimer (FTimerEvent* ev) { - std::printf("timer event, id %d\n\r", ev->timerId() ); + bool is_last_line = false; + int timer_id = ev->timerId(); + + if ( getPrintPos().getY() == getLineNumber() ) + is_last_line = true; + + setColor (short(1 + timer_id), fc::Default); + printf ("timer event, id %d\n", timer_id ); + + if ( is_last_line ) + { + scrollAreaForward (vdesktop); + + if ( ! scrollTermForward() ) + putArea (getTermPos(), vdesktop); + } + + setAreaCursor (1, getPrintPos().getY(), true, vdesktop); } //---------------------------------------------------------------------- @@ -54,12 +71,12 @@ void timer::draw() { setNormal(); setColor (fc::Default, fc::Default); - clearArea(); + clearArea (vdesktop); printPosTerm (1,1); print ("---------------\n"); print ("Press Q to quit\n"); print ("---------------\n"); - setCursorPos (1,4); + setAreaCursor (1, 4, true, vdesktop); }