/* * This file is a part of TTCalc - a mathematical calculator * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * 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 #include #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 parser1; ttmath::Parser parser2; ttmath::Parser parser3; #else ttmath::Parser 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 void PutResultFromParser(ttmath::Parser & matparser) { unsigned int i = 0; res.clear(); res2.clear(); for(i=0 ; iGetLanguages()->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 ; i0 && 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 void ParseString(ttmath::Parser & 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 & 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 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); }