You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
507 lines
11 KiB
507 lines
11 KiB
/* |
|
* This file is a part of TTCalc - a mathematical calculator |
|
* and is distributed under the (new) BSD licence. |
|
* Author: Tomasz Sowa <t.sowa@slimaczek.pl> |
|
*/ |
|
|
|
/* |
|
* Copyright (c) 2006-2009, Tomasz Sowa |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* * Redistributions of source code must retain the above copyright notice, |
|
* this list of conditions and the following disclaimer. |
|
* |
|
* * Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* * Neither the name Tomasz Sowa nor the names of contributors to this |
|
* project may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
* THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include <windows.h> |
|
#include <ttmath/ttmath.h> |
|
#include "programresources.h" |
|
#include "resource.h" |
|
#include "messages.h" |
|
#include "bigtypes.h" |
|
|
|
|
|
namespace Pad |
|
{ |
|
HWND edit; |
|
WNDPROC old_edit_proc; |
|
std::string parse_string; |
|
int precision; |
|
HFONT font; |
|
|
|
int base_input; |
|
int base_output; |
|
bool always_scientific; |
|
int when_scientific; |
|
int rounding; |
|
bool remove_zeroes; |
|
int angle_deg_rad_grad; |
|
char decimal_point; |
|
Languages::Country country; |
|
ttmath::Objects * variables; |
|
ttmath::Objects * functions; |
|
ttmath::ErrorCode code; |
|
bool calculated; |
|
|
|
std::string res, res2; |
|
|
|
#ifndef TTCALC_PORTABLE |
|
ttmath::Parser<TTMathBig1> parser1; |
|
ttmath::Parser<TTMathBig2> parser2; |
|
ttmath::Parser<TTMathBig3> parser3; |
|
#else |
|
ttmath::Parser<TTMathBig1> parser1; |
|
#endif |
|
|
|
|
|
void PutChars(const char * str) |
|
{ |
|
SendMessage(edit, EM_REPLACESEL, true, (LPARAM)str); |
|
} |
|
|
|
|
|
void PutChars(std::string & str) |
|
{ |
|
PutChars(str.c_str()); |
|
} |
|
|
|
|
|
void PutOverflowMsg() |
|
{ |
|
PutChars(GetPrgRes()->GetLanguages()->ErrorMessage(country, ttmath::err_overflow)); |
|
PutChars("\r\n"); |
|
} |
|
|
|
|
|
template<typename ValueType> |
|
void PutResultFromParser(ttmath::Parser<ValueType> & matparser) |
|
{ |
|
unsigned int i = 0; |
|
|
|
res.clear(); |
|
res2.clear(); |
|
|
|
for(i=0 ; i<matparser.stack.size() ; ++i) |
|
{ |
|
try |
|
{ |
|
ValueType result = matparser.stack[i].value; |
|
|
|
if( result.ToString(res2, base_output, always_scientific, when_scientific, rounding, remove_zeroes, decimal_point) ) |
|
res2 = GetPrgRes()->GetLanguages()->GuiMessage(country, Languages::overflow_during_printing); |
|
} |
|
catch(...) |
|
{ |
|
res2 = GetPrgRes()->GetLanguages()->ErrorMessage(country, ttmath::err_internal_error); |
|
} |
|
|
|
res += res2; |
|
|
|
if( i < matparser.stack.size()-1 ) |
|
res += "\r\n"; |
|
} |
|
|
|
res += ' '; |
|
PutChars(res); |
|
} |
|
|
|
|
|
void PutResult() |
|
{ |
|
#ifndef TTCALC_PORTABLE |
|
|
|
switch( precision ) |
|
{ |
|
case 0: |
|
PutResultFromParser(parser1); |
|
break; |
|
|
|
case 1: |
|
PutResultFromParser(parser2); |
|
break; |
|
|
|
default: |
|
PutResultFromParser(parser3); |
|
break; |
|
} |
|
|
|
#else |
|
|
|
PutResultFromParser(parser1); |
|
|
|
#endif |
|
} |
|
|
|
|
|
|
|
// line - index of a line -- as you see it on the edit control |
|
// (if the text is wrapped then the line is larger) |
|
void GetParseString(const char * buf, int line) |
|
{ |
|
int i; |
|
|
|
int first_line_char = SendMessage(edit, EM_LINEINDEX, line, 0); |
|
// first_line_char takes into consideration \r\n characters |
|
|
|
if( first_line_char < 0 ) |
|
// something wrong |
|
return; |
|
|
|
// looking for the line |
|
for(i=0 ; i<first_line_char && buf[i]!=0 ; ++i); |
|
|
|
// looking for the beginning of the line |
|
for( ; i>0 && buf[i-1]!=10 ; --i); |
|
|
|
// copying the whole line |
|
for( ; buf[i]!=0 && buf[i]!='\r' && buf[i]!='\n' ; ++i ) |
|
parse_string += buf[i]; |
|
} |
|
|
|
|
|
void GetParseString() |
|
{ |
|
int line; |
|
|
|
parse_string.clear(); |
|
|
|
// index of a last line to parse (-1 because the ENTER has been put) |
|
line = SendMessage(edit, EM_LINEFROMCHAR, -1, 0) - 1; |
|
|
|
if( line < 0 ) |
|
// something wrong |
|
return; |
|
|
|
|
|
HLOCAL handle = (HLOCAL)SendMessage(edit, EM_GETHANDLE, 0, 0); |
|
|
|
if( handle == 0 ) |
|
// something wrong |
|
return; |
|
|
|
const char * buf = (const char*)LocalLock(handle); |
|
|
|
if( buf ) |
|
GetParseString(buf, line); |
|
|
|
LocalUnlock(handle); |
|
} |
|
|
|
|
|
template<class ValueType> |
|
void ParseString(ttmath::Parser<ValueType> & matparser) |
|
{ |
|
matparser.SetBase(base_input); |
|
matparser.SetDegRadGrad(angle_deg_rad_grad); |
|
matparser.SetFunctions(functions); |
|
matparser.SetVariables(variables); |
|
|
|
code = matparser.Parse(parse_string.c_str()); |
|
|
|
calculated = matparser.Calculated(); |
|
} |
|
|
|
|
|
void SetParameters() |
|
{ |
|
base_input = GetPrgRes()->GetBaseInput(); |
|
base_output = GetPrgRes()->GetBaseOutput(); |
|
always_scientific = GetPrgRes()->GetDisplayAlwaysScientific(); |
|
when_scientific = GetPrgRes()->GetDisplayWhenScientific(); |
|
rounding = GetPrgRes()->GetDisplayRounding(); |
|
precision = GetPrgRes()->GetPrecision(); |
|
remove_zeroes = GetPrgRes()->GetRemovingZeroes(); |
|
angle_deg_rad_grad = GetPrgRes()->GetDegRadGrad(); |
|
country = GetPrgRes()->GetLanguages()->GetCurrentLanguage(); |
|
|
|
if( GetPrgRes()->GetDecimalPoint() == 0 ) |
|
decimal_point = '.'; |
|
else |
|
decimal_point = ','; |
|
|
|
variables = GetPrgRes()->GetVariables(); |
|
functions = GetPrgRes()->GetFunctions(); |
|
} |
|
|
|
|
|
void ParseString() |
|
{ |
|
if( parse_string.empty() ) |
|
return; |
|
|
|
SetParameters(); |
|
|
|
try |
|
{ |
|
#ifndef TTCALC_PORTABLE |
|
|
|
switch( precision ) |
|
{ |
|
case 0: |
|
ParseString(parser1); |
|
break; |
|
|
|
case 1: |
|
ParseString(parser2); |
|
break; |
|
|
|
default: |
|
ParseString(parser3); |
|
break; |
|
} |
|
|
|
#else |
|
ParseString(parser1); |
|
#endif |
|
} |
|
catch(...) |
|
{ |
|
code = ttmath::err_internal_error; |
|
} |
|
|
|
|
|
if( code==ttmath::err_ok && calculated ) |
|
PutResult(); |
|
else |
|
if( code==ttmath::err_overflow ) |
|
PutOverflowMsg(); |
|
} |
|
|
|
|
|
LRESULT EditReturnPressed(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
DWORD sel_start, sel_end; |
|
|
|
SendMessage(edit, EM_GETSEL, (WPARAM)&sel_start, (LPARAM)&sel_end); |
|
|
|
if( sel_start != sel_end ) |
|
// something is selected |
|
return CallWindowProc(old_edit_proc, hwnd, msg, wParam, lParam); |
|
|
|
// putting the ENTER |
|
LRESULT res = CallWindowProc(old_edit_proc, hwnd, msg, wParam, lParam); |
|
|
|
GetParseString(); |
|
ParseString(); |
|
|
|
return res; |
|
} |
|
|
|
|
|
|
|
LRESULT EditSubclass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
switch( msg ) |
|
{ |
|
case WM_CHAR: |
|
if( wParam == VK_RETURN ) |
|
{ |
|
return EditReturnPressed(hwnd, msg, wParam, lParam); |
|
} |
|
break; |
|
} |
|
|
|
return CallWindowProc(old_edit_proc, hwnd, msg, wParam, lParam); |
|
} |
|
|
|
|
|
|
|
|
|
LRESULT PadCreate(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
edit = CreateWindow("edit", "", |
|
WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL, |
|
0, 0, 100, 100, hwnd, 0, GetPrgRes()->GetInstance(), 0); |
|
|
|
if( !edit ) |
|
return 0; |
|
|
|
old_edit_proc = (WNDPROC)SetWindowLong(edit, GWL_WNDPROC, (LONG)EditSubclass); |
|
|
|
// 65535 - 64KB |
|
// we're using some kind of messages which operates only on 64KB |
|
SendMessage(edit, EM_SETLIMITTEXT, 65535 - 5, 0); |
|
|
|
if( font != 0 ) |
|
SendMessage(edit, WM_SETFONT, (WPARAM)font, 0); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
LRESULT PadMove(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
|
{ |
|
RECT r; |
|
|
|
GetWindowRect(hwnd,&r); |
|
|
|
GetPrgRes()->SetPadXPos( r.left ); |
|
GetPrgRes()->SetPadYPos( r.top ); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
LRESULT PadSize(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
// client coordinates |
|
int cx = LOWORD(lParam); |
|
int cy = HIWORD(lParam); |
|
int fwSizeType = int(wParam); |
|
RECT r; |
|
|
|
|
|
if( fwSizeType == SIZE_MAXIMIZED ) |
|
GetPrgRes()->SetPadMaximized(true); |
|
else |
|
if( fwSizeType == SIZE_RESTORED ) |
|
GetPrgRes()->SetPadMaximized(false); |
|
|
|
MoveWindow(edit, 0, 0, cx, cy, true); |
|
|
|
if( fwSizeType != SIZE_MINIMIZED && fwSizeType != SIZE_MAXIMIZED ) |
|
{ |
|
GetWindowRect(hwnd, &r); |
|
GetPrgRes()->SetPadXSize( r.right - r.left ); |
|
GetPrgRes()->SetPadYSize( r.bottom - r.top ); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
LRESULT PadClose(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
GetPrgRes()->ShowPad( false ); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
LRESULT PadFocus(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
SetFocus(edit); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
void CreatePadMessagesTable(Messages<LRESULT> & messages) |
|
{ |
|
messages.Associate(WM_CREATE, PadCreate); |
|
messages.Associate(WM_MOVE, PadMove); |
|
messages.Associate(WM_SIZE, PadSize); |
|
messages.Associate(WM_CLOSE, PadClose); |
|
messages.Associate(WM_SETFOCUS, PadFocus); |
|
} |
|
|
|
|
|
LRESULT CALLBACK WindowPadProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
static Messages<LRESULT> messages; |
|
bool method_exists; |
|
LRESULT res; |
|
|
|
if( messages.Empty() ) |
|
// initiation |
|
CreatePadMessagesTable(messages); |
|
|
|
res = messages.Call(msg, hwnd, msg, wParam, lParam, &method_exists); |
|
|
|
if( !method_exists ) |
|
return DefWindowProc(hwnd, msg, wParam, lParam); |
|
|
|
return res; |
|
} |
|
|
|
|
|
|
|
ATOM RegisterPadClass(const char * ttcalc_pad_class_name) |
|
{ |
|
WNDCLASS w; |
|
|
|
w.style = 0; |
|
w.lpfnWndProc = WindowPadProc; |
|
w.cbClsExtra = 0; |
|
w.cbWndExtra = 0; |
|
w.hInstance = GetPrgRes()->GetInstance(); |
|
w.hIcon = LoadIcon(GetPrgRes()->GetInstance(), MAKEINTRESOURCE(IDI_ICON2)); |
|
w.hCursor = 0; |
|
w.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1); |
|
w.lpszMenuName = 0; |
|
w.lpszClassName = ttcalc_pad_class_name; |
|
|
|
return RegisterClass(&w); |
|
} |
|
|
|
|
|
} // namespace Pad |
|
|
|
|
|
|
|
|
|
|
|
bool CreatePadWindow() |
|
{ |
|
using namespace Pad; |
|
|
|
static char ttcalc_pad_class_name[] = "TTCalcPadWindow"; |
|
ATOM a = RegisterPadClass(ttcalc_pad_class_name); |
|
|
|
if( a == 0 ) |
|
return false; |
|
|
|
bool pad_maximized_from_file = GetPrgRes()->GetPadMaximized(); |
|
// CreateWindow() would change maximizing |
|
|
|
font = CreateFont(0, 0, 0, 0, FW_NORMAL, false, false, false, |
|
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, |
|
DEFAULT_QUALITY, DEFAULT_PITCH, "Ms Shell Dlg"); |
|
|
|
|
|
HWND pad = CreateWindowEx(0, ttcalc_pad_class_name, |
|
"Pad", |
|
WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW , |
|
GetPrgRes()->GetPadXPos(), GetPrgRes()->GetPadYPos(), |
|
GetPrgRes()->GetPadXSize(), GetPrgRes()->GetPadYSize(), |
|
0 /*GetPrgRes()->GetMainWindow()*/, 0, GetPrgRes()->GetInstance(), 0); |
|
|
|
GetPrgRes()->SetPadWindow(pad); |
|
GetPrgRes()->SetPadMaximized( pad_maximized_from_file ); |
|
GetPrgRes()->ShowPad( GetPrgRes()->IsPadVisible() ); |
|
|
|
return pad!=0 && edit!=0; |
|
} |
|
|
|
|
|
void DestroyPadWindow() |
|
{ |
|
using namespace Pad; |
|
|
|
DeleteObject(font); |
|
} |
|
|
|
|
|
|