Replace the switch-case in the calculator example by an STL map with method pointers

This commit is contained in:
Markus Gans 2017-12-30 21:27:17 +01:00
parent 61f824f54d
commit 3b90af9efb
15 changed files with 232 additions and 295 deletions

View File

@ -1,5 +1,7 @@
2017-12-30 Markus Gans <guru.mail@muenster.de>
* Refactoring of the FListBox mouse event handler
* Replace the switch-case in the calculator example by an STL map
with method pointers
2017-12-29 Markus Gans <guru.mail@muenster.de>
* Refactoring of the FDialog mouse event handler

View File

@ -125,7 +125,9 @@ class Calc : public FDialog
void cb_buttonClicked (FWidget*, data_ptr);
private:
// Enumeration
// Typedef and Enumeration
typedef void (Calc::*keyFunction)(lDouble&); // Method pointer
enum button
{
Sine,
@ -168,29 +170,29 @@ class Calc : public FDialog
// Methods
void drawDispay();
virtual void draw();
void clear();
void zero();
void one();
void two();
void three();
void four();
void five();
void six();
void seven();
void eight();
void nine();
void add();
void subtract();
void multiply();
void divide();
void equals();
void clear (lDouble&);
void zero (lDouble&);
void one (lDouble&);
void two (lDouble&);
void three (lDouble&);
void four (lDouble&);
void five (lDouble&);
void six (lDouble&);
void seven (lDouble&);
void eight (lDouble&);
void nine (lDouble&);
void add (lDouble&);
void subtract (lDouble&);
void multiply (lDouble&);
void divide (lDouble&);
void equals (lDouble&);
void change_sign (lDouble&);
void radix_point();
void radix_point(lDouble&);
void reciprocal (lDouble&);
void percent (lDouble&);
void pi (lDouble&);
void open_bracket();
void close_bracket();
void open_bracket (lDouble&);
void close_bracket (lDouble&);
void log_e (lDouble&);
void power_e (lDouble&);
void log_10 (lDouble&);
@ -210,6 +212,8 @@ class Calc : public FDialog
void clearInfixOperator();
void calcInfixOperator();
void adjustSize();
const wchar_t* getButtonText (int);
void mapKeyFunctions();
// Data Members
bool error;
@ -233,6 +237,7 @@ class Calc : public FDialog
std::stack<stack_data> bracket_stack;
std::map<Calc::button, Button*> calculator_buttons;
std::map<Calc::button, keyFunction> key_map;
};
#pragma pack(pop)
@ -252,47 +257,10 @@ Calc::Calc (FWidget* parent)
, input("")
, bracket_stack()
, calculator_buttons()
, key_map()
{
mapKeyFunctions();
clearInfixOperator();
const wchar_t* const button_text[Calc::NUM_OF_BUTTONS] =
{
L"&Sin",
L"&Cos",
L"&Tan",
L"1/&x",
L"&On",
L"L&n",
L"&e\x02e3",
L"&y\x02e3",
L"Sq&r",
L"&\xf7",
L"&Lg",
L"10&\x02e3",
L"&(",
L"&)",
L"&\xd7",
L"&Hyp",
L"&7",
L"&8",
L"&9",
L"&-",
L"&Arc",
L"&4",
L"&5",
L"&6",
L"&+",
L"&\x03c0",
L"&1",
L"&2",
L"&3",
L"&%",
L"&0",
L"&.",
L"",
L"&="
};
std::setlocale(LC_NUMERIC, "C");
setText ("Calculator");
setGeometry (19, 6, 37, 18);
@ -316,7 +284,7 @@ Calc::Calc (FWidget* parent)
btn->setFlat();
btn->setNoUnderline();
btn->setText(button_text[key]);
btn->setText(getButtonText(key));
btn->setDoubleFlatLine(fc::top);
btn->setDoubleFlatLine(fc::bottom);
@ -419,7 +387,7 @@ void Calc::drawDispay()
}
//----------------------------------------------------------------------
void Calc::clear()
void Calc::clear (lDouble&)
{
error = false;
arcus_mode = false;
@ -433,7 +401,7 @@ void Calc::clear()
}
//----------------------------------------------------------------------
void Calc::zero()
void Calc::zero (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -446,7 +414,7 @@ void Calc::zero()
}
//----------------------------------------------------------------------
void Calc::one()
void Calc::one (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -458,7 +426,7 @@ void Calc::one()
}
//----------------------------------------------------------------------
void Calc::two()
void Calc::two (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -470,7 +438,7 @@ void Calc::two()
}
//----------------------------------------------------------------------
void Calc::three()
void Calc::three (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -482,7 +450,7 @@ void Calc::three()
}
//----------------------------------------------------------------------
void Calc::four()
void Calc::four (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -494,7 +462,7 @@ void Calc::four()
}
//----------------------------------------------------------------------
void Calc::five()
void Calc::five (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -506,7 +474,7 @@ void Calc::five()
}
//----------------------------------------------------------------------
void Calc::six()
void Calc::six (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -518,7 +486,7 @@ void Calc::six()
}
//----------------------------------------------------------------------
void Calc::seven()
void Calc::seven (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -530,7 +498,7 @@ void Calc::seven()
}
//----------------------------------------------------------------------
void Calc::eight()
void Calc::eight (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -542,7 +510,7 @@ void Calc::eight()
}
//----------------------------------------------------------------------
void Calc::nine()
void Calc::nine (lDouble&)
{
if ( input.getLength() >= max_char )
return;
@ -554,7 +522,7 @@ void Calc::nine()
}
//----------------------------------------------------------------------
void Calc::add()
void Calc::add (lDouble&)
{
if ( ! isOperatorKey(last_key) )
calcInfixOperator();
@ -564,7 +532,7 @@ void Calc::add()
}
//----------------------------------------------------------------------
void Calc::subtract()
void Calc::subtract (lDouble&)
{
if ( ! isOperatorKey(last_key) )
calcInfixOperator();
@ -574,7 +542,7 @@ void Calc::subtract()
}
//----------------------------------------------------------------------
void Calc::multiply()
void Calc::multiply (lDouble&)
{
if ( ! isOperatorKey(last_key) )
calcInfixOperator();
@ -584,7 +552,7 @@ void Calc::multiply()
}
//----------------------------------------------------------------------
void Calc::divide()
void Calc::divide (lDouble&)
{
if ( ! isOperatorKey(last_key) )
calcInfixOperator();
@ -594,7 +562,7 @@ void Calc::divide()
}
//----------------------------------------------------------------------
void Calc::equals()
void Calc::equals (lDouble&)
{
infix_operator = last_infix_operator;
calcInfixOperator();
@ -609,10 +577,18 @@ void Calc::change_sign (lDouble& x)
}
//----------------------------------------------------------------------
void Calc::radix_point()
void Calc::radix_point (lDouble&)
{
if ( ! input.includes('.') )
if ( input.getLength() >= max_char )
return;
if ( isDataEntryKey(last_key)
&& ! input.isNull()
&& ! input.isEmpty()
&& ! input.includes('.') )
input += '.';
else
input = "0.";
}
//----------------------------------------------------------------------
@ -643,7 +619,7 @@ void Calc::pi (lDouble& x)
}
//----------------------------------------------------------------------
void Calc::open_bracket()
void Calc::open_bracket (lDouble&)
{
stack_data d = { a, infix_operator };
bracket_stack.push(d);
@ -654,7 +630,7 @@ void Calc::open_bracket()
}
//----------------------------------------------------------------------
void Calc::close_bracket()
void Calc::close_bracket (lDouble&)
{
if ( bracket_stack.empty() )
return;
@ -1017,6 +993,7 @@ void Calc::calcInfixOperator()
default:
break;
}
clearInfixOperator();
}
@ -1032,13 +1009,19 @@ void Calc::onKeyPress (FKeyEvent* ev)
case fc::Fkey_backspace:
if ( len > 0 )
{
if ( len == 1 )
input = "";
else
input = input.left(input.getLength() - 1);
lDouble& x = getValue();
if ( len == 1 )
{
input = "";
x = 0.0L;
}
else
{
input = input.left(input.getLength() - 1);
x = lDouble(std::atof(input.c_str()));
}
drawDispay();
updateTerminal();
}
@ -1078,149 +1061,10 @@ void Calc::onClose (FCloseEvent* ev)
void Calc::cb_buttonClicked (FWidget*, data_ptr data)
{
lDouble& x = getValue();
int key = *(static_cast<int*>(data));
Calc::button key = *(static_cast<Calc::button*>(data));
switch ( key )
{
case Sine:
sine(x); // sin
break;
case Cosine:
cosine(x); // cos
break;
case Tangent:
tangent(x); // tan
break;
case Reciprocal:
reciprocal(x); // 1 / x
break;
case On:
clear();
break;
case Natural_logarithm:
log_e(x); // ln
break;
case Powers_of_e:
power_e(x); // eˣ
break;
case Power:
power(x); // yˣ
break;
case Square_root:
square_root(x); // sqrt
break;
case Divide:
divide(); // ÷
break;
case Common_logarithm:
log_10(x); // lg
break;
case Powers_of_ten:
power_10(x); // 10ˣ
break;
case Parenthese_l:
open_bracket(); // (
break;
case Parenthese_r:
close_bracket(); // )
break;
case Multiply:
multiply(); // *
break;
case Hyperbolic:
hyperbolic(x); // hyp
break;
case Seven:
seven(); // 7
break;
case Eight:
eight(); // 8
break;
case Nine:
nine(); // 9
break;
case Subtract:
subtract(); // -
break;
case Arcus:
arcus(x); // arc
break;
case Four:
four(); // 4
break;
case Five:
five(); // 5
break;
case Six:
six(); // 6
break;
case Add:
add(); // +
break;
case Pi:
pi(x); // π
break;
case One:
one(); // 1
break;
case Two:
two(); // 2
break;
case Three:
three(); // 3
break;
case Percent:
percent(x); // %
break;
case Zero:
zero(); // 0
break;
case Decimal_point:
radix_point(); // .
break;
case Change_sign:
change_sign(x); // ±
break;
case Equals:
equals(); // =
break;
default:
break;
} // end of switch
// Call the key function
(this->*key_map[key])(x);
if ( ! input.isEmpty() )
{
@ -1228,7 +1072,7 @@ void Calc::cb_buttonClicked (FWidget*, data_ptr data)
x = lDouble(input.toDouble());
else
{
// remove trailing zeros
// Remove trailing zeros
while ( ! input.includes(L'e')
&& input.includes(L'.')
&& input.back() == L'0' )
@ -1255,6 +1099,89 @@ void Calc::adjustSize()
FDialog::adjustSize();
}
//----------------------------------------------------------------------
const wchar_t* Calc::getButtonText (int key)
{
static const wchar_t* const button_text[Calc::NUM_OF_BUTTONS] =
{
L"&Sin",
L"&Cos",
L"&Tan",
L"1/&x",
L"&On",
L"L&n",
L"&e\x02e3",
L"&y\x02e3",
L"Sq&r",
L"&\xf7",
L"&Lg",
L"10&\x02e3",
L"&(",
L"&)",
L"&\xd7",
L"&Hyp",
L"&7",
L"&8",
L"&9",
L"&-",
L"&Arc",
L"&4",
L"&5",
L"&6",
L"&+",
L"&\x03c0",
L"&1",
L"&2",
L"&3",
L"&%",
L"&0",
L"&.",
L"",
L"&="
};
return button_text[key];
}
//----------------------------------------------------------------------
void Calc::mapKeyFunctions()
{
key_map[Sine] = &Calc::sine; // sin
key_map[Cosine] = &Calc::cosine; // cos
key_map[Tangent] = &Calc::tangent; // tan
key_map[Reciprocal] = &Calc::reciprocal; // 1/x
key_map[On] = &Calc::clear; // On
key_map[Natural_logarithm] = &Calc::log_e; // ln
key_map[Powers_of_e] = &Calc::power_e; // eˣ
key_map[Power] = &Calc::power; // yˣ
key_map[Square_root] = &Calc::square_root; // sqrt
key_map[Divide] = &Calc::divide; // ÷
key_map[Common_logarithm] = &Calc::log_10; // lg
key_map[Powers_of_ten] = &Calc::power_10; // 10ˣ
key_map[Parenthese_l] = &Calc::open_bracket; // (
key_map[Parenthese_r] = &Calc::close_bracket; // )
key_map[Multiply] = &Calc::multiply; // *
key_map[Hyperbolic] = &Calc::hyperbolic; // hyp
key_map[Seven] = &Calc::seven; // 7
key_map[Eight] = &Calc::eight; // 8
key_map[Nine] = &Calc::nine; // 9
key_map[Subtract] = &Calc::subtract; // -
key_map[Arcus] = &Calc::arcus; // arc
key_map[Four] = &Calc::four; // 4
key_map[Five] = &Calc::five; // 5
key_map[Six] = &Calc::six; // 6
key_map[Add] = &Calc::add; // +
key_map[Pi] = &Calc::pi; // π
key_map[One] = &Calc::one; // 1
key_map[Two] = &Calc::two; // 2
key_map[Three] = &Calc::three; // 3
key_map[Percent] = &Calc::percent; // %
key_map[Zero] = &Calc::zero; // 0
key_map[Decimal_point] = &Calc::radix_point; // .
key_map[Change_sign] = &Calc::change_sign; // ±
key_map[Equals] = &Calc::equals; // =
}
//----------------------------------------------------------------------
// main part

View File

@ -54,8 +54,8 @@ int main (int argc, char* argv[])
dgl->setText ("UNIX select");
w = 20;
h = 13;
x = (app.getColumnNumber() - w) / 2;
y = (app.getLineNumber() - h) / 2;
x = (app.getDesktopWidth() - w) / 2;
y = (app.getDesktopHeight() - h) / 2;
dgl->setGeometry (x, y, w, h);
// Create a button group

View File

@ -44,8 +44,6 @@ class Keyboard : public FWidget
Keyboard::Keyboard (FWidget* parent)
: FWidget(parent)
{
resetXTermForeground();
resetXTermBackground();
wc.term_fg = fc::Default;
wc.term_bg = fc::Default;
}
@ -56,7 +54,7 @@ void Keyboard::onKeyPress (FKeyEvent* ev)
int key_id = ev->key();
bool is_last_line = false;
if ( getPrintPos().getY() == getLineNumber() )
if ( getPrintPos().getY() == getDesktopHeight() )
is_last_line = true;
print() << "Key " << getKeyName(key_id).c_str()

View File

@ -26,9 +26,12 @@
#include <final/final.h>
// global FVTerm object
// Global FVTerm object
static FVTerm* terminal;
// Global FApplication object
static FApplication* app;
// function prototype
bool keyPressed();
void term_boundaries (int&, int&);
@ -63,8 +66,8 @@ bool keyPressed()
void term_boundaries (int& x, int& y)
{
// checks and corrects the terminal boundaries
int term_width = terminal->getColumnNumber();
int term_height = terminal->getLineNumber();
int term_width = app->getDesktopWidth();
int term_height = app->getDesktopHeight();
if ( x < 0 )
x = 0;
@ -156,10 +159,11 @@ int main (int argc, char* argv[])
// Pointer to the global virtual terminal object
terminal = static_cast<FVTerm*>(&TermApp);
app = &TermApp;
// Get screen dimension
xmax = TermApp.getColumnNumber() - 1;
ymax = TermApp.getLineNumber() - 1;
xmax = TermApp.getDesktopWidth() - 1;
ymax = TermApp.getDesktopHeight() - 1;
FString line(xmax + 1, '-');
// Place the cursor in the upper left corner

View File

@ -73,8 +73,6 @@ AttribDlg::AttribDlg (FWidget* parent)
, next_button()
, back_button()
{
resetXTermForeground();
resetXTermBackground();
setText ( "A terminal attributes test ("
+ FString(getTermType())
+ ")");

View File

@ -52,8 +52,6 @@ Timer::Timer (FWidget* parent)
delTimer (id);
addTimer (250); // 250-millisecond timer
resetXTermForeground();
resetXTermBackground();
wc.term_fg = fc::Default;
wc.term_bg = fc::Default;
}
@ -74,7 +72,7 @@ void Timer::onTimer (FTimerEvent* ev)
bool is_last_line = false;
int timer_id = ev->timerId();
if ( getPrintPos().getY() == getLineNumber() )
if ( getPrintPos().getY() == getDesktopHeight() )
is_last_line = true;
setColor (short(1 + timer_id), fc::Default);

View File

@ -789,8 +789,8 @@ void MyDialog::cb_about (FWidget*, data_ptr)
//----------------------------------------------------------------------
void MyDialog::cb_terminfo (FWidget*, data_ptr)
{
int x = getColumnNumber();
int y = getLineNumber();
int x = getDesktopWidth();
int y = getDesktopHeight();
FMessageBox info1 ( "Environment"
, FString()
<< " Type: " << getTermType() << "\n"

View File

@ -181,6 +181,8 @@ class FWidget : public FVTerm, public FObject
const FRect& getGeometryWithShadow();
const FRect& getTermGeometry();
const FRect& getTermGeometryWithShadow();
int getDesktopWidth();
int getDesktopHeight();
int getFlags() const;
FPoint getCursorPos();
FPoint getPrintPos();
@ -708,6 +710,14 @@ inline const FRect& FWidget::getTermGeometryWithShadow()
return adjust_wsize_term_shadow;
}
//----------------------------------------------------------------------
inline int FWidget::getDesktopWidth()
{ return getColumnNumber(); }
//----------------------------------------------------------------------
inline int FWidget::getDesktopHeight()
{ return getLineNumber(); }
//----------------------------------------------------------------------
inline int FWidget::getFlags() const
{ return flags; }

View File

@ -1645,11 +1645,11 @@ bool FApplication::parseUrxvtMouse()
if ( y_neg || y == 0 )
y = 1;
if ( x > getColumnNumber() )
x = short(getColumnNumber());
if ( x > getDesktopWidth() )
x = short(getDesktopWidth());
if ( y > getLineNumber() )
y = short(getLineNumber());
if ( y > getDesktopHeight() )
y = short(getDesktopHeight());
new_mouse_position.setPoint (x, y);
// fill bit field with 0

View File

@ -594,9 +594,9 @@ void FMenu::adjustItems()
int FMenu::adjustX (int x_pos)
{
// Is menu outside on the right of the screen?
if ( x_pos + int(max_item_width) >= getColumnNumber() - 1 )
if ( x_pos + int(max_item_width) >= getDesktopWidth() - 1 )
{
x_pos = getColumnNumber() - int(max_item_width + 1);
x_pos = getDesktopWidth() - int(max_item_width + 1);
// Menu to large for the screen
if ( x_pos < 1 )
x_pos = 1;

View File

@ -60,7 +60,7 @@ void FMenuBar::hide()
fg = wc.term_fg;
bg = wc.term_bg;
setColor (fg, bg);
screenWidth = getColumnNumber();
screenWidth = getDesktopWidth();
if ( screenWidth < 0 )
return;
@ -92,7 +92,7 @@ void FMenuBar::resetMenu()
//----------------------------------------------------------------------
void FMenuBar::adjustSize()
{
setGeometry (1, 1, getColumnNumber(), 1, false);
setGeometry (1, 1, getDesktopWidth(), 1, false);
adjustItems();
}
@ -786,7 +786,7 @@ void FMenuBar::drawItems()
if ( isMonochron() )
setReverse(true);
screenWidth = getColumnNumber();
screenWidth = getDesktopWidth();
iter = item_list.begin();
last = item_list.end();

View File

@ -200,7 +200,7 @@ void FStatusBar::hide()
fg = wc.term_fg;
bg = wc.term_bg;
setColor (fg, bg);
screenWidth = getColumnNumber();
screenWidth = getDesktopWidth();
if ( screenWidth < 0 )
return;
@ -235,7 +235,7 @@ void FStatusBar::drawMessage()
return;
x = x_msg;
termWidth = getColumnNumber();
termWidth = getDesktopWidth();
space_offset = 1;
hasKeys = bool(! key_list.empty());
@ -352,7 +352,7 @@ void FStatusBar::clear()
//----------------------------------------------------------------------
void FStatusBar::adjustSize()
{
setGeometry (1, getLineNumber(), getColumnNumber(), 1, false);
setGeometry (1, getDesktopHeight(), getDesktopWidth(), 1, false);
}
//----------------------------------------------------------------------
@ -581,7 +581,7 @@ void FStatusBar::drawKeys()
std::vector<FStatusKey*>::const_iterator iter, last;
int screenWidth;
screenWidth = getColumnNumber();
screenWidth = getDesktopWidth();
x = 1;
if ( key_list.empty() )

View File

@ -1385,14 +1385,14 @@ void FWidget::detectTermSize()
{
FWidget* r = rootObject;
FTerm::detectTermSize();
r->adjust_wsize.setRect (1, 1, getColumnNumber(), getLineNumber());
r->offset.setRect (0, 0, getColumnNumber(), getLineNumber());
r->adjust_wsize.setRect (1, 1, getDesktopWidth(), getDesktopHeight());
r->offset.setRect (0, 0, getDesktopWidth(), getDesktopHeight());
r->client_offset.setCoordinates
(
r->padding.left,
r->padding.top,
getColumnNumber() - 1 - r->padding.right,
getLineNumber() - 1 - r->padding.bottom
getDesktopWidth() - 1 - r->padding.right,
getDesktopHeight() - 1 - r->padding.bottom
);
}
@ -2303,9 +2303,9 @@ void FWidget::init()
// Determine width and height of the terminal
detectTermSize();
wsize.setRect(1, 1, getColumnNumber(), getLineNumber());
wsize.setRect(1, 1, getDesktopWidth(), getDesktopHeight());
adjust_wsize = wsize;
offset.setRect(0, 0, getColumnNumber(), getLineNumber());
offset.setRect(0, 0, getDesktopWidth(), getDesktopHeight());
client_offset = offset;
double_flatline_mask.top.resize (uLong(getWidth()), false);