finalcut/src/fbutton.cpp

671 lines
15 KiB
C++

// fbutton.cpp
// class FButton
#include "fapp.h"
#include "fbutton.h"
#include "fstatusbar.h"
//----------------------------------------------------------------------
// class FButton
//----------------------------------------------------------------------
// constructors and destructor
//----------------------------------------------------------------------
FButton::FButton(FWidget* parent) : FWidget(parent)
{
this->init();
}
//----------------------------------------------------------------------
FButton::FButton (const FString& txt, FWidget* parent) : FWidget(parent)
{
this->init();
setText(txt);
}
//----------------------------------------------------------------------
FButton::~FButton() // destructor
{
delAccelerator (this);
}
// private methods of FButton
//----------------------------------------------------------------------
void FButton::init()
{
flags = 0;
button_down = false;
click_animation = true;
this->text = "";
setForegroundColor (wc.button_active_fg);
setBackgroundColor (wc.button_active_bg);
setHotkeyForegroundColor (wc.button_hotkey_fg);
setFocusForegroundColor (wc.button_active_focus_fg);
setFocusBackgroundColor (wc.button_active_focus_bg);
setInactiveForegroundColor (wc.button_inactive_fg);
setInactiveBackgroundColor (wc.button_inactive_bg);
if ( hasFocus() )
this->flags = FOCUS;
if ( isEnabled() )
this->flags |= ACTIVE;
updateButtonColor();
}
//----------------------------------------------------------------------
uChar FButton::getHotkey()
{
int length;
if ( text.isEmpty() )
return 0;
length = int(text.getLength());
for (int i=0; i < length; i++)
if ( (i+1 < length) && (text[uInt(i)] == '&') )
return uChar(text[uInt(++i)]);
return 0;
}
//----------------------------------------------------------------------
void FButton::setHotkeyAccelerator()
{
int hotkey = getHotkey();
if ( hotkey )
{
if ( isalpha(hotkey) || isdigit(hotkey) )
{
addAccelerator (tolower(hotkey), this);
addAccelerator (toupper(hotkey), this);
// Meta + hotkey
addAccelerator (0x20000e0+tolower(hotkey), this);
}
else
addAccelerator (getHotkey(), this);
}
else
delAccelerator(this);
}
//----------------------------------------------------------------------
void FButton::draw()
{
register wchar_t* src;
register wchar_t* dest;
wchar_t* ButtonText;
FString txt;
int d, i, j, x, mono_offset, margin;
int length, hotkeypos, hotkey_offset, space;
bool isActiveFocus, isActive, isFocus, isFlat;
bool isNonFlatShadow, isNoUnderline;
if ( text.isNull() || text.isEmpty() )
return;
length = int(text.getLength());
hotkeypos = -1;
hotkey_offset = 0;
space = int(' ');
if ( isMonochron() )
ButtonText = new wchar_t[length+3];
else
ButtonText = new wchar_t[length+1];
txt = this->text;
src = const_cast<wchar_t*>(txt.wc_str());
dest = const_cast<wchar_t*>(ButtonText);
isActiveFocus = (flags & (ACTIVE+FOCUS)) == (ACTIVE+FOCUS);
isActive = ((flags & ACTIVE) != 0);
isFocus = ((flags & FOCUS) != 0);
isFlat = ((flags & FLAT) != 0);
isNonFlatShadow = ((flags & (SHADOW+FLAT)) == SHADOW);
isNoUnderline = ((flags & NO_UNDERLINE) != 0);
setUpdateVTerm(false);
if ( button_down && click_animation )
{
// noshadow + indent one character to the right
if ( isFlat )
clearFlatBorder();
clearShadow();
setColor ( parentWidget()->getForegroundColor(),
parentWidget()->getBackgroundColor() );
for (int y=1; y <= height; y++)
{
gotoxy (xpos+xmin-1, ypos+ymin-2+y);
print (' '); // clear one left █
}
d = 1;
}
else
d = 0;
if ( ! isActive && (isMonochron() || getMaxColor() < 16) )
space = fc::MediumShade; // ▒
if ( isMonochron() && isActiveFocus )
{
txt = "<" + txt + ">";
length = int(txt.getLength());
src = const_cast<wchar_t*>(txt.wc_str());
mono_offset = 2;
}
else
mono_offset = 0;
// find hotkey position in string
// + generate a new string without the '&'-sign
for (i=0; i < length; i++)
{
if ( (i < length) && (txt[uInt(i)] == '&') && (hotkeypos == -1) )
{
hotkeypos = i;
i++;
src++;
}
*dest++ = *src++;
}
if ( hotkeypos != -1 )
hotkey_offset = 1;
if ( (length - hotkey_offset + mono_offset - hotkey_offset) <= width )
margin = 1;
else
margin = 0;
if ( isMonochron() && (isActive || isFocus) )
setReverse(true);
if ( isFlat )
{
if ( margin == 1 )
{
setColor (foregroundColor, button_bg);
for (int y=0; y <= height-1; y++)
{
gotoxy (xpos+xmin-1+d, ypos+ymin-1+y);
print (space); // full block █
}
}
if ( ! button_down )
drawFlatBorder();
}
else if ( ! isMonochron() )
{
if ( ! isActive && getMaxColor() < 16 )
setColor (button_fg, button_bg);
else
setColor (button_bg, parentWidget()->getBackgroundColor());
gotoxy (xpos+xmin-1+d, ypos+ymin-1);
for (int y=1; y <= height; y++)
{
// Cygwin terminal use IBM Codepage 850
if ( this->isCygwinTerminal() )
print (fc::FullBlock); // █
else
print (fc::RightHalfBlock); // ▐
gotoxy (xpos+xmin-1+d, ypos+ymin-1+y);
}
}
if ( ! button_down
&& ! isNewFont()
&& (isFlat || ! hasShadow() || isMonochron()) )
{
// clear the right █ from button down
setColor ( parentWidget()->getForegroundColor(),
parentWidget()->getBackgroundColor() );
for (int y=1; y <= height; y++)
{
if ( isMonochron() )
setReverse(false);
gotoxy (xpos+xmin-1+width, ypos+ymin-2+y);
print (' '); // clear right
if ( isMonochron() )
setReverse(true);
}
}
if ( hotkeypos != -1 )
length--;
i = width - length - 1;
i = int(i / 2);
if ( height > 1 )
j = int((height-1) / 2);
else
j=0;
gotoxy (xpos+xmin-1+margin+d, ypos+ymin-1+j);
setColor (button_fg, button_bg);
for (x=0; x < i; x++)
print (space); // █
if ( hotkeypos == -1 )
setCursorPos ( xpos+xmin-1+margin+i,
ypos+ymin-1+j ); // first character
else
setCursorPos ( xpos+xmin-1+margin+i+hotkeypos,
ypos+ymin-1+j ); // hotkey
if ( isMonochron() && isActiveFocus )
setBold();
for (int z=0; x < i+length && z < width; z++,x++)
{
if ( (z == hotkeypos) && isActive )
{
setColor (button_hotkey_fg, button_bg);
if ( ! isNoUnderline )
setUnderline();
print ( ButtonText[z] );
if ( ! isNoUnderline )
unsetUnderline();
setColor (button_fg, button_bg);
}
else
{
print ( ButtonText[z] );
}
}
if ( isMonochron() && isActiveFocus )
unsetBold();
for (x=i+length; x < width-1; x++)
print (space); // █
if ( height > 1 )
{
for (i=0; i < j; i++)
{
gotoxy (xpos+xmin+d, ypos+ymin-1+i);
for (int z=1; z <= width-1; z++)
print (space); // █
}
for (i=j+1; i < height; i++)
{
gotoxy (xpos+xmin+d, ypos+ymin-1+i);
for (int z=1; z <= width-1; z++)
print (space); // █
}
}
if ( isMonochron() )
setReverse(false);
if ( isNonFlatShadow && ! button_down )
{
setColor ( parentWidget()->getForegroundColor(),
parentWidget()->getBackgroundColor() );
print(' '); // restore background after button down
drawShadow();
}
setUpdateVTerm(true);
delete[] ButtonText;
if ( isFocus && statusBar() )
{
FString msg = getStatusbarMessage();
FString curMsg = statusBar()->getMessage();
if ( curMsg != msg )
{
statusBar()->setMessage(msg);
statusBar()->drawMessage();
}
}
}
//----------------------------------------------------------------------
void FButton::updateButtonColor()
{
if ( isEnabled() )
{
if ( hasFocus() )
{
button_fg = button_focus_fg;
button_bg = button_focus_bg;
}
else
{
button_fg = foregroundColor;
button_bg = backgroundColor;
}
}
else // inactive
{
button_fg = button_inactive_fg;
button_bg = button_inactive_bg;
}
}
//----------------------------------------------------------------------
void FButton::processClick()
{
emitCallback("clicked");
}
// public methods of FButton
//----------------------------------------------------------------------
void FButton::setForegroundColor (int color)
{
FWidget::setForegroundColor(color);
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::setBackgroundColor (int color)
{
FWidget::setBackgroundColor(color);
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::setHotkeyForegroundColor (int color)
{
if ( color >> 8 == 0 ) // valid colors 0..254
button_hotkey_fg = color;
}
void FButton::setFocusForegroundColor (int color)
{
if ( color >> 8 == 0 ) // valid colors 0..254
button_focus_fg = color;
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::setFocusBackgroundColor (int color)
{
if ( color >> 8 == 0 ) // valid colors 0..254
button_focus_bg = color;
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::setInactiveForegroundColor (int color)
{
if ( color >> 8 == 0 ) // valid colors 0..254
button_inactive_fg = color;
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::setInactiveBackgroundColor (int color)
{
if ( color >> 8 == 0 ) // valid colors 0..254
button_inactive_bg = color;
updateButtonColor();
}
//----------------------------------------------------------------------
void FButton::hide()
{
int fg, bg, s, f, size;
char* blank;
FWidget::hide();
fg = parentWidget()->getForegroundColor();
bg = parentWidget()->getBackgroundColor();
setColor (fg, bg);
s = hasShadow() ? 1 : 0;
f = isFlat() ? 1 : 0;
size = width + s + (f << 1);
blank = new char[size+1];
memset(blank, ' ', uLong(size));
blank[size] = '\0';
for (int y=0; y < height+s+(f << 1); y++)
{
gotoxy (xpos+xmin-1-f, ypos+ymin-1+y-f);
print (blank);
}
delete[] blank;
}
//----------------------------------------------------------------------
bool FButton::setNoUnderline(bool on)
{
if ( on )
this->flags |= NO_UNDERLINE;
else
this->flags &= ~NO_UNDERLINE;
return on;
}
//----------------------------------------------------------------------
bool FButton::setEnable(bool on)
{
FWidget::setEnable(on);
if ( on )
{
this->flags |= ACTIVE;
setHotkeyAccelerator();
}
else
{
this->flags &= ~ACTIVE;
delAccelerator (this);
}
updateButtonColor();
return on;
}
//----------------------------------------------------------------------
bool FButton::setFocus(bool on)
{
FWidget::setFocus(on);
if ( on )
{
this->flags |= FOCUS;
if ( isEnabled() )
{
if ( statusBar() )
{
FString msg = getStatusbarMessage();
FString curMsg = statusBar()->getMessage();
if ( curMsg != msg )
statusBar()->setMessage(msg);
}
}
}
else
{
this->flags &= ~FOCUS;
if ( isEnabled() && statusBar() )
statusBar()->clearMessage();
}
updateButtonColor();
return on;
}
//----------------------------------------------------------------------
bool FButton::setFlat(bool on)
{
if ( on )
this->flags |= FLAT;
else
this->flags &= ~FLAT;
return on;
}
//----------------------------------------------------------------------
bool FButton::setShadow(bool on)
{
if ( on && Encoding != fc::VT100 && Encoding != fc::ASCII )
this->flags |= SHADOW;
else
this->flags &= ~SHADOW;
return on;
}
//----------------------------------------------------------------------
bool FButton::setDown(bool on)
{
if ( button_down != on )
{
button_down = on;
redraw();
}
return on;
}
//----------------------------------------------------------------------
void FButton::onKeyPress (FKeyEvent* event)
{
int key;
if ( ! isEnabled() )
return;
key = event->key();
switch ( key )
{
case fc::Fkey_return:
case fc::Fkey_enter:
case fc::Fkey_space:
if ( click_animation )
{
setDown();
usleep(150000);
setUp();
}
processClick();
event->accept();
break;
}
}
//----------------------------------------------------------------------
void FButton::onMouseDown (FMouseEvent* event)
{
if ( event->getButton() != LeftButton )
{
setUp();
return;
}
if ( ! hasFocus() )
{
FWidget* focused_widget = getFocusWidget();
FFocusEvent out (FocusOut_Event);
FApplication::queueEvent(focused_widget, &out);
this->setFocus();
if ( focused_widget )
focused_widget->redraw();
if ( statusBar() )
statusBar()->drawMessage();
}
FPoint gPos = event->getGlobalPos();
if ( getGeometryGlobal().contains(gPos) )
setDown();
}
//----------------------------------------------------------------------
void FButton::onMouseUp (FMouseEvent* event)
{
if ( event->getButton() != LeftButton )
return;
if ( button_down )
{
setUp();
if ( getGeometryGlobal().contains(event->getGlobalPos()) )
processClick();
}
}
//----------------------------------------------------------------------
void FButton::onMouseMove (FMouseEvent* event)
{
if ( event->getButton() != LeftButton )
return;
FPoint gPos = event->getGlobalPos();
if ( click_animation )
{
if ( getGeometryGlobal().contains(gPos) )
setDown();
else
setUp();
}
}
//----------------------------------------------------------------------
void FButton::onAccel (FAccelEvent* event)
{
if ( isEnabled() )
{
if ( ! hasFocus() )
{
FWidget* focused_widget = static_cast<FWidget*>(event->focusedWidget());
FFocusEvent out (FocusOut_Event);
FApplication::queueEvent(focused_widget, &out);
setFocus();
if ( focused_widget )
focused_widget->redraw();
if ( click_animation )
setDown();
else
redraw();
if ( statusBar() )
statusBar()->drawMessage();
}
else if ( click_animation )
setDown();
if ( click_animation )
{
usleep(150000);
setUp();
}
processClick();
event->accept();
}
}
//----------------------------------------------------------------------
void FButton::onFocusIn (FFocusEvent*)
{
if ( statusBar() )
statusBar()->drawMessage();
}
//----------------------------------------------------------------------
void FButton::onFocusOut (FFocusEvent*)
{
if ( statusBar() )
{
statusBar()->clearMessage();
statusBar()->drawMessage();
}
}
//----------------------------------------------------------------------
void FButton::setText (const FString& txt)
{
this->text = txt;
if ( isEnabled() )
{
delAccelerator (this);
setHotkeyAccelerator();
}
}