Evaluate asynchronously in a separate thread
Show calculating animation
This commit is contained in:
parent
159d1fb69a
commit
969fac14a7
@ -50,6 +50,10 @@
|
||||
#define B_TRANSLATION_CONTEXT "CalcView"
|
||||
|
||||
|
||||
static const int32 kMsgCalculating = 'calc';
|
||||
static const int32 kMsgAnimateDots = 'dots';
|
||||
static const int32 kMsgDoneEvaluating = 'done';
|
||||
|
||||
//const uint8 K_COLOR_OFFSET = 32;
|
||||
const float kFontScaleY = 0.4f;
|
||||
const float kFontScaleX = 0.4f;
|
||||
@ -57,6 +61,8 @@ const float kExpressionFontScaleY = 0.6f;
|
||||
const float kDisplayScaleY = 0.2f;
|
||||
|
||||
static const bigtime_t kFlashOnOffInterval = 100000;
|
||||
static const bigtime_t kCalculatingInterval = 1000000;
|
||||
static const bigtime_t kAnimationInterval = 333333;
|
||||
|
||||
static const float kMinimumWidthCompact = 130.0f;
|
||||
static const float kMaximumWidthCompact = 400.0f;
|
||||
@ -139,7 +145,11 @@ CalcView::CalcView(BRect frame, rgb_color rgbBaseColor, BMessage* settings)
|
||||
fPopUpMenu(NULL),
|
||||
fAutoNumlockItem(NULL),
|
||||
fAudioFeedbackItem(NULL),
|
||||
fOptions(new CalcOptions())
|
||||
fOptions(new CalcOptions()),
|
||||
fEvaluateThread(-1),
|
||||
fEvaluateMessageRunner(NULL),
|
||||
fEvaluateSemaphore(B_BAD_SEM_ID),
|
||||
fEnabled(true)
|
||||
{
|
||||
// tell the app server not to erase our b/g
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
@ -172,7 +182,11 @@ CalcView::CalcView(BMessage* archive)
|
||||
fPopUpMenu(NULL),
|
||||
fAutoNumlockItem(NULL),
|
||||
fAudioFeedbackItem(NULL),
|
||||
fOptions(new CalcOptions())
|
||||
fOptions(new CalcOptions()),
|
||||
fEvaluateThread(-1),
|
||||
fEvaluateMessageRunner(NULL),
|
||||
fEvaluateSemaphore(B_BAD_SEM_ID),
|
||||
fEnabled(true)
|
||||
{
|
||||
// Do not restore the follow mode, in shelfs, we never follow.
|
||||
SetResizingMode(B_FOLLOW_NONE);
|
||||
@ -186,6 +200,8 @@ CalcView::~CalcView()
|
||||
delete fKeypad;
|
||||
delete fOptions;
|
||||
free(fKeypadDescription);
|
||||
delete fEvaluateMessageRunner;
|
||||
delete_sem(fEvaluateSemaphore);
|
||||
}
|
||||
|
||||
|
||||
@ -303,6 +319,80 @@ CalcView::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgAnimateDots:
|
||||
{
|
||||
int32 end = fExpressionTextView->TextLength();
|
||||
int32 start = end - 3;
|
||||
if (fEnabled || strcmp(fExpressionTextView->Text() + start, "...") != 0) {
|
||||
// stop the message runner
|
||||
delete fEvaluateMessageRunner;
|
||||
fEvaluateMessageRunner = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8 dot = 0;
|
||||
if (message->FindUInt8("dot", &dot) == B_OK) {
|
||||
rgb_color fontColor = fExpressionTextView->HighColor();
|
||||
rgb_color backColor = fExpressionTextView->LowColor();
|
||||
fExpressionTextView->SetStylable(true);
|
||||
fExpressionTextView->SetFontAndColor(start, end, NULL, 0, &backColor);
|
||||
fExpressionTextView->SetFontAndColor(start + dot - 1, start + dot, NULL,
|
||||
0, &fontColor);
|
||||
fExpressionTextView->SetStylable(false);
|
||||
}
|
||||
|
||||
dot++;
|
||||
if (dot == 4)
|
||||
dot = 1;
|
||||
|
||||
delete fEvaluateMessageRunner;
|
||||
BMessage animate(kMsgAnimateDots);
|
||||
animate.AddUInt8("dot", dot);
|
||||
fEvaluateMessageRunner = new (std::nothrow) BMessageRunner(
|
||||
BMessenger(this), &animate, kAnimationInterval, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgCalculating:
|
||||
{
|
||||
// calculation has taken more than 3 seconds
|
||||
if (fEnabled) {
|
||||
// stop the message runner
|
||||
delete fEvaluateMessageRunner;
|
||||
fEvaluateMessageRunner = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
BString calculating;
|
||||
calculating << B_TRANSLATE("Calculating") << "...";
|
||||
fExpressionTextView->SetText(calculating.String());
|
||||
|
||||
delete fEvaluateMessageRunner;
|
||||
BMessage animate(kMsgAnimateDots);
|
||||
animate.AddUInt8("dot", 1U);
|
||||
fEvaluateMessageRunner = new (std::nothrow) BMessageRunner(
|
||||
BMessenger(this), &animate, kAnimationInterval, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgDoneEvaluating:
|
||||
{
|
||||
_SetEnabled(true);
|
||||
rgb_color fontColor = fExpressionTextView->HighColor();
|
||||
fExpressionTextView->SetFontAndColor(NULL, 0, &fontColor);
|
||||
|
||||
const char* result;
|
||||
if (message->FindString("error", &result) == B_OK)
|
||||
fExpressionTextView->SetText(result);
|
||||
else if (message->FindString("value", &result) == B_OK)
|
||||
fExpressionTextView->SetValue(result);
|
||||
|
||||
// stop the message runner
|
||||
delete fEvaluateMessageRunner;
|
||||
fEvaluateMessageRunner = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
@ -591,7 +681,8 @@ CalcView::FrameResized(float width, float height)
|
||||
? fHeight : fHeight * kDisplayScaleY;
|
||||
BFont font(be_bold_font);
|
||||
font.SetSize(sizeDisp * kExpressionFontScaleY);
|
||||
fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL);
|
||||
rgb_color fontColor = fExpressionTextView->HighColor();
|
||||
fExpressionTextView->SetFontAndColor(&font, B_FONT_ALL, &fontColor);
|
||||
|
||||
expressionRect.OffsetTo(B_ORIGIN);
|
||||
float inset = (expressionRect.Height() - fExpressionTextView->LineHeight(0)) / 2;
|
||||
@ -736,31 +827,39 @@ CalcView::SaveSettings(BMessage* archive) const
|
||||
void
|
||||
CalcView::Evaluate()
|
||||
{
|
||||
BString expression = fExpressionTextView->Text();
|
||||
|
||||
if (expression.Length() == 0) {
|
||||
if (fExpressionTextView->TextLength() == 0) {
|
||||
beep();
|
||||
return;
|
||||
}
|
||||
|
||||
_AudioFeedback(false);
|
||||
|
||||
// evaluate expression
|
||||
BString value;
|
||||
|
||||
try {
|
||||
ExpressionParser parser;
|
||||
parser.SetDegreeMode(fOptions->degree_mode);
|
||||
value = parser.Evaluate(expression.String());
|
||||
} catch (ParseException e) {
|
||||
BString error(e.message.String());
|
||||
error << " at " << (e.position + 1);
|
||||
fExpressionTextView->SetText(error.String());
|
||||
fEvaluateThread = spawn_thread(_EvaluateThread, "Evaluate Thread",
|
||||
B_LOW_PRIORITY, this);
|
||||
if (fEvaluateThread < B_OK) {
|
||||
// failed to create evaluate thread, error out
|
||||
fExpressionTextView->SetText(strerror(fEvaluateThread));
|
||||
return;
|
||||
}
|
||||
|
||||
// render new result to display
|
||||
fExpressionTextView->SetValue(value.String());
|
||||
_AudioFeedback(false);
|
||||
_SetEnabled(false);
|
||||
// Disable input while we evaluate
|
||||
|
||||
status_t threadStatus = resume_thread(fEvaluateThread);
|
||||
if (threadStatus != B_OK) {
|
||||
// evaluate thread failed to start, error out
|
||||
fExpressionTextView->SetText(strerror(threadStatus));
|
||||
_SetEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fEvaluateMessageRunner == NULL) {
|
||||
BMessage message(kMsgCalculating);
|
||||
fEvaluateMessageRunner = new (std::nothrow) BMessageRunner(
|
||||
BMessenger(this), &message, kCalculatingInterval, 1);
|
||||
status_t runnerStatus = fEvaluateMessageRunner->InitCheck();
|
||||
if (runnerStatus != B_OK)
|
||||
printf("Evaluate Message Runner: %s\n", strerror(runnerStatus));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -895,6 +994,41 @@ CalcView::SetKeypadMode(uint8 mode)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
/*static*/ status_t
|
||||
CalcView::_EvaluateThread(void* data)
|
||||
{
|
||||
CalcView* calcView = reinterpret_cast<CalcView*>(data);
|
||||
if (calcView == NULL)
|
||||
return B_BAD_TYPE;
|
||||
|
||||
BMessenger messenger(calcView);
|
||||
if (!messenger.IsValid())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BString result;
|
||||
status_t status = acquire_sem(calcView->fEvaluateSemaphore);
|
||||
if (status == B_OK) {
|
||||
ExpressionParser parser;
|
||||
parser.SetDegreeMode(calcView->fOptions->degree_mode);
|
||||
BString expression(calcView->fExpressionTextView->Text());
|
||||
try {
|
||||
result = parser.Evaluate(expression.String());
|
||||
} catch (ParseException e) {
|
||||
result << e.message.String() << " at " << (e.position + 1);
|
||||
status = B_ERROR;
|
||||
}
|
||||
release_sem(calcView->fEvaluateSemaphore);
|
||||
} else
|
||||
result = strerror(status);
|
||||
|
||||
BMessage message(kMsgDoneEvaluating);
|
||||
message.AddString(status == B_OK ? "value" : "error", result.String());
|
||||
messenger.SendMessage(&message);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CalcView::_Init(BMessage* settings)
|
||||
{
|
||||
@ -907,6 +1041,8 @@ CalcView::_Init(BMessage* settings)
|
||||
|
||||
// fetch the calc icon for compact view
|
||||
_FetchAppIcon(fCalcIcon);
|
||||
|
||||
fEvaluateSemaphore = create_sem(1, "Evaluate Semaphore");
|
||||
}
|
||||
|
||||
|
||||
@ -1023,6 +1159,9 @@ CalcView::_ParseCalcDesc(const char* keypadDescription)
|
||||
void
|
||||
CalcView::_PressKey(int key)
|
||||
{
|
||||
if (!fEnabled)
|
||||
return;
|
||||
|
||||
assert(key < (fRows * fColumns));
|
||||
assert(key >= 0);
|
||||
|
||||
@ -1294,3 +1433,12 @@ CalcView::_IsEmbedded()
|
||||
{
|
||||
return Parent() != NULL && (Parent()->Flags() & B_DRAW_ON_CHILDREN) != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CalcView::_SetEnabled(bool enable)
|
||||
{
|
||||
fEnabled = enable;
|
||||
fExpressionTextView->MakeSelectable(enable);
|
||||
fExpressionTextView->MakeEditable(enable);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ static const float kMaximumHeightBasic = 400.0f;
|
||||
class BString;
|
||||
class BMenuItem;
|
||||
class BMessage;
|
||||
class BMessageRunner;
|
||||
class BPopUpMenu;
|
||||
class CalcOptions;
|
||||
class CalcOptionsWindow;
|
||||
@ -97,6 +98,7 @@ class CalcView : public BView {
|
||||
void SetKeypadMode(uint8 mode);
|
||||
|
||||
private:
|
||||
static status_t _EvaluateThread(void* data);
|
||||
void _Init(BMessage* settings);
|
||||
status_t _LoadSettings(BMessage* archive);
|
||||
void _ParseCalcDesc(const char* keypadDescription);
|
||||
@ -119,6 +121,8 @@ class CalcView : public BView {
|
||||
void _FetchAppIcon(BBitmap* into);
|
||||
bool _IsEmbedded();
|
||||
|
||||
void _SetEnabled(bool enable);
|
||||
|
||||
// grid dimensions
|
||||
int16 fColumns;
|
||||
int16 fRows;
|
||||
@ -161,6 +165,11 @@ class CalcView : public BView {
|
||||
|
||||
// calculator options.
|
||||
CalcOptions* fOptions;
|
||||
|
||||
thread_id fEvaluateThread;
|
||||
BMessageRunner* fEvaluateMessageRunner;
|
||||
sem_id fEvaluateSemaphore;
|
||||
bool fEnabled;
|
||||
};
|
||||
|
||||
#endif // _CALC_VIEW_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user