2031 lines
48 KiB
C++
2031 lines
48 KiB
C++
/***********************************************************************
|
|
* fwidget.cpp - Intermediate base class for all widget objects *
|
|
* *
|
|
* This file is part of the Final Cut widget toolkit *
|
|
* *
|
|
* Copyright 2015-2020 Markus Gans *
|
|
* *
|
|
* The Final Cut is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public License *
|
|
* as published by the Free Software Foundation; either version 3 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* The Final Cut is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this program. If not, see *
|
|
* <http://www.gnu.org/licenses/>. *
|
|
***********************************************************************/
|
|
|
|
#include <vector>
|
|
|
|
#include "final/fapplication.h"
|
|
#include "final/fevent.h"
|
|
#include "final/fmenubar.h"
|
|
#include "final/fstatusbar.h"
|
|
#include "final/fstring.h"
|
|
#include "final/ftermdata.h"
|
|
#include "final/fwidget.h"
|
|
#include "final/fwidgetcolors.h"
|
|
#include "final/fwindow.h"
|
|
|
|
namespace finalcut
|
|
{
|
|
|
|
// global FWidget object
|
|
static FWidget* root_widget{nullptr};
|
|
|
|
// static class attributes
|
|
FStatusBar* FWidget::statusbar{nullptr};
|
|
FMenuBar* FWidget::menubar{nullptr};
|
|
FWidget* FWidget::show_root_widget{nullptr};
|
|
FWidget* FWidget::redraw_root_widget{nullptr};
|
|
FWidget::FWidgetList* FWidget::window_list{nullptr};
|
|
FWidget::FWidgetList* FWidget::dialog_list{nullptr};
|
|
FWidget::FWidgetList* FWidget::always_on_top_list{nullptr};
|
|
FWidget::FWidgetList* FWidget::close_widget{nullptr};
|
|
FWidgetColors FWidget::wcolors{};
|
|
bool FWidget::init_desktop{false};
|
|
bool FWidget::hideable{false};
|
|
uInt FWidget::modal_dialog_counter{};
|
|
|
|
//----------------------------------------------------------------------
|
|
// class FWidget
|
|
//----------------------------------------------------------------------
|
|
|
|
// constructors and destructor
|
|
//----------------------------------------------------------------------
|
|
FWidget::FWidget (FWidget* parent, bool disable_alt_screen)
|
|
: FVTerm( ! (bool(parent) || root_widget), disable_alt_screen)
|
|
, FObject(parent)
|
|
{
|
|
// init bit field with 0
|
|
memset (&flags, 0, sizeof(flags));
|
|
|
|
flags.active = true; // Enable widget by default
|
|
flags.visible = true; // A widget is visible by default
|
|
flags.focusable = true; // A widget is focusable by default
|
|
flags.visible_cursor = true; // A widget has a visible cursor by default
|
|
setWidgetProperty (true); // This FObject is a widget
|
|
|
|
if ( ! parent )
|
|
{
|
|
if ( root_widget )
|
|
{
|
|
auto ftermdata = FTerm::getFTermData();
|
|
ftermdata->setExitMessage("FWidget: No parent defined! "
|
|
"There should be only one root object");
|
|
FApplication::exit(EXIT_FAILURE);
|
|
return;
|
|
}
|
|
|
|
root_widget = this;
|
|
show_root_widget = nullptr;
|
|
redraw_root_widget = nullptr;
|
|
modal_dialog_counter = 0;
|
|
statusbar = nullptr;
|
|
initRootWidget();
|
|
}
|
|
else
|
|
{
|
|
flags.visible_cursor = ! hideable;
|
|
woffset = parent->wclient_offset;
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget::~FWidget() // destructor
|
|
{
|
|
processDestroy();
|
|
delCallbacks();
|
|
FApplication::removeQueuedEvent(this);
|
|
|
|
// unset clicked widget
|
|
if ( this == getClickedWidget() )
|
|
setClickedWidget(nullptr);
|
|
|
|
// unset the local window widget focus
|
|
if ( flags.focus )
|
|
{
|
|
if ( auto window = FWindow::getWindowWidget(this) )
|
|
if ( window != this )
|
|
window->setWindowFocusWidget(nullptr);
|
|
}
|
|
|
|
// unset the global widget focus
|
|
if ( this == FWidget::getFocusWidget() )
|
|
FWidget::setFocusWidget(nullptr);
|
|
|
|
// unset main widget
|
|
if ( this == getMainWidget() )
|
|
{
|
|
setMainWidget(nullptr);
|
|
quit();
|
|
}
|
|
|
|
accelerator_list.clear();
|
|
|
|
// finish the program
|
|
if ( root_widget == this )
|
|
finish();
|
|
}
|
|
|
|
|
|
// public methods of FWidget
|
|
//----------------------------------------------------------------------
|
|
FWidget* FWidget::getRootWidget() const
|
|
{
|
|
auto obj = const_cast<FWidget*>(this);
|
|
auto p_obj = getParentWidget();
|
|
|
|
while ( ! obj->isRootWidget() && p_obj )
|
|
{
|
|
obj = p_obj;
|
|
p_obj = p_obj->getParentWidget();
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget* FWidget::getParentWidget() const
|
|
{
|
|
auto p_obj = getParent();
|
|
|
|
if ( p_obj && p_obj->isWidget() )
|
|
return static_cast<FWidget*>(p_obj);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget* FWidget::getFirstFocusableWidget (FObjectList list)
|
|
{
|
|
if ( list.empty() )
|
|
return nullptr;
|
|
|
|
auto iter = list.begin();
|
|
|
|
while ( iter != list.end() )
|
|
{
|
|
if ( (*iter)->isWidget() )
|
|
{
|
|
auto child = static_cast<FWidget*>(*iter);
|
|
|
|
if ( child->isEnabled() && child->acceptFocus() )
|
|
return child;
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget* FWidget::getLastFocusableWidget (FObjectList list)
|
|
{
|
|
if ( list.empty() )
|
|
return nullptr;
|
|
|
|
auto iter = list.end();
|
|
|
|
do
|
|
{
|
|
--iter;
|
|
|
|
if ( ! (*iter)->isWidget() )
|
|
continue;
|
|
|
|
auto child = static_cast<FWidget*>(*iter);
|
|
|
|
if ( child->isEnabled() && child->acceptFocus() )
|
|
return child;
|
|
}
|
|
while ( iter != list.begin() );
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
std::vector<bool>& FWidget::doubleFlatLine_ref (fc::sides side)
|
|
{
|
|
assert ( side == fc::top
|
|
|| side == fc::right
|
|
|| side == fc::bottom
|
|
|| side == fc::left );
|
|
|
|
switch ( side )
|
|
{
|
|
case fc::top:
|
|
return double_flatline_mask.top;
|
|
|
|
case fc::right:
|
|
return double_flatline_mask.right;
|
|
|
|
case fc::bottom:
|
|
return double_flatline_mask.bottom;
|
|
|
|
case fc::left:
|
|
return double_flatline_mask.left;
|
|
}
|
|
|
|
return double_flatline_mask.left;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FPoint FWidget::getPrintPos()
|
|
{
|
|
const auto& cur = getPrintCursor();
|
|
return FPoint ( cur.getX() - woffset.getX1() - getX() + 1
|
|
, cur.getY() - woffset.getY1() - getY() + 1 );
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setMainWidget (FWidget* obj)
|
|
{
|
|
main_widget = obj;
|
|
auto app_object = FApplication::getApplicationObject();
|
|
|
|
if ( obj && app_object && ! getFocusWidget() )
|
|
app_object->focusFirstChild();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::setVisible (bool enable)
|
|
{
|
|
return (flags.visible = enable);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::setEnable (bool enable)
|
|
{
|
|
return (flags.active = enable);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::setFocus (bool enable)
|
|
{
|
|
if ( ! isEnabled() )
|
|
return false;
|
|
|
|
if ( flags.focus == enable )
|
|
return true;
|
|
|
|
auto last_focus = FWidget::getFocusWidget();
|
|
|
|
// set widget focus
|
|
if ( enable && ! flags.focus )
|
|
{
|
|
if ( last_focus )
|
|
last_focus->unsetFocus();
|
|
|
|
FWidget::setFocusWidget(this);
|
|
}
|
|
|
|
// Activates the window with the focused widget
|
|
setWindowFocus (enable);
|
|
|
|
// Set status bar text for widget focus
|
|
setStatusbarText (enable);
|
|
return (flags.focus = enable);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setColor()
|
|
{
|
|
// Changes colors to the widget default colors
|
|
setColor (foreground_color, background_color);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setX (int x, bool adjust)
|
|
{
|
|
if ( getX() == x && wsize.getX() == x )
|
|
return;
|
|
|
|
if ( ! isWindowWidget() && x < 1 )
|
|
x = 1;
|
|
|
|
wsize.setX(x);
|
|
adjust_wsize.setX(x);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setY (int y, bool adjust)
|
|
{
|
|
if ( getY() == y && wsize.getY() == y )
|
|
return;
|
|
|
|
if ( ! isWindowWidget() && y < 1 )
|
|
y = 1;
|
|
|
|
wsize.setY(y);
|
|
adjust_wsize.setY(y);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setPos (const FPoint& p, bool adjust)
|
|
{
|
|
FPoint pos(p);
|
|
|
|
if ( getX() == pos.getX() && wsize.getX() == pos.getX()
|
|
&& getY() == pos.getY() && wsize.getY() == pos.getY() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( ! isWindowWidget() )
|
|
{
|
|
if ( pos.getX() < 1 )
|
|
pos.setX(1);
|
|
|
|
if ( pos.getY() < 1 )
|
|
pos.setY(1);
|
|
}
|
|
|
|
wsize.setPos(pos);
|
|
adjust_wsize.setPos(pos);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setWidth (std::size_t width, bool adjust)
|
|
{
|
|
width = std::min (width, size_hints.max_width);
|
|
width = std::max (width, size_hints.min_width);
|
|
|
|
if ( getWidth() == width && wsize.getWidth() == width )
|
|
return;
|
|
|
|
if ( width < 1 )
|
|
width = 1;
|
|
|
|
wsize.setWidth(width);
|
|
adjust_wsize.setWidth(width);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setHeight (std::size_t height, bool adjust)
|
|
{
|
|
height = std::min (height, size_hints.max_height);
|
|
height = std::max (height, size_hints.min_height);
|
|
|
|
if ( getHeight() == height && wsize.getHeight() == height )
|
|
return;
|
|
|
|
if ( height < 1 )
|
|
height = 1;
|
|
|
|
wsize.setHeight(height);
|
|
adjust_wsize.setHeight(height);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setSize (const FSize& size, bool adjust)
|
|
{
|
|
std::size_t width = size.getWidth();
|
|
std::size_t height = size.getHeight();
|
|
width = std::min (width, size_hints.max_width);
|
|
width = std::max (width, size_hints.min_width);
|
|
height = std::min (height, size_hints.max_height);
|
|
height = std::max (height, size_hints.min_height);
|
|
|
|
if ( getWidth() == width && wsize.getWidth() == width
|
|
&& getHeight() == height && wsize.getHeight() == height )
|
|
return;
|
|
|
|
if ( width < 1 )
|
|
width = 1;
|
|
|
|
if ( height < 1 )
|
|
height = 1;
|
|
|
|
wsize.setWidth(width);
|
|
wsize.setHeight(height);
|
|
adjust_wsize.setWidth(width);
|
|
adjust_wsize.setHeight(height);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setTopPadding (int top, bool adjust)
|
|
{
|
|
if ( padding.top == top )
|
|
return;
|
|
|
|
padding.top = top;
|
|
|
|
if ( adjust )
|
|
{
|
|
if ( isRootWidget() )
|
|
{
|
|
auto r = root_widget;
|
|
r->wclient_offset.setY1 (r->padding.top);
|
|
adjustSizeGlobal();
|
|
}
|
|
else
|
|
adjustSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setLeftPadding (int left, bool adjust)
|
|
{
|
|
if ( padding.left == left )
|
|
return;
|
|
|
|
padding.left = left;
|
|
|
|
if ( adjust )
|
|
{
|
|
if ( isRootWidget() )
|
|
{
|
|
auto r = root_widget;
|
|
r->wclient_offset.setX1 (r->padding.left);
|
|
adjustSizeGlobal();
|
|
}
|
|
else
|
|
adjustSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setBottomPadding (int bottom, bool adjust)
|
|
{
|
|
if ( padding.bottom == bottom )
|
|
return;
|
|
|
|
padding.bottom = bottom;
|
|
|
|
if ( adjust )
|
|
{
|
|
if ( isRootWidget() )
|
|
{
|
|
auto r = root_widget;
|
|
r->wclient_offset.setY2 (int(r->getHeight()) - 1 - r->padding.bottom);
|
|
adjustSizeGlobal();
|
|
}
|
|
else
|
|
adjustSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setRightPadding (int right, bool adjust)
|
|
{
|
|
if ( padding.right == right )
|
|
return;
|
|
|
|
padding.right = right;
|
|
|
|
if ( adjust )
|
|
{
|
|
if ( isRootWidget() )
|
|
{
|
|
auto r = root_widget;
|
|
r->wclient_offset.setX2 (int(r->getWidth()) - 1 - r->padding.right);
|
|
adjustSizeGlobal();
|
|
}
|
|
else
|
|
adjustSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setTermSize (const FSize& size)
|
|
{
|
|
// Set xterm size to width x height
|
|
|
|
if ( isXTerminal() )
|
|
{
|
|
root_widget->wsize.setRect(FPoint(1, 1), size);
|
|
root_widget->adjust_wsize = root_widget->wsize;
|
|
FTerm::setTermSize(size); // width = columns / height = lines
|
|
detectTermSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setGeometry (const FPoint& p, const FSize& s, bool adjust)
|
|
{
|
|
// Sets the geometry of the widget relative to its parent
|
|
|
|
const int x = p.getX();
|
|
const int y = p.getY();
|
|
std::size_t w = s.getWidth();
|
|
std::size_t h = s.getHeight();
|
|
w = std::min (w, size_hints.max_width);
|
|
w = std::max (w, size_hints.min_width);
|
|
h = std::min (h, size_hints.max_height);
|
|
h = std::max (h, size_hints.min_height);
|
|
|
|
if ( getPos() == p && getWidth() == w && getHeight() == h )
|
|
return;
|
|
|
|
if ( ! isWindowWidget() )
|
|
{
|
|
( x < 1 ) ? wsize.setX(1) : wsize.setX(x);
|
|
( y < 1 ) ? wsize.setY(1) : wsize.setY(y);
|
|
}
|
|
else
|
|
{
|
|
wsize.setX(x);
|
|
wsize.setY(y);
|
|
}
|
|
|
|
( w < 1 ) ? wsize.setWidth(1) : wsize.setWidth(w);
|
|
( h < 1 ) ? wsize.setHeight(1) : wsize.setHeight(h);
|
|
|
|
adjust_wsize = wsize;
|
|
const int term_x = getTermX();
|
|
const int term_y = getTermY();
|
|
|
|
wclient_offset.setCoordinates ( term_x - 1 + padding.left
|
|
, term_y - 1 + padding.top
|
|
, term_x - 2 + int(getWidth()) - padding.right
|
|
, term_y - 2 + int(getHeight()) - padding.bottom );
|
|
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
|
|
if ( adjust )
|
|
adjustSize();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::setCursorPos (const FPoint& pos)
|
|
{
|
|
// sets the input cursor position
|
|
|
|
widget_cursor_position.setPoint(pos);
|
|
|
|
if ( ! flags.focus || isWindowWidget() )
|
|
return false;
|
|
|
|
if ( ! FWindow::getWindowWidget(this) )
|
|
return false;
|
|
|
|
const auto& area = getPrintArea();
|
|
|
|
if ( area->widget )
|
|
{
|
|
int woffsetX = getTermX() - area->widget->getTermX();
|
|
int woffsetY = getTermY() - area->widget->getTermY();
|
|
|
|
if ( isChildPrintArea() )
|
|
{
|
|
woffsetX += (1 - area->widget->getLeftPadding());
|
|
woffsetY += (1 - area->widget->getTopPadding());
|
|
}
|
|
|
|
setAreaCursor ( FPoint ( woffsetX + pos.getX()
|
|
, woffsetY + pos.getY() )
|
|
, flags.visible_cursor
|
|
, area );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setPrintPos (const FPoint& pos)
|
|
{
|
|
const FPoint p{ woffset.getX1() + getX() + pos.getX() - 1,
|
|
woffset.getY1() + getY() + pos.getY() - 1 };
|
|
setPrintCursor(p);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setDoubleFlatLine (fc::sides side, bool bit)
|
|
{
|
|
uLong length{};
|
|
|
|
assert ( side == fc::top
|
|
|| side == fc::right
|
|
|| side == fc::bottom
|
|
|| side == fc::left );
|
|
|
|
switch ( side )
|
|
{
|
|
case fc::top:
|
|
length = double_flatline_mask.top.size();
|
|
double_flatline_mask.top.assign(length, bit);
|
|
break;
|
|
|
|
case fc::right:
|
|
length = double_flatline_mask.right.size();
|
|
double_flatline_mask.right.assign(length, bit);
|
|
break;
|
|
|
|
case fc::bottom:
|
|
length = double_flatline_mask.bottom.size();
|
|
double_flatline_mask.bottom.assign(length, bit);
|
|
break;
|
|
|
|
case fc::left:
|
|
length = double_flatline_mask.left.size();
|
|
double_flatline_mask.left.assign(length, bit);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setDoubleFlatLine (fc::sides side, int pos, bool bit)
|
|
{
|
|
assert ( side == fc::top
|
|
|| side == fc::right
|
|
|| side == fc::bottom
|
|
|| side == fc::left );
|
|
|
|
assert ( pos >= 1 );
|
|
|
|
uLong length{};
|
|
const uLong index = uLong(pos - 1);
|
|
|
|
switch ( side )
|
|
{
|
|
case fc::top:
|
|
length = double_flatline_mask.top.size();
|
|
|
|
if ( index < length )
|
|
double_flatline_mask.top[index] = bit;
|
|
|
|
break;
|
|
|
|
case fc::right:
|
|
length = double_flatline_mask.right.size();
|
|
|
|
if ( index < length )
|
|
double_flatline_mask.right[index] = bit;
|
|
|
|
break;
|
|
|
|
case fc::bottom:
|
|
length = double_flatline_mask.bottom.size();
|
|
|
|
if ( index < length )
|
|
double_flatline_mask.bottom[index] = bit;
|
|
|
|
break;
|
|
|
|
case fc::left:
|
|
length = double_flatline_mask.left.size();
|
|
|
|
if ( index < length )
|
|
double_flatline_mask.left[index] = bit;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget* FWidget::childWidgetAt (const FPoint& pos)
|
|
{
|
|
if ( ! hasChildren() )
|
|
return nullptr;
|
|
|
|
for (auto&& child : getChildren())
|
|
{
|
|
if ( ! child->isWidget() )
|
|
continue;
|
|
|
|
auto widget = static_cast<FWidget*>(child);
|
|
|
|
if ( widget->isEnabled()
|
|
&& widget->isShown()
|
|
&& ! widget->isWindowWidget()
|
|
&& widget->getTermGeometry().contains(pos) )
|
|
{
|
|
auto sub_child = widget->childWidgetAt(pos);
|
|
return ( sub_child != nullptr ) ? sub_child : widget;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int FWidget::numOfFocusableChildren()
|
|
{
|
|
if ( ! hasChildren() )
|
|
return 0;
|
|
|
|
int num{0};
|
|
|
|
for (auto&& child : getChildren())
|
|
{
|
|
if ( child->isWidget() )
|
|
{
|
|
const auto& widget = static_cast<FWidget*>(child);
|
|
|
|
if ( widget->isShown()
|
|
&& widget->acceptFocus()
|
|
&& ! widget->isWindowWidget() )
|
|
num++;
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::close()
|
|
{
|
|
// Sends a close event and quits the application on acceptance
|
|
|
|
FCloseEvent ev(fc::Close_Event);
|
|
FApplication::sendEvent(this, &ev);
|
|
|
|
if ( ev.isAccepted() )
|
|
{
|
|
if ( this == getMainWidget() )
|
|
quit();
|
|
else
|
|
{
|
|
hide();
|
|
|
|
if ( ! flags.modal )
|
|
close_widget->push_back(this);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::addCallback ( const FString& cb_signal
|
|
, FCallback cb_function
|
|
, FDataPtr data )
|
|
{
|
|
// Add a (normal) function pointer as callback
|
|
|
|
FCallbackData obj{ cb_signal, nullptr, cb_function, data };
|
|
callback_objects.push_back(obj);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::addCallback ( const FString& cb_signal
|
|
, FWidget* cb_instance
|
|
, FCallback cb_function
|
|
, FDataPtr data )
|
|
{
|
|
// Add a member function pointer as callback
|
|
|
|
FCallbackData obj{ cb_signal, cb_instance, cb_function, data };
|
|
callback_objects.push_back(obj);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::delCallback (FCallback cb_function)
|
|
{
|
|
// Delete cb_function form callback list
|
|
|
|
if ( callback_objects.empty() )
|
|
return;
|
|
|
|
auto iter = callback_objects.begin();
|
|
|
|
while ( iter != callback_objects.end() )
|
|
{
|
|
if ( getCallbackPtr(iter->cb_function) == getCallbackPtr(cb_function) )
|
|
iter = callback_objects.erase(iter);
|
|
else
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::delCallback (const FWidget* cb_instance)
|
|
{
|
|
// Delete all member function pointer from cb_instance
|
|
|
|
if ( callback_objects.empty() )
|
|
return;
|
|
|
|
auto iter = callback_objects.begin();
|
|
|
|
while ( iter != callback_objects.end() )
|
|
{
|
|
if ( iter->cb_instance == cb_instance )
|
|
iter = callback_objects.erase(iter);
|
|
else
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::delCallbacks()
|
|
{
|
|
// Delete all callbacks from this widget
|
|
|
|
callback_objects.clear(); // function pointer
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::emitCallback (const FString& emit_signal)
|
|
{
|
|
// Initiate callback for the given signal
|
|
|
|
if ( callback_objects.empty() )
|
|
return;
|
|
|
|
for (auto&& cback : callback_objects)
|
|
{
|
|
if ( cback.cb_signal == emit_signal )
|
|
{
|
|
// Calling the stored function pointer
|
|
auto callback = cback.cb_function;
|
|
callback (this, cback.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::addAccelerator (FKey key, FWidget* obj)
|
|
{
|
|
// Adding a keyboard accelerator for the given widget
|
|
|
|
auto widget = static_cast<FWidget*>(FWindow::getWindowWidget(obj));
|
|
FAccelerator accel = { key, obj };
|
|
|
|
if ( ! widget || widget == statusbar || widget == menubar )
|
|
widget = getRootWidget();
|
|
|
|
if ( widget )
|
|
widget->accelerator_list.push_back(accel);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::delAccelerator (FWidget* obj)
|
|
{
|
|
// Deletes all accelerators of the given widget
|
|
|
|
auto widget = static_cast<FWidget*>(FWindow::getWindowWidget(this));
|
|
|
|
if ( ! widget || widget == statusbar || widget == menubar )
|
|
widget = getRootWidget();
|
|
|
|
if ( widget
|
|
&& ! widget->accelerator_list.empty() )
|
|
{
|
|
auto iter = widget->accelerator_list.begin();
|
|
|
|
while ( iter != widget->accelerator_list.end() )
|
|
{
|
|
if ( iter->object == obj )
|
|
iter = widget->accelerator_list.erase(iter);
|
|
else
|
|
++iter;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::redraw()
|
|
{
|
|
// Redraw the widget immediately unless it is hidden.
|
|
|
|
if ( ! redraw_root_widget )
|
|
redraw_root_widget = this;
|
|
|
|
if ( isRootWidget() )
|
|
{
|
|
startTerminalUpdate();
|
|
// clean desktop
|
|
setColor (wcolors.term_fg, wcolors.term_bg);
|
|
clearArea (getVirtualDesktop());
|
|
}
|
|
else if ( ! isShown() )
|
|
return;
|
|
|
|
draw();
|
|
|
|
if ( isRootWidget() )
|
|
drawWindows();
|
|
else
|
|
drawChildren();
|
|
|
|
if ( isRootWidget() )
|
|
finishTerminalUpdate();
|
|
|
|
if ( redraw_root_widget == this )
|
|
{
|
|
updateTerminal();
|
|
flush();
|
|
redraw_root_widget = nullptr;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::resize()
|
|
{
|
|
if ( isRootWidget() )
|
|
{
|
|
const FRect old_term_geometry (getTermGeometry());
|
|
detectTermSize();
|
|
FRect term_geometry (getTermGeometry());
|
|
term_geometry.move (-1, -1);
|
|
|
|
if ( old_term_geometry.getSize() == term_geometry.getSize() )
|
|
return;
|
|
|
|
resizeVTerm (term_geometry.getSize());
|
|
resizeArea (term_geometry, getShadow(), getVirtualDesktop());
|
|
adjustSizeGlobal();
|
|
}
|
|
else
|
|
adjustSize();
|
|
|
|
// resize the four double-flatline-masks
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::show()
|
|
{
|
|
// Make the widget visible and draw it
|
|
|
|
if ( ! isVisible() )
|
|
return;
|
|
|
|
if ( ! init_desktop )
|
|
{
|
|
// Sets the initial screen settings
|
|
initScreenSettings();
|
|
// Initializing vdesktop
|
|
const auto& r = getRootWidget();
|
|
setColor(r->getForegroundColor(), r->getBackgroundColor());
|
|
clearArea (getVirtualDesktop());
|
|
// Destop is now initialized
|
|
init_desktop = true;
|
|
}
|
|
|
|
if ( ! show_root_widget )
|
|
{
|
|
startTerminalUpdate();
|
|
show_root_widget = this;
|
|
}
|
|
|
|
draw(); // Draw the widget
|
|
flags.hidden = false;
|
|
flags.shown = true;
|
|
|
|
if ( hasChildren() )
|
|
{
|
|
for (auto&& child : getChildren())
|
|
{
|
|
if ( child->isWidget() )
|
|
{
|
|
auto widget = static_cast<FWidget*>(child);
|
|
|
|
if ( ! widget->flags.hidden )
|
|
widget->show();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( show_root_widget && show_root_widget == this )
|
|
{
|
|
finishTerminalUpdate();
|
|
updateTerminal();
|
|
flush();
|
|
show_root_widget = nullptr;
|
|
}
|
|
|
|
FShowEvent show_ev (fc::Show_Event);
|
|
FApplication::sendEvent(this, &show_ev);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::hide()
|
|
{
|
|
// Hide the widget
|
|
|
|
flags.hidden = true;
|
|
|
|
if ( isVisible() )
|
|
{
|
|
flags.shown = false;
|
|
|
|
if ( ! isDialogWidget()
|
|
&& FWidget::getFocusWidget() == this
|
|
&& ! focusPrevChild() )
|
|
{
|
|
if ( FWidget::getFocusWidget() )
|
|
FWidget::getFocusWidget()->unsetFocus();
|
|
|
|
FWidget::setFocusWidget(getParentWidget());
|
|
}
|
|
|
|
FHideEvent hide_ev (fc::Hide_Event);
|
|
FApplication::sendEvent(this, &hide_ev);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::focusFirstChild()
|
|
{
|
|
if ( ! hasChildren() )
|
|
return false;
|
|
|
|
auto iter = FObject::begin();
|
|
const auto last = FObject::end();
|
|
|
|
while ( iter != last )
|
|
{
|
|
if ( ! (*iter)->isWidget() )
|
|
{
|
|
++iter;
|
|
continue;
|
|
}
|
|
|
|
auto widget = static_cast<FWidget*>(*iter);
|
|
|
|
if ( widget->isEnabled()
|
|
&& widget->acceptFocus()
|
|
&& ! widget->isMenuWidget() )
|
|
{
|
|
widget->setFocus();
|
|
|
|
if ( widget->numOfChildren() >= 1 )
|
|
{
|
|
if ( ! widget->focusFirstChild() && widget->isWindowWidget() )
|
|
{
|
|
++iter;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::focusLastChild()
|
|
{
|
|
if ( ! hasChildren() )
|
|
return false;
|
|
|
|
auto iter = FObject::end();
|
|
const auto first = FObject::begin();
|
|
|
|
do
|
|
{
|
|
--iter;
|
|
|
|
if ( ! (*iter)->isWidget() )
|
|
continue;
|
|
|
|
auto widget = static_cast<FWidget*>(*iter);
|
|
|
|
if ( widget->isEnabled()
|
|
&& widget->acceptFocus()
|
|
&& ! widget->isMenuWidget() )
|
|
{
|
|
widget->setFocus();
|
|
|
|
if ( widget->numOfChildren() >= 1 )
|
|
{
|
|
if ( ! widget->focusLastChild() && widget->isWindowWidget() )
|
|
continue;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
while ( iter != first );
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::move (const FPoint& pos)
|
|
{
|
|
wsize.move(pos);
|
|
adjust_wsize.move(pos);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::quit()
|
|
{
|
|
FApplication::exit(0);
|
|
}
|
|
|
|
|
|
// protected methods of FWidget
|
|
//----------------------------------------------------------------------
|
|
FVTerm::FTermArea* FWidget::getPrintArea()
|
|
{
|
|
// returns the print area of this object
|
|
|
|
if ( getCurrentPrintArea() )
|
|
return getCurrentPrintArea();
|
|
else
|
|
{
|
|
FWidget* obj{};
|
|
FWidget* p_obj = this;
|
|
|
|
do
|
|
{
|
|
obj = p_obj;
|
|
p_obj = static_cast<FWidget*>(obj->getParent());
|
|
}
|
|
while ( ! obj->getVWin() && ! obj->getChildPrintArea() && p_obj );
|
|
|
|
if ( obj->getVWin() )
|
|
{
|
|
setPrintArea (obj->getVWin());
|
|
return getCurrentPrintArea();
|
|
}
|
|
else if ( obj->getChildPrintArea() )
|
|
{
|
|
setPrintArea (obj->getChildPrintArea());
|
|
return getCurrentPrintArea();
|
|
}
|
|
}
|
|
|
|
return getVirtualDesktop();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::addPreprocessingHandler ( const FVTerm* instance
|
|
, const FPreprocessingFunction& function )
|
|
{
|
|
if ( ! getCurrentPrintArea() )
|
|
FWidget::getPrintArea();
|
|
|
|
FVTerm::addPreprocessingHandler (instance, function);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::delPreprocessingHandler (const FVTerm* instance)
|
|
{
|
|
if ( ! getCurrentPrintArea() )
|
|
FWidget::getPrintArea();
|
|
|
|
FVTerm::delPreprocessingHandler (instance);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::isChildPrintArea() const
|
|
{
|
|
const auto& p_obj = static_cast<FWidget*>(getParent());
|
|
|
|
if ( p_obj
|
|
&& p_obj->getChildPrintArea()
|
|
&& p_obj->getChildPrintArea() == getCurrentPrintArea() )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setStatusBar (FStatusBar* sbar)
|
|
{
|
|
if ( ! sbar || statusbar == sbar )
|
|
return;
|
|
|
|
if ( statusbar )
|
|
delete statusbar;
|
|
|
|
statusbar = sbar;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setMenuBar (FMenuBar* mbar)
|
|
{
|
|
if ( ! mbar || menubar == mbar )
|
|
return;
|
|
|
|
if ( menubar )
|
|
delete menubar;
|
|
|
|
menubar = mbar;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setParentOffset()
|
|
{
|
|
const auto& p = getParentWidget();
|
|
|
|
if ( p )
|
|
woffset = p->wclient_offset;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setTermOffset()
|
|
{
|
|
const auto& r = getRootWidget();
|
|
const int w = int(r->getWidth());
|
|
const int h = int(r->getHeight());
|
|
woffset.setCoordinates (0, 0, w - 1, h - 1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setTermOffsetWithPadding()
|
|
{
|
|
const auto& r = getRootWidget();
|
|
woffset.setCoordinates ( r->getLeftPadding()
|
|
, r->getTopPadding()
|
|
, int(r->getWidth()) - 1 - r->getRightPadding()
|
|
, int(r->getHeight()) - 1 - r->getBottomPadding() );
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::adjustSize()
|
|
{
|
|
if ( ! isRootWidget() )
|
|
{
|
|
const auto& p = getParentWidget();
|
|
|
|
if ( isWindowWidget() )
|
|
{
|
|
if ( ignore_padding && ! isDialogWidget() )
|
|
setTermOffset();
|
|
else
|
|
woffset = root_widget->wclient_offset;
|
|
}
|
|
else if ( ignore_padding && p )
|
|
{
|
|
woffset.setCoordinates ( p->getTermX() - 1
|
|
, p->getTermY() - 1
|
|
, p->getTermX() + int(p->getWidth()) - 2
|
|
, p->getTermY() + int(p->getHeight()) - 2 );
|
|
}
|
|
else if ( p )
|
|
woffset = p->wclient_offset;
|
|
|
|
adjust_wsize = wsize;
|
|
}
|
|
|
|
// Move and shrink in case of lack of space
|
|
if ( ! hasChildPrintArea() )
|
|
insufficientSpaceAdjust();
|
|
|
|
wclient_offset.setCoordinates
|
|
(
|
|
getTermX() - 1 + padding.left,
|
|
getTermY() - 1 + padding.top,
|
|
getTermX() - 2 + int(getWidth()) - padding.right,
|
|
getTermY() - 2 + int(getHeight()) - padding.bottom
|
|
);
|
|
|
|
if ( hasChildren() )
|
|
{
|
|
for (auto&& child : getChildren())
|
|
{
|
|
if ( child->isWidget() )
|
|
{
|
|
auto widget = static_cast<FWidget*>(child);
|
|
|
|
if ( ! widget->isWindowWidget() )
|
|
widget->adjustSize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::adjustSizeGlobal()
|
|
{
|
|
if ( ! isRootWidget() )
|
|
{
|
|
getRootWidget()->adjustSizeGlobal();
|
|
return;
|
|
}
|
|
|
|
if ( window_list && ! window_list->empty() )
|
|
{
|
|
for (auto&& window : *window_list)
|
|
window->adjustSize();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::hideArea (const FSize& size)
|
|
{
|
|
if ( size.isEmpty() )
|
|
return;
|
|
|
|
FColor fg{};
|
|
FColor bg{};
|
|
const auto& parent_widget = getParentWidget();
|
|
|
|
if ( parent_widget )
|
|
{
|
|
fg = parent_widget->getForegroundColor();
|
|
bg = parent_widget->getBackgroundColor();
|
|
}
|
|
else
|
|
{
|
|
fg = wcolors.dialog_fg;
|
|
bg = wcolors.dialog_bg;
|
|
}
|
|
|
|
setColor (fg, bg);
|
|
|
|
if ( size.getWidth() == 0 )
|
|
return;
|
|
|
|
for (int y{0}; y < int(size.getHeight()); y++)
|
|
{
|
|
print() << FPoint(1, 1 + y) << FString(size.getWidth(), L' ');
|
|
}
|
|
|
|
flush();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::focusNextChild()
|
|
{
|
|
if ( isDialogWidget() || ! hasParent() )
|
|
return false;
|
|
|
|
const auto& parent = getParentWidget();
|
|
|
|
if ( ! parent
|
|
|| ! parent->hasChildren()
|
|
|| parent->numOfFocusableChildren() <= 1 )
|
|
return false;
|
|
|
|
auto iter = parent->begin();
|
|
const auto last = parent->end();
|
|
|
|
while ( iter != last )
|
|
{
|
|
if ( ! (*iter)->isWidget() )
|
|
{
|
|
++iter;
|
|
continue;
|
|
}
|
|
|
|
const auto& w = static_cast<FWidget*>(*iter);
|
|
|
|
if ( w != this )
|
|
{
|
|
++iter;
|
|
continue;
|
|
}
|
|
|
|
FWidget* next{nullptr};
|
|
auto next_element = iter;
|
|
|
|
do
|
|
{
|
|
++next_element;
|
|
|
|
if ( next_element == parent->end() )
|
|
next_element = parent->begin();
|
|
|
|
if ( ! (*next_element)->isWidget() )
|
|
continue;
|
|
|
|
next = static_cast<FWidget*>(*next_element);
|
|
} while ( ! next
|
|
|| ! next->isEnabled()
|
|
|| ! next->acceptFocus()
|
|
|| ! next->isShown()
|
|
|| next->isWindowWidget() );
|
|
|
|
bool accpt = changeFocus (next, parent, fc::FocusNextWidget);
|
|
|
|
if ( ! accpt )
|
|
return false;
|
|
|
|
break; // The focus has been changed
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::focusPrevChild()
|
|
{
|
|
if ( isDialogWidget() || ! hasParent() )
|
|
return false;
|
|
|
|
const auto& parent = getParentWidget();
|
|
|
|
if ( ! parent
|
|
|| ! parent->hasChildren()
|
|
|| parent->numOfFocusableChildren() <= 1 )
|
|
return false;
|
|
|
|
auto iter = parent->end();
|
|
const auto first = parent->begin();
|
|
|
|
do
|
|
{
|
|
--iter;
|
|
|
|
if ( ! (*iter)->isWidget() )
|
|
continue;
|
|
|
|
const auto& w = static_cast<FWidget*>(*iter);
|
|
|
|
if ( w != this )
|
|
continue;
|
|
|
|
FWidget* prev{nullptr};
|
|
auto prev_element = iter;
|
|
|
|
do
|
|
{
|
|
if ( ! (*prev_element)->isWidget() )
|
|
{
|
|
--prev_element;
|
|
continue;
|
|
}
|
|
|
|
if ( prev_element == parent->begin() )
|
|
prev_element = parent->end();
|
|
|
|
--prev_element;
|
|
prev = static_cast<FWidget*>(*prev_element);
|
|
} while ( ! prev
|
|
|| ! prev->isEnabled()
|
|
|| ! prev->acceptFocus()
|
|
|| ! prev->isShown()
|
|
|| prev->isWindowWidget() );
|
|
|
|
const bool accpt = changeFocus (prev, parent, fc::FocusPreviousWidget);
|
|
|
|
if ( ! accpt )
|
|
return false;
|
|
|
|
break; // The focus has been changed
|
|
}
|
|
while ( iter != first );
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::event (FEvent* ev)
|
|
{
|
|
switch ( uInt(ev->type()) )
|
|
{
|
|
case fc::KeyPress_Event:
|
|
KeyPressEvent (static_cast<FKeyEvent*>(ev));
|
|
break;
|
|
|
|
case fc::KeyUp_Event:
|
|
onKeyUp (static_cast<FKeyEvent*>(ev));
|
|
break;
|
|
|
|
case fc::KeyDown_Event:
|
|
KeyDownEvent (static_cast<FKeyEvent*>(ev));
|
|
break;
|
|
|
|
case fc::MouseDown_Event:
|
|
emitCallback("mouse-press");
|
|
onMouseDown (static_cast<FMouseEvent*>(ev));
|
|
break;
|
|
|
|
case fc::MouseUp_Event:
|
|
emitCallback("mouse-release");
|
|
onMouseUp (static_cast<FMouseEvent*>(ev));
|
|
break;
|
|
|
|
case fc::MouseDoubleClick_Event:
|
|
onMouseDoubleClick (static_cast<FMouseEvent*>(ev));
|
|
break;
|
|
|
|
case fc::MouseWheel_Event:
|
|
emitWheelCallback(static_cast<FWheelEvent*>(ev));
|
|
onWheel (static_cast<FWheelEvent*>(ev));
|
|
break;
|
|
|
|
case fc::MouseMove_Event:
|
|
emitCallback("mouse-move");
|
|
onMouseMove (static_cast<FMouseEvent*>(ev));
|
|
break;
|
|
|
|
case fc::FocusIn_Event:
|
|
emitCallback("focus-in");
|
|
onFocusIn (static_cast<FFocusEvent*>(ev));
|
|
break;
|
|
|
|
case fc::FocusOut_Event:
|
|
emitCallback("focus-out");
|
|
onFocusOut (static_cast<FFocusEvent*>(ev));
|
|
break;
|
|
|
|
case fc::ChildFocusIn_Event:
|
|
onChildFocusIn (static_cast<FFocusEvent*>(ev));
|
|
break;
|
|
|
|
case fc::ChildFocusOut_Event:
|
|
onChildFocusOut (static_cast<FFocusEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Accelerator_Event:
|
|
onAccel (static_cast<FAccelEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Resize_Event:
|
|
onResize (static_cast<FResizeEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Show_Event:
|
|
onShow (static_cast<FShowEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Hide_Event:
|
|
onHide (static_cast<FHideEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Close_Event:
|
|
onClose (static_cast<FCloseEvent*>(ev));
|
|
break;
|
|
|
|
case fc::Timer_Event:
|
|
onTimer (static_cast<FTimerEvent*>(ev));
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onKeyPress (FKeyEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onKeyUp (FKeyEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onKeyDown (FKeyEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onMouseDown (FMouseEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onMouseUp (FMouseEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onMouseDoubleClick (FMouseEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onWheel (FWheelEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onMouseMove (FMouseEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onFocusIn (FFocusEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onFocusOut (FFocusEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onChildFocusIn (FFocusEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onChildFocusOut (FFocusEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onAccel (FAccelEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onResize (FResizeEvent* ev)
|
|
{
|
|
// The terminal was resized
|
|
root_widget->resize();
|
|
root_widget->redraw();
|
|
ev->accept();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onShow (FShowEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onHide (FHideEvent*)
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::onClose (FCloseEvent* ev)
|
|
{
|
|
ev->accept();
|
|
}
|
|
|
|
|
|
// private methods of FWidget
|
|
//----------------------------------------------------------------------
|
|
void FWidget::initRootWidget()
|
|
{
|
|
try
|
|
{
|
|
// Initialize widget lists
|
|
window_list = new FWidgetList();
|
|
dialog_list = new FWidgetList();
|
|
always_on_top_list = new FWidgetList();
|
|
close_widget = new FWidgetList();
|
|
}
|
|
catch (const std::bad_alloc& ex)
|
|
{
|
|
std::cerr << bad_alloc_str << ex.what() << std::endl;
|
|
return;
|
|
}
|
|
|
|
hideable = isCursorHideable();
|
|
flags.visible_cursor = ! hideable;
|
|
|
|
// Determine width and height of the terminal
|
|
detectTermSize();
|
|
wsize.setRect(1, 1, getDesktopWidth(), getDesktopHeight());
|
|
adjust_wsize = wsize;
|
|
woffset.setRect(0, 0, getDesktopWidth(), getDesktopHeight());
|
|
wclient_offset = woffset;
|
|
|
|
double_flatline_mask.top.resize (getWidth(), false);
|
|
double_flatline_mask.right.resize (getHeight(), false);
|
|
double_flatline_mask.bottom.resize (getWidth(), false);
|
|
double_flatline_mask.left.resize (getHeight(), false);
|
|
|
|
// Initialize default widget colors
|
|
setColorTheme();
|
|
|
|
// Default foreground and background color of the desktop/terminal
|
|
foreground_color = wcolors.term_fg;
|
|
background_color = wcolors.term_bg;
|
|
init_desktop = false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::finish()
|
|
{
|
|
if ( close_widget )
|
|
{
|
|
delete close_widget;
|
|
close_widget = nullptr;
|
|
}
|
|
|
|
if ( dialog_list )
|
|
{
|
|
delete dialog_list;
|
|
dialog_list = nullptr;
|
|
}
|
|
|
|
if ( always_on_top_list )
|
|
{
|
|
delete always_on_top_list;
|
|
always_on_top_list = nullptr;
|
|
}
|
|
|
|
if ( window_list )
|
|
{
|
|
delete window_list;
|
|
window_list = nullptr;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
inline void FWidget::insufficientSpaceAdjust()
|
|
{
|
|
// Move and shrink widget if there is not enough space available
|
|
|
|
if ( isWindowWidget() )
|
|
return;
|
|
|
|
// move left if not enough space
|
|
while ( getTermX() + int(getWidth()) - padding.right > woffset.getX2() + 2 )
|
|
{
|
|
adjust_wsize.x1_ref()--;
|
|
adjust_wsize.x2_ref()--;
|
|
|
|
if ( adjust_wsize.x1_ref() < 1 )
|
|
adjust_wsize.x1_ref() = 1;
|
|
}
|
|
|
|
// move up if not enough space
|
|
while ( getTermY() + int(getHeight()) - padding.bottom > woffset.getY2() + 2 )
|
|
{
|
|
adjust_wsize.y1_ref()--;
|
|
adjust_wsize.y2_ref()--;
|
|
|
|
if ( adjust_wsize.y1_ref() < 1 )
|
|
adjust_wsize.y1_ref() = 1;
|
|
}
|
|
|
|
// reduce the width if not enough space
|
|
while ( woffset.getX1() + int(getWidth()) - 1 > woffset.getX2() )
|
|
adjust_wsize.x2_ref()--;
|
|
|
|
if ( getWidth() < size_hints.min_width )
|
|
adjust_wsize.setWidth(size_hints.min_width);
|
|
|
|
if ( getWidth() == 0 )
|
|
adjust_wsize.setWidth(1);
|
|
|
|
// reduce the height if not enough space
|
|
while ( woffset.getY1() + int(getHeight()) - 1 > woffset.getY2() )
|
|
adjust_wsize.y2_ref()--;
|
|
|
|
if ( getHeight() < size_hints.min_height )
|
|
adjust_wsize.setHeight(size_hints.min_height);
|
|
|
|
if ( getHeight() == 0 )
|
|
adjust_wsize.setHeight(1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::KeyPressEvent (FKeyEvent* kev)
|
|
{
|
|
FWidget* widget(this);
|
|
|
|
while ( widget )
|
|
{
|
|
widget->onKeyPress(kev);
|
|
|
|
if ( ! kev->isAccepted() )
|
|
{
|
|
const FKey key = kev->key();
|
|
|
|
if ( [&] ()
|
|
{
|
|
if ( isFocusNextKey(key) )
|
|
return focusNextChild();
|
|
else if ( isFocusPrevKey(key) )
|
|
return focusPrevChild();
|
|
|
|
return false;
|
|
}() )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( kev->isAccepted()
|
|
|| widget->isRootWidget()
|
|
|| widget->getFlags().modal )
|
|
return;
|
|
|
|
widget = widget->getParentWidget();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::KeyDownEvent (FKeyEvent* kev)
|
|
{
|
|
FWidget* widget(this);
|
|
|
|
while ( widget )
|
|
{
|
|
widget->onKeyDown(kev);
|
|
|
|
if ( kev->isAccepted() || widget->isRootWidget() )
|
|
break;
|
|
|
|
widget = widget->getParentWidget();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::emitWheelCallback (const FWheelEvent* ev)
|
|
{
|
|
const int wheel = ev->getWheel();
|
|
|
|
if ( wheel == fc::WheelUp )
|
|
emitCallback("mouse-wheel-up");
|
|
else if ( wheel == fc::WheelDown )
|
|
emitCallback("mouse-wheel-down");
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setWindowFocus (bool enable)
|
|
{
|
|
// set the window focus
|
|
|
|
if ( ! enable )
|
|
return;
|
|
|
|
auto window = FWindow::getWindowWidget(this);
|
|
|
|
if ( ! window )
|
|
return;
|
|
|
|
if ( ! window->isWindowActive() )
|
|
{
|
|
bool has_raised = window->raiseWindow();
|
|
FWindow::setActiveWindow(window);
|
|
|
|
if ( has_raised && window->isVisible() && window->isShown() )
|
|
window->redraw();
|
|
}
|
|
|
|
window->setWindowFocusWidget(this);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
FWidget::FCallbackPtr FWidget::getCallbackPtr (FCallback cb_function)
|
|
{
|
|
return *cb_function.template target<FCallbackPtr>();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool FWidget::changeFocus ( FWidget* follower, const FWidget* parent
|
|
, fc::FocusTypes ft )
|
|
{
|
|
FFocusEvent out (fc::FocusOut_Event);
|
|
out.setFocusType(ft);
|
|
FApplication::sendEvent(this, &out);
|
|
|
|
FFocusEvent cfo (fc::ChildFocusOut_Event);
|
|
cfo.setFocusType(ft);
|
|
cfo.ignore();
|
|
FApplication::sendEvent(parent, &cfo);
|
|
|
|
if ( cfo.isAccepted() )
|
|
out.ignore();
|
|
|
|
if ( out.isAccepted() )
|
|
{
|
|
if ( follower == this )
|
|
return false;
|
|
|
|
follower->setFocus();
|
|
FFocusEvent cfi (fc::ChildFocusIn_Event);
|
|
FApplication::sendEvent(parent, &cfi);
|
|
|
|
FFocusEvent in (fc::FocusIn_Event);
|
|
in.setFocusType(ft);
|
|
FApplication::sendEvent(follower, &in);
|
|
|
|
if ( in.isAccepted() )
|
|
{
|
|
redraw();
|
|
follower->redraw();
|
|
updateTerminal();
|
|
flush();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::draw()
|
|
{ }
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::drawWindows()
|
|
{
|
|
// redraw windows
|
|
FChar default_char{};
|
|
default_char.ch = ' ';
|
|
default_char.fg_color = fc::Black;
|
|
default_char.bg_color = fc::Black;
|
|
default_char.attr.byte[0] = 0;
|
|
default_char.attr.byte[1] = 0;
|
|
|
|
if ( ! window_list || window_list->empty() )
|
|
return;
|
|
|
|
for (auto&& window : *window_list)
|
|
{
|
|
if ( window->isShown() )
|
|
{
|
|
auto v_win = window->getVWin();
|
|
const int w = v_win->width + v_win->right_shadow;
|
|
const int h = v_win->height + v_win->bottom_shadow;
|
|
std::fill_n (v_win->data, w * h, default_char);
|
|
window->redraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::drawChildren()
|
|
{
|
|
// draw child elements
|
|
if ( ! hasChildren() )
|
|
return;
|
|
|
|
for (auto&& child : getChildren())
|
|
{
|
|
if ( child->isWidget() )
|
|
{
|
|
auto widget = static_cast<FWidget*>(child);
|
|
|
|
if ( widget->isShown() && ! widget->isWindowWidget() )
|
|
widget->redraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setColorTheme()
|
|
{
|
|
// Sets the default color theme
|
|
|
|
if ( getMaxColor() < 16 ) // for 8 color mode
|
|
wcolors.set8ColorTheme();
|
|
else
|
|
wcolors.set16ColorTheme();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void FWidget::setStatusbarText (bool enable)
|
|
{
|
|
if ( ! isEnabled() || ! getStatusBar() )
|
|
return;
|
|
|
|
if ( enable )
|
|
{
|
|
const auto& msg = getStatusbarMessage();
|
|
const auto& curMsg = getStatusBar()->getMessage();
|
|
|
|
if ( curMsg != msg )
|
|
getStatusBar()->setMessage(msg);
|
|
}
|
|
else
|
|
{
|
|
getStatusBar()->clearMessage();
|
|
}
|
|
}
|
|
|
|
|
|
// non-member functions
|
|
//----------------------------------------------------------------------
|
|
void detectTermSize()
|
|
{
|
|
const auto& r = root_widget;
|
|
FTerm::detectTermSize();
|
|
r->adjust_wsize.setRect (1, 1, r->getDesktopWidth(), r->getDesktopHeight());
|
|
r->woffset.setRect (0, 0, r->getDesktopWidth(), r->getDesktopHeight());
|
|
r->wclient_offset.setCoordinates
|
|
(
|
|
r->padding.left,
|
|
r->padding.top,
|
|
int(r->getDesktopWidth()) - 1 - r->padding.right,
|
|
int(r->getDesktopHeight()) - 1 - r->padding.bottom
|
|
);
|
|
}
|
|
|
|
} // namespace finalcut
|