finalcut/src/fstatusbar.cpp

733 lines
16 KiB
C++
Raw Normal View History

2017-11-04 07:03:53 +01:00
/***********************************************************************
* fstatusbar.cpp - Widget FStatusBar and FStatusKey *
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2014-2018 Markus Gans *
2017-11-04 07:03:53 +01:00
* *
* 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/>. *
***********************************************************************/
2015-05-23 13:35:12 +02:00
2017-09-11 03:06:02 +02:00
#include <vector>
#include "final/fstatusbar.h"
2015-05-23 13:35:12 +02:00
namespace finalcut
{
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
// class FStatusKey
//----------------------------------------------------------------------
// constructor and destructor
//----------------------------------------------------------------------
2015-09-22 04:18:20 +02:00
FStatusKey::FStatusKey(FWidget* parent)
: FWidget(parent)
, key(0)
, text()
, active(false)
, mouse_focus(false)
, bar(0)
2015-05-23 13:35:12 +02:00
{
init (parent);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
2017-03-17 22:59:06 +01:00
FStatusKey::FStatusKey (int k, const FString& txt, FWidget* parent)
2015-09-22 04:18:20 +02:00
: FWidget(parent)
, key(k)
, text(txt)
, active(false)
, mouse_focus(false)
, bar(0)
2015-05-23 13:35:12 +02:00
{
init (parent);
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
FStatusKey::~FStatusKey() // destructor
{
if ( getConnectedStatusbar() )
getConnectedStatusbar()->remove(this);
2015-11-12 01:33:16 +01:00
delAccelerator();
2015-05-23 13:35:12 +02:00
}
// public methods of FStatusKey
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2015-09-20 05:44:50 +02:00
void FStatusKey::onAccel (FAccelEvent* ev)
2015-05-23 13:35:12 +02:00
{
if ( isActivated() )
return;
setActive();
if ( getConnectedStatusbar() )
getConnectedStatusbar()->redraw();
ev->accept();
// unset after get back from callback
unsetActive();
if ( getConnectedStatusbar() )
getConnectedStatusbar()->redraw();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
2015-10-17 19:40:43 +02:00
void FStatusKey::setActive()
2015-05-23 13:35:12 +02:00
{
2015-09-22 04:18:20 +02:00
active = true;
2015-05-23 13:35:12 +02:00
processActivate();
}
//----------------------------------------------------------------------
bool FStatusKey::setMouseFocus(bool on)
{
if ( on == mouse_focus )
return true;
return mouse_focus = on;
2015-05-23 13:35:12 +02:00
}
// private methods of FStatusKey
//----------------------------------------------------------------------
void FStatusKey::init (FWidget* parent)
{
2017-09-11 03:06:02 +02:00
setGeometry (1, 1, 1, 1);
if ( parent && parent->isInstanceOf("FStatusBar") )
{
setConnectedStatusbar (static_cast<FStatusBar*>(parent));
if ( getConnectedStatusbar() )
getConnectedStatusbar()->insert(this);
}
}
//----------------------------------------------------------------------
void FStatusKey::processActivate()
{
emitCallback("activate");
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
// class FStatusBar
//----------------------------------------------------------------------
// constructor and destructor
//----------------------------------------------------------------------
2015-09-22 04:18:20 +02:00
FStatusBar::FStatusBar(FWidget* parent)
: FWindow(parent)
, key_list()
2015-09-22 04:18:20 +02:00
, text("")
, mouse_down()
, screenWidth(80)
, keyname_len(0)
2015-09-22 04:18:20 +02:00
, x(-1)
, x_msg(-1)
2015-05-23 13:35:12 +02:00
{
2015-09-22 04:18:20 +02:00
init();
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
2017-09-11 03:06:02 +02:00
FStatusBar::~FStatusBar() // destructor
2015-05-23 13:35:12 +02:00
{
// delete all keys
if ( ! key_list.empty() )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::iterator iter;
iter = key_list.begin();
2015-05-23 13:35:12 +02:00
while ( iter != key_list.end() )
2015-05-23 13:35:12 +02:00
{
(*iter)->setConnectedStatusbar(0);
2015-05-23 13:35:12 +02:00
delAccelerator (*iter);
iter = key_list.erase(iter);
2015-05-23 13:35:12 +02:00
}
}
2016-07-28 01:04:27 +02:00
setStatusBar(0);
2015-05-23 13:35:12 +02:00
}
// public methods of FStatusBar
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
2017-03-17 22:59:06 +01:00
void FStatusBar::setMessage (const FString& mgs)
2015-05-23 13:35:12 +02:00
{
text = mgs;
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
bool FStatusBar::hasActivatedKey()
{
if ( ! key_list.empty() )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::const_iterator iter, last;
iter = key_list.begin();
last = key_list.end();
while ( iter != last )
2015-05-23 13:35:12 +02:00
{
if ( (*iter)->isActivated() )
return true;
++iter;
2015-05-23 13:35:12 +02:00
}
}
return false;
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FStatusBar::hide()
{
short fg, bg;
char* blank;
FWindow::hide();
fg = wc.term_fg;
bg = wc.term_bg;
setColor (fg, bg);
screenWidth = getDesktopWidth();
if ( screenWidth < 0 )
return;
2017-08-12 22:55:29 +02:00
try
{
blank = new char[uInt(screenWidth) + 1];
2017-08-12 22:55:29 +02:00
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
std::memset(blank, ' ', uLong(screenWidth));
blank[screenWidth] = '\0';
setPrintPos (1, 1);
print (blank);
delete[] blank;
}
//----------------------------------------------------------------------
void FStatusBar::drawMessage()
2015-05-23 13:35:12 +02:00
{
int termWidth, space_offset;
bool isLastActiveFocus, hasKeys;
if ( ! (isVisible() ) )
2015-05-23 13:35:12 +02:00
return;
if ( x < 0 || x_msg < 0 )
2015-05-23 13:35:12 +02:00
return;
x = x_msg;
termWidth = getDesktopWidth();
space_offset = 1;
hasKeys = bool(! key_list.empty());
2015-05-23 13:35:12 +02:00
if ( hasKeys )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::const_iterator iter = key_list.end();
isLastActiveFocus = bool ( (*(iter - 1))->isActivated()
2017-11-26 22:37:18 +01:00
|| (*(iter - 1))->hasMouseFocus() );
}
else
isLastActiveFocus = false;
2015-05-23 13:35:12 +02:00
if ( isLastActiveFocus )
space_offset = 0;
2015-05-23 13:35:12 +02:00
setColor (wc.statusbar_fg, wc.statusbar_bg);
setPrintPos (x, 1);
if ( isMonochron() )
setReverse(true);
if ( x + space_offset + 3 < termWidth )
{
if ( text )
{
if ( ! isLastActiveFocus )
{
x++;
print (' ');
}
if ( hasKeys )
{
x += 2;
print (fc::BoxDrawingsVertical); // │
print (' ');
}
int msg_length = int(getMessage().getLength());
x += msg_length;
if ( x - 1 <= termWidth )
print (getMessage());
else
{
2017-12-21 00:25:58 +01:00
// Print ellipsis
print ( getMessage().left(uInt(msg_length + termWidth - x - 1)) );
print ("..");
}
}
}
for (int i = x; i <= termWidth; i++)
print (' ');
if ( isMonochron() )
setReverse(false);
}
//----------------------------------------------------------------------
void FStatusBar::insert (FStatusKey* skey)
{
key_list.push_back (skey);
addAccelerator (skey->getKey(), skey);
skey->addCallback
(
"activate",
F_METHOD_CALLBACK (this, &FStatusBar::cb_statuskey_activated)
);
}
//----------------------------------------------------------------------
void FStatusBar::remove (FStatusKey* skey)
{
std::vector<FStatusKey*>::iterator iter;
delAccelerator (skey);
if ( key_list.empty() )
return;
iter = key_list.begin();
while ( iter != key_list.end() )
{
if ( (*iter) == skey )
{
iter = key_list.erase(iter);
skey->setConnectedStatusbar(0);
break;
}
else
++iter;
}
}
//----------------------------------------------------------------------
void FStatusBar::remove (int pos)
{
if ( int(getCount()) < pos )
return;
key_list.erase (key_list.begin() + pos - 1);
}
//----------------------------------------------------------------------
void FStatusBar::clear()
{
key_list.clear();
}
//----------------------------------------------------------------------
void FStatusBar::adjustSize()
{
setGeometry (1, getDesktopHeight(), getDesktopWidth(), 1, false);
}
//----------------------------------------------------------------------
void FStatusBar::onMouseDown (FMouseEvent* ev)
{
if ( hasActivatedKey() )
return;
if ( ev->getButton() != fc::LeftButton )
{
mouse_down = false;
if ( ! key_list.empty() )
{
std::vector<FStatusKey*>::const_iterator iter, last;
iter = key_list.begin();
last = key_list.end();
while ( iter != last )
{
(*iter)->unsetMouseFocus();
++iter;
}
}
redraw();
return;
}
if ( mouse_down )
return;
mouse_down = true;
if ( ! key_list.empty() )
{
std::vector<FStatusKey*>::const_iterator iter, last;
int X = 1;
iter = key_list.begin();
last = key_list.end();
while ( iter != last )
{
int x1 = X
, kname_len = int(getKeyName((*iter)->getKey()).getLength())
, txt_length = int((*iter)->getText().getLength())
, x2 = x1 + kname_len + txt_length + 1
, mouse_x = ev->getX()
, mouse_y = ev->getY();
2015-05-23 13:35:12 +02:00
if ( mouse_x >= x1
2017-11-26 22:37:18 +01:00
&& mouse_x <= x2
&& mouse_y == 1
&& ! (*iter)->hasMouseFocus() )
2015-05-23 13:35:12 +02:00
{
(*iter)->setMouseFocus();
2015-09-22 04:18:20 +02:00
redraw();
2015-05-23 13:35:12 +02:00
}
2015-05-23 13:35:12 +02:00
X = x2 + 2;
++iter;
}
}
}
//----------------------------------------------------------------------
2015-09-20 05:44:50 +02:00
void FStatusBar::onMouseUp (FMouseEvent* ev)
2015-05-23 13:35:12 +02:00
{
if ( hasActivatedKey() )
return;
2016-01-17 02:57:08 +01:00
if ( ev->getButton() != fc::LeftButton )
2015-05-23 13:35:12 +02:00
return;
if ( mouse_down )
{
mouse_down = false;
if ( ! key_list.empty() )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::const_iterator iter, last;
2015-05-23 13:35:12 +02:00
int X = 1;
iter = key_list.begin();
last = key_list.end();
2015-05-23 13:35:12 +02:00
while ( iter != last )
2015-05-23 13:35:12 +02:00
{
int x1 = X
, kname_len = int(getKeyName((*iter)->getKey()).getLength())
, txt_length = int((*iter)->getText().getLength())
, x2 = x1 + kname_len + txt_length + 1;
2015-05-23 13:35:12 +02:00
if ( (*iter)->hasMouseFocus() )
{
2015-09-28 04:31:29 +02:00
int mouse_x, mouse_y;
2015-05-23 13:35:12 +02:00
(*iter)->unsetMouseFocus();
2015-09-28 04:31:29 +02:00
mouse_x = ev->getX();
mouse_y = ev->getY();
2015-05-23 13:35:12 +02:00
if ( mouse_x >= x1 && mouse_x <= x2 && mouse_y == 1 )
(*iter)->setActive();
// unset after get back from callback
(*iter)->unsetActive();
2015-09-22 04:18:20 +02:00
redraw();
2015-05-23 13:35:12 +02:00
}
2015-05-23 13:35:12 +02:00
X = x2 + 2;
++iter;
}
}
}
}
//----------------------------------------------------------------------
2015-09-20 05:44:50 +02:00
void FStatusBar::onMouseMove (FMouseEvent* ev)
2015-05-23 13:35:12 +02:00
{
if ( hasActivatedKey() )
return;
2016-01-17 02:57:08 +01:00
if ( ev->getButton() != fc::LeftButton )
2015-05-23 13:35:12 +02:00
return;
if ( mouse_down && ! key_list.empty() )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::const_iterator iter, last;
2015-05-23 13:35:12 +02:00
bool focus_changed = false;
int X = 1;
iter = key_list.begin();
last = key_list.end();
2015-05-23 13:35:12 +02:00
while ( iter != last )
2015-05-23 13:35:12 +02:00
{
int x1 = X
, kname_len = int(getKeyName((*iter)->getKey()).getLength())
, txt_length = int((*iter)->getText().getLength())
, x2 = x1 + kname_len + txt_length + 1
, mouse_x = ev->getX()
, mouse_y = ev->getY();
if ( mouse_x >= x1
2017-11-26 22:37:18 +01:00
&& mouse_x <= x2
&& mouse_y == 1 )
2015-05-23 13:35:12 +02:00
{
if ( ! (*iter)->hasMouseFocus() )
{
(*iter)->setMouseFocus();
focus_changed = true;
}
}
else
{
if ( (*iter)->hasMouseFocus() )
{
(*iter)->unsetMouseFocus();
focus_changed = true;
}
}
2015-05-23 13:35:12 +02:00
X = x2 + 2;
++iter;
}
2015-05-23 13:35:12 +02:00
if ( focus_changed )
2015-09-22 04:18:20 +02:00
redraw();
2015-05-23 13:35:12 +02:00
}
}
//----------------------------------------------------------------------
void FStatusBar::cb_statuskey_activated (FWidget* widget, data_ptr)
2015-05-23 13:35:12 +02:00
{
if ( ! key_list.empty() )
2015-05-23 13:35:12 +02:00
{
std::vector<FStatusKey*>::const_iterator iter, last;
FStatusKey* statuskey = static_cast<FStatusKey*>(widget);
iter = key_list.begin();
last = key_list.end();
2015-05-23 13:35:12 +02:00
while ( iter != last )
2015-05-23 13:35:12 +02:00
{
if ( (*iter) != statuskey && (*iter)->isActivated() )
(*iter)->unsetActive();
2015-05-23 13:35:12 +02:00
++iter;
}
}
if ( isVisible() && isShown() )
redraw();
2015-05-23 13:35:12 +02:00
}
// private methods of FStatusBar
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FStatusBar::init()
2015-05-23 13:35:12 +02:00
{
FWidget* r = getRootWidget();
int w = r->getWidth();
int h = r->getHeight();
// initialize geometry values
setGeometry (1, h, w, 1, false);
setAlwaysOnTop();
setStatusBar(this);
ignorePadding();
mouse_down = false;
2015-05-23 13:35:12 +02:00
if ( getRootWidget() )
getRootWidget()->setBottomPadding(1, true);
setForegroundColor (wc.statusbar_fg);
setBackgroundColor (wc.statusbar_bg);
unsetFocusable();
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FStatusBar::draw()
{
drawKeys();
drawMessage();
}
2015-05-23 13:35:12 +02:00
//----------------------------------------------------------------------
void FStatusBar::drawKeys()
{
keyList::const_iterator iter, last;
screenWidth = getDesktopWidth();
x = 1;
if ( key_list.empty() )
2015-05-23 13:35:12 +02:00
{
x_msg = 1;
return;
2015-05-23 13:35:12 +02:00
}
setPrintPos (1, 1);
2015-05-23 13:35:12 +02:00
if ( isMonochron() )
setReverse(true);
iter = key_list.begin();
last = key_list.end();
while ( iter != last )
2015-05-23 13:35:12 +02:00
{
keyname_len = int(getKeyName((*iter)->getKey()).getLength());
if ( x + keyname_len + 2 < screenWidth )
2015-05-23 13:35:12 +02:00
{
if ( (*iter)->isActivated() || (*iter)->hasMouseFocus() )
drawActiveKey (iter);
2015-05-23 13:35:12 +02:00
else
drawKey (iter);
2015-05-23 13:35:12 +02:00
}
else
{
setColor (wc.statusbar_fg, wc.statusbar_bg);
for (; x <= screenWidth; x++)
print (' ');
2015-05-23 13:35:12 +02:00
}
++iter;
2015-05-23 13:35:12 +02:00
}
if ( isMonochron() )
setReverse(false);
x_msg = x;
2015-05-23 13:35:12 +02:00
}
//----------------------------------------------------------------------
void FStatusBar::drawKey (keyList::const_iterator iter)
{
// Draw not active key
int txt_length;
FStatusKey* item = *iter;
setColor (wc.statusbar_hotkey_fg, wc.statusbar_hotkey_bg);
x++;
print (' ');
x += keyname_len;
print (getKeyName(item->getKey()));
setColor (wc.statusbar_fg, wc.statusbar_bg);
x++;
print ('-');
txt_length = int(item->getText().getLength());
x += txt_length;
if ( x - 1 <= screenWidth )
print (item->getText());
else
{
// Print ellipsis
print ( item->getText()
.left(uInt(txt_length + screenWidth - x - 1)) );
print ("..");
}
if ( iter + 1 != key_list.end()
&& ( (*(iter + 1))->isActivated() || (*(iter + 1))->hasMouseFocus() )
&& x + int(getKeyName((*(iter + 1))->getKey()).getLength()) + 3
< screenWidth )
{
// Next element is active
if ( isMonochron() )
setReverse(false);
if ( hasHalfBlockCharacter() )
{
setColor (wc.statusbar_active_fg, wc.statusbar_active_bg);
print (fc::LeftHalfBlock); // ▐
}
else
print (' ');
x++;
if ( isMonochron() )
setReverse(true);
}
else if ( iter + 1 != key_list.end() && x < screenWidth )
{
// Not the last element
setColor (wc.statusbar_separator_fg, wc.statusbar_bg);
x++;
print (fc::BoxDrawingsVertical); // │
}
}
//----------------------------------------------------------------------
void FStatusBar::drawActiveKey (keyList::const_iterator iter)
{
// Draw active key
int txt_length;
FStatusKey* item = *iter;
if ( isMonochron() )
setReverse(false);
setColor ( wc.statusbar_active_hotkey_fg
, wc.statusbar_active_hotkey_bg );
x++;
print (' ');
x += keyname_len;
print (getKeyName(item->getKey()));
setColor (wc.statusbar_active_fg, wc.statusbar_active_bg);
x++;
print ('-');
txt_length = int(item->getText().getLength());
x += txt_length;
if ( x <= screenWidth )
{
print (item->getText());
x++;
print (fc::RightHalfBlock); // ▌
}
else
{
// Print ellipsis
print ( item->getText()
.left(uInt(txt_length + screenWidth - x - 1)) );
print ("..");
}
if ( isMonochron() )
setReverse(true);
}
} // namespace finalcut