From 56df867ef7c23f59a9ab403cd845425d7e5320fa Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Wed, 8 Mar 2017 23:48:30 +0100 Subject: [PATCH] Improve input cursor positioning in FScrollView --- ChangeLog | 3 +++ README.md | 2 +- doc/100prozent.txt | 23 ------------------- src/fapp.h | 2 +- src/fobject.cpp | 14 ++++++++++++ src/fobject.h | 6 +++++ src/foptimove.cpp | 4 ++-- src/fscrollview.cpp | 54 ++++++++++++++++++++++++++++++++++++++++----- src/fscrollview.h | 6 ++++- src/fstring.cpp | 4 ++-- src/fterm.cpp | 12 +++++----- src/fterm.h | 2 +- src/fvterm.cpp | 18 ++++++++++++++- src/fvterm.h | 3 ++- src/fwidget.cpp | 21 +++++++++++++----- src/fwidget.h | 2 +- src/fwindow.h | 2 +- test/scrollview.cpp | 30 ++++++++++++++++--------- 18 files changed, 145 insertions(+), 63 deletions(-) delete mode 100644 doc/100prozent.txt diff --git a/ChangeLog b/ChangeLog index e675df30..a77810aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-03-08 Markus Gans + * Improve input cursor positioning in FScrollView + 2017-02-24 Markus Gans * Corrected swapped top and left offset variables in the class FVTerm diff --git a/README.md b/README.md index 9e2c5099..bd5b1d6c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The Final Cut ============= -The Final Cut is a class library and widget toolkit with full mouse support for creating a text-based user interface. The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple windows on the screen. +The Final Cut is a class library and widget toolkit with full mouse support for creating a [text-based user interface](https://en.wikipedia.org/wiki/Text-based_user_interface). The library supports the programmer to develop an application for the text console. It allows the simultaneous handling of multiple windows on the screen. The C++ class design was inspired by the Qt framework. It provides common controls like dialog windows, push buttons, check boxes, radio buttons, input lines, list boxes, status bars and so on. ![](doc/fileopen-dialog.png) diff --git a/doc/100prozent.txt b/doc/100prozent.txt deleted file mode 100644 index 8c92c0f9..00000000 --- a/doc/100prozent.txt +++ /dev/null @@ -1,23 +0,0 @@ -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -select(1, [0], NULL, NULL, {0, 100000}) = 1 (in [0], left {0, 99999}) -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_NONBLOCK|O_LARGEFILE) = 0 -read(0, "", 1023) = 0 -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -select(1, [0], NULL, NULL, {0, 100000}) = 1 (in [0], left {0, 99998}) -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_NONBLOCK|O_LARGEFILE) = 0 -read(0, "", 1023) = 0 -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -select(1, [0], NULL, NULL, {0, 100000}) = 1 (in [0], left {0, 99999}) -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_NONBLOCK|O_LARGEFILE) = 0 -read(0, "", 1023) = 0 -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -select(1, [0], NULL, NULL, {0, 100000}) = 1 (in [0], left {0, 99999}) -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_NONBLOCK|O_LARGEFILE) = 0 -read(0, "", 1023) = 0 -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -select(1, [0], NULL, NULL, {0, 100000}) = 1 (in [0], left {0, 99999}) -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_NONBLOCK|O_LARGEFILE) = 0 -read(0, "", 1023) = 0 -fcntl(0, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE) = 0 -^CProcess 7036 detached - diff --git a/src/fapp.h b/src/fapp.h index 3d743fbc..bf7b19b2 100644 --- a/src/fapp.h +++ b/src/fapp.h @@ -21,7 +21,7 @@ // ▕▁▁▁▁▁▁▁▁▁▏ // ▲ // │ -// ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ 1 *▕▔▔▔▔▔▔▔▔▏ +// ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▏ // ▕ FApplication ▏-┬- - - -▕ FEvent ▏ // ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▏ // : diff --git a/src/fobject.cpp b/src/fobject.cpp index 5d21e64a..9a0026e1 100644 --- a/src/fobject.cpp +++ b/src/fobject.cpp @@ -67,6 +67,20 @@ FObject::~FObject() // destructor } // public methods of FObject +//---------------------------------------------------------------------- +bool FObject::isChild (FObject* obj) const +{ + while ( FObject* p_obj = obj->getParent() ) + { + obj = p_obj; + + if ( obj == this ) + return true; + } + + return false; +} + //---------------------------------------------------------------------- void FObject::addChild (FObject* obj) { diff --git a/src/fobject.h b/src/fobject.h index ad95e37f..0b67fab8 100644 --- a/src/fobject.h +++ b/src/fobject.h @@ -75,6 +75,8 @@ class FObject // Inquiries bool hasParent() const; bool hasChildren() const; + bool isChild (FObject*) const; + bool isDirectChild (FObject*) const; bool isTimerInUpdating() const; // Methods @@ -140,6 +142,10 @@ inline bool FObject::hasParent() const inline bool FObject::hasChildren() const { return bool( ! children_list.empty() ); } +//---------------------------------------------------------------------- +inline bool FObject::isDirectChild (FObject* obj) const +{ return bool( obj->getParent() == this ); } + //---------------------------------------------------------------------- inline bool FObject::isTimerInUpdating() const { return timer_modify_lock; } diff --git a/src/foptimove.cpp b/src/foptimove.cpp index 6e574d5e..e41fde60 100644 --- a/src/foptimove.cpp +++ b/src/foptimove.cpp @@ -709,8 +709,8 @@ int FOptiMove::capDurationToLength (int duration) //---------------------------------------------------------------------- int FOptiMove::repeatedAppend (capability& o, int count, char* dst) { - register size_t src_len; - register size_t dst_len; + register std::size_t src_len; + register std::size_t dst_len; register int total; src_len = std::strlen(o.cap); diff --git a/src/fscrollview.cpp b/src/fscrollview.cpp index 389a6d6d..f8368ec0 100644 --- a/src/fscrollview.cpp +++ b/src/fscrollview.cpp @@ -2,6 +2,7 @@ // Provides: class FScrollView #include "fscrollview.h" +#include "fwindow.h" //---------------------------------------------------------------------- @@ -23,7 +24,7 @@ FScrollView::FScrollView (FWidget* parent) , vMode(fc::Auto) , hMode(fc::Auto) { - init(); + init(parent); } //---------------------------------------------------------------------- @@ -329,16 +330,16 @@ void FScrollView::scrollTo (int x, int y) viewport_geometry.setWidth(save_width); viewport_geometry.setHeight(save_height); - hbar->setValue (xoffset); - vbar->setValue (yoffset); - drawHBar(); - drawVBar(); viewport->has_changes = true; setTopPadding (1 - yoffset); setLeftPadding (1 - xoffset); setBottomPadding (1 - (getScrollHeight() - getViewportHeight() - yoffset)); setRightPadding (1 - (getScrollWidth() - getViewportWidth() - xoffset) + nf_offset); copy2area(); + hbar->setValue (xoffset); + vbar->setValue (yoffset); + drawHBar(); + drawVBar(); updateTerminal(); } @@ -723,6 +724,7 @@ void FScrollView::copy2area() print_area->changes[ay+y].xmax = uInt(ax+x_end-1); } + setViewportCursor(); viewport->has_changes = false; print_area->has_changes = true; } @@ -730,8 +732,29 @@ void FScrollView::copy2area() // private methods of FScrollView //---------------------------------------------------------------------- -void FScrollView::init() +inline FPoint FScrollView::getViewportCursorPos() { + int x, y; + FWidget* window = FWindow::getWindowWidget(this); + if ( window ) + { + int widget_offsetX = getTermX() - window->getTermX(); + int widget_offsetY = getTermY() - window->getTermY(); + x = widget_offsetX + viewport->input_cursor_x - viewport_geometry.getX(); + y = widget_offsetY + viewport->input_cursor_y - viewport_geometry.getY(); + return FPoint(x,y); + } + else + return FPoint(-1,-1); +} + +//---------------------------------------------------------------------- +void FScrollView::init (FWidget* parent) +{ + assert ( parent != 0 ); + assert ( std::strcmp ( parent->getClassName() + , const_cast("FScrollView") ) != 0 ); + setForegroundColor (wc.dialog_fg); setBackgroundColor (wc.dialog_bg); @@ -849,6 +872,25 @@ void FScrollView::setVerticalScrollBarVisibility() } } +//---------------------------------------------------------------------- +void FScrollView::setViewportCursor() +{ + if ( ! isChild(getFocusWidget()) ) + return; + + FPoint cursor_pos ( viewport->input_cursor_x - 1 + , viewport->input_cursor_y - 1 ); + FPoint window_cursor_pos = getViewportCursorPos(); + print_area->input_cursor_x = window_cursor_pos.getX(); + print_area->input_cursor_y = window_cursor_pos.getY(); + + if ( viewport->input_cursor_visible + && viewport_geometry.contains(cursor_pos) ) + print_area->input_cursor_visible = true; + else + print_area->input_cursor_visible = false; +} + //---------------------------------------------------------------------- void FScrollView::cb_VBarChange (FWidget*, data_ptr) { diff --git a/src/fscrollview.h b/src/fscrollview.h index 4ad4aad7..95ce65e4 100644 --- a/src/fscrollview.h +++ b/src/fscrollview.h @@ -128,11 +128,15 @@ class FScrollView : public FWidget // Disable assignment operator (=) FScrollView& operator = (const FScrollView&); + // Accessors + FPoint getViewportCursorPos(); + // Methods - void init(); + void init (FWidget*); void calculateScrollbarPos(); void setHorizontalScrollBarVisibility(); void setVerticalScrollBarVisibility(); + void setViewportCursor(); void redrawHBar(); void redrawVBar(); void drawHBar(); diff --git a/src/fstring.cpp b/src/fstring.cpp index e21b2d6a..9338635b 100644 --- a/src/fstring.cpp +++ b/src/fstring.cpp @@ -2381,7 +2381,7 @@ inline char* FString::wc_to_c_str (const wchar_t* s) const c_string = new char[dest_size](); // pre-initialiaze the whole string with '\0' - std::memset (c_string, '\0', size_t(dest_size)); + std::memset (c_string, '\0', std::size_t(dest_size)); } catch (const std::bad_alloc& ex) { @@ -2435,7 +2435,7 @@ inline wchar_t* FString::c_to_wc_str (const char* s) const { dest = new wchar_t[size](); // pre-initialiaze the whole string with '\0' - std::wmemset (dest, L'\0', size_t(size)); + std::wmemset (dest, L'\0', std::size_t(size)); } catch (const std::bad_alloc& ex) { diff --git a/src/fterm.cpp b/src/fterm.cpp index 13899f46..1263b9ad 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -379,7 +379,7 @@ int FTerm::parseKeyString ( char buffer[] , timeval* time_keypressed ) { register uChar firstchar = uChar(buffer[0]); - register size_t buf_len = std::strlen(buffer); + register std::size_t buf_len = std::strlen(buffer); const long key_timeout = 100000; // 100 ms int key, len, n; @@ -831,7 +831,7 @@ FString* FTerm::getXTermFont() { if ( std::scanf("\033]50;%[^\n]s", temp) == 1 ) { - size_t n = std::strlen(temp); + std::size_t n = std::strlen(temp); // BEL + '\0' = string terminator if ( n >= 5 && temp[n-1] == BEL[0] && temp[n] == '\0' ) @@ -868,7 +868,7 @@ FString* FTerm::getXTermTitle() { if ( std::scanf("\033]l%[^\n]s", temp) == 1 ) { - size_t n = std::strlen(temp); + std::size_t n = std::strlen(temp); // Esc + \ = OSC string terminator if ( n >= 2 && temp[n-2] == ESC[0] && temp[n-1] == '\\' ) @@ -912,7 +912,7 @@ const FString FTerm::getXTermColorName (int color) { if ( std::scanf("\033]4;%d;%[^\n]s", &color, temp) == 2 ) { - size_t n = std::strlen(temp); + std::size_t n = std::strlen(temp); // BEL + '\0' = string terminator if ( n >= 6 && temp[n-1] == BEL[0] && temp[n] == '\0' ) @@ -1969,7 +1969,7 @@ void FTerm::restoreTTYsettings() int FTerm::getScreenFont() { struct console_font_op font; - const size_t data_size = 4 * 32 * 512; + const std::size_t data_size = 4 * 32 * 512; int ret; if ( fd_tty < 0 ) @@ -2026,7 +2026,7 @@ int FTerm::setScreenFont ( uChar* fontdata, uInt count else { const uInt bytes_per_line = font.width / 8; - const size_t data_size = bytes_per_line * 32 * font.charcount; + const std::size_t data_size = bytes_per_line * 32 * font.charcount; try { diff --git a/src/fterm.h b/src/fterm.h index af4811b1..3a4ab1f9 100644 --- a/src/fterm.h +++ b/src/fterm.h @@ -4,7 +4,7 @@ // Base class // ══════════ // -// ▕▔▔▔▔▔▔▔▏ 1 1▕▔▔▔▔▔▔▔▔▔▔▔▏ +// ▕▔▔▔▔▔▔▔▏1 1▕▔▔▔▔▔▔▔▔▔▔▔▏ // ▕ FTerm ▏-┬- - - -▕ FOptiMove ▏ // ▕▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▁▁▁▏ // : diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 36e97079..92fabfbe 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -262,7 +262,7 @@ void FVTerm::delPreprocessingHandler (FVTerm* instance) if ( ! print_area ) FVTerm::getPrintArea(); - if ( ! print_area || ! print_area->preprocessing_call.empty() ) + if ( ! print_area || print_area->preprocessing_call.empty() ) return; FPreprocessing::iterator iter, end; @@ -689,6 +689,19 @@ FVTerm::term_area* FVTerm::getPrintArea() return vdesktop; } +//---------------------------------------------------------------------- +bool FVTerm::isChildPrintArea() const +{ + FVTerm* p_obj = static_cast(getParent()); + + if ( p_obj + && p_obj->child_print_area + && p_obj->child_print_area == this->print_area ) + return true; + else + return false; +} + //---------------------------------------------------------------------- void FVTerm::createArea ( const FRect& r , const FPoint& p @@ -736,6 +749,8 @@ void FVTerm::resizeArea ( int offset_left, int offset_top , int rsw, int bsh , term_area* area ) { + // Resize the virtual window to a new size. + assert ( offset_top >= 0 ); assert ( width > 0 ); assert ( height > 0 ); @@ -814,6 +829,7 @@ void FVTerm::resizeArea ( int offset_left, int offset_top void FVTerm::removeArea (term_area*& area) { // remove the virtual window + if ( area != 0 ) { if ( area->changes != 0 ) diff --git a/src/fvterm.h b/src/fvterm.h index 81ca9fae..903158e6 100644 --- a/src/fvterm.h +++ b/src/fvterm.h @@ -11,7 +11,7 @@ // │ │ // └─────┬─────┘ // │ -// ▕▔▔▔▔▔▔▔▔▏ 1 *▕▔▔▔▔▔▔▔▔▔▏ +// ▕▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▔▏ // ▕ FVTerm ▏-┬- - - -▕ FString ▏ // ▕▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▁▏ // : @@ -283,6 +283,7 @@ class FVTerm : public FObject, public FTerm // Inquiries bool hasPrintArea() const; bool hasChildPrintArea() const; + bool isChildPrintArea() const; bool isVirtualWindow() const; // Methods diff --git a/src/fwidget.cpp b/src/fwidget.cpp index 2dc8832c..450fa9da 100644 --- a/src/fwidget.cpp +++ b/src/fwidget.cpp @@ -674,15 +674,24 @@ bool FWidget::setCursorPos (register int x, register int y) if ( (flags & fc::focus) == 0 || isWindowWidget() ) return false; - FWidget* window = FWindow::getWindowWidget(this); - - if ( ! window ) + if ( ! FWindow::getWindowWidget(this) ) return false; - if ( term_area* area = window->getVWin() ) + term_area* area = getPrintArea(); + + if ( area->widget ) { - setAreaCursor ( getTermX() - window->getTermX() + x - , getTermY() - window->getTermY() + y + int widget_offsetX = getTermX() - area->widget->getTermX(); + int widget_offsetY = getTermY() - area->widget->getTermY(); + + if ( isChildPrintArea() ) + { + widget_offsetX += (1 - area->widget->getLeftPadding()); + widget_offsetY += (1 - area->widget->getTopPadding()); + } + + setAreaCursor ( widget_offsetX + x + , widget_offsetY + y , visible_cursor , area ); return true; diff --git a/src/fwidget.h b/src/fwidget.h index 08686a24..950fc5c8 100644 --- a/src/fwidget.h +++ b/src/fwidget.h @@ -16,7 +16,7 @@ // ▕▁▁▁▁▁▁▁▁▏ // ▲ // │ -// ▕▔▔▔▔▔▔▔▔▔▏ 1 1▕▔▔▔▔▔▔▔▔▔▔▔▔▏ +// ▕▔▔▔▔▔▔▔▔▔▏1 1▕▔▔▔▔▔▔▔▔▔▔▔▔▏ // ▕ FWidget ▏-┬- - - -▕ FStatusBar ▏ // ▕▁▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▁▁▁▁▏ // : diff --git a/src/fwindow.h b/src/fwindow.h index e68c56bf..af19c669 100644 --- a/src/fwindow.h +++ b/src/fwindow.h @@ -21,7 +21,7 @@ // ▕▁▁▁▁▁▁▁▁▁▏ // ▲ // │ -// ▕▔▔▔▔▔▔▔▔▔▏ 1 *▕▔▔▔▔▔▔▔▔▏ +// ▕▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▏ // ▕ FWindow ▏-┬- - - -▕ FEvent ▏ // ▕▁▁▁▁▁▁▁▁▁▏ : ▕▁▁▁▁▁▁▁▁▏ // : diff --git a/test/scrollview.cpp b/test/scrollview.cpp index f221916d..fd5af398 100644 --- a/test/scrollview.cpp +++ b/test/scrollview.cpp @@ -27,14 +27,19 @@ class scrollview : public FScrollView void setScrollSize (int, int); private: + // Disable copy constructor + scrollview (const scrollview&); + // Disable assignment operator (=) + scrollview& operator = (const scrollview&); + // Method void draw(); // Callback methods - void cb_go_east (FWidget*, void*); - void cb_go_south (FWidget*, void*); - void cb_go_west (FWidget*, void*); - void cb_go_north (FWidget*, void*); + void cb_go_east (FWidget*, data_ptr); + void cb_go_south (FWidget*, data_ptr); + void cb_go_west (FWidget*, data_ptr); + void cb_go_north (FWidget*, data_ptr); // Data Members FButton* go_east; @@ -44,9 +49,14 @@ class scrollview : public FScrollView }; #pragma pack(pop) +#include "fcheckbox.h" //---------------------------------------------------------------------- scrollview::scrollview (FWidget* parent) : FScrollView(parent) + , go_east() + , go_south() + , go_west() + , go_north() { go_east = new FButton(wchar_t(fc::BlackRightPointingPointer) , this); go_east->setGeometry (1, 1, 5, 1); @@ -128,7 +138,7 @@ void scrollview::draw() } //---------------------------------------------------------------------- -void scrollview::cb_go_east (FWidget*, void*) +void scrollview::cb_go_east (FWidget*, data_ptr) { scrollToX (getScrollWidth() - getViewportWidth() + 1); go_south->setFocus(); @@ -137,7 +147,7 @@ void scrollview::cb_go_east (FWidget*, void*) } //---------------------------------------------------------------------- -void scrollview::cb_go_south (FWidget*, void*) +void scrollview::cb_go_south (FWidget*, data_ptr) { scrollToY (getScrollHeight() - getViewportHeight() + 1); go_west->setFocus(); @@ -146,7 +156,7 @@ void scrollview::cb_go_south (FWidget*, void*) } //---------------------------------------------------------------------- -void scrollview::cb_go_west (FWidget*, void*) +void scrollview::cb_go_west (FWidget*, data_ptr) { scrollToX (1); go_north->setFocus(); @@ -155,7 +165,7 @@ void scrollview::cb_go_west (FWidget*, void*) } //---------------------------------------------------------------------- -void scrollview::cb_go_north (FWidget*, void*) +void scrollview::cb_go_north (FWidget*, data_ptr) { scrollToY (1); go_east->setFocus(); @@ -184,7 +194,7 @@ class scrollviewdemo : public FDialog void onClose (FCloseEvent*); // Callback method - void cb_quit (FWidget* = 0, void* = 0); + void cb_quit (FWidget* = 0, data_ptr = 0); }; #pragma pack(pop) @@ -224,7 +234,7 @@ scrollviewdemo::~scrollviewdemo() { } //---------------------------------------------------------------------- -void scrollviewdemo::cb_quit (FWidget*, void*) +void scrollviewdemo::cb_quit (FWidget*, data_ptr) { close(); }