Giter VIP home page Giter VIP logo

pymanujan's Introduction

Pymanujan ♾️

Python powered calculator; but without eval().

Introduction

Whole code is written in Python. New developers and contribtors can easily go through the code to understand the logic behind the program. I tried to include as much comments and documentations within the code itself. Feel free to ping me for any queries. Best-suited for new developers this simple program provides a stage for develpoment of one's skill, expertise and familiarity of Python programming language.

Pymanujan can do these now:

  • ➕ Addition
  • ➖ Subtraction
  • ✖️ Multiplication
  • ➗ Division
  • ⭐ Exponentiation
  • 🔺 Trigonometric functions
  • 🔻 Inverse trigonometric functions
  • ❗ Factorial
  • 🌲 Logarithms

User interface of Pymanujan (v2.0) 🖥️

Pymanujan (v2 0)

Build Pymanujan yourself:

Clone this repository from Github. Then create a virtual-environment and install the dependencies.

git clone https://github.com/tsadarsh/Pymanujan.git
cd ./Pymanujan
python3 -m venv env
source env/bin/activate
python -m pip install -r requirements.txt
python main.py

Contribution 🤓

All are welcome to contribute to this project. Create new Issue for feature-request or bug reports. Implemented a new feature? Awesome give a PR.

Goal is to improve expertise on Python 🐍.

"Though a calculator app is no path-breaking project to work on, it gives confidence to a new-devloper the abilty to build something from scratch" -maddypie

pymanujan's People

Contributors

smm10 avatar tsadarsh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

pymanujan's Issues

Create feature to 'Copy' result by click of 'Copy' button

Currently 'Copy' button does not do anything. Using tkinter's clipboard_append() destroys the content on clipboard once the app is closed. Find a workaround or use any other method to implement this functionality.

If the current content being displayed is an expression, 'Copy' should copy the whole expression to the clipboard.
If the current content being displayed is the calculated result, the content after Ans: should be copied to clipboard.

Emphasis on having the copied value on clipboard even after the app is closed.

Binding buttons in for cycle

Refers to #3.

Today's update:

  • Function __put_dot updated.

  • New class for GUI added.

  • Fatal errors in GUI:

    • Every button entry (excluding '=') results in display of character '0'

I came to a conclusion that ttk.Button with same name rebinds the command to latest definition. Hence this code chunk rebinds every button command to '0' (last entry):

...
    __layout = ['*', '/', 'C', 'AC',
                '9', '8', '7', '-',
                '6', '5', '4', '+',
                '3', '2', '1', '+/-',
                '.', '0', '=']
    ...
# ln: 170
        ''' Control Binding '''
        buttons = []
        for bt_text in self.__layout[:-1]:
            bt = ttk.Button(master=keypad)
            bt['text'] = bt_text
            bt['command'] = lambda: (self.bt_cmd.into_storage(bt_text),
                                     self.bt_cmd.show_storage(self.DISPLAY))
            buttons.append(bt)
...

Is this conclusion relevant or am I getting it wrong?

The problem is we trying to access the variable from outer scope. More detailed explanation: here.

Thus, the solution is:

    """
    __layout = ['*', '/', 'C', 'AC',
                    '9', '8', '7', '-',
                    '6', '5', '4', '+',
                    '3', '2', '1', '+/-',
                    '.', '0', '=']
    """
    ...
    def __bind_buttons(self):
        functions = {character: (lambda character=character: self.__storage.into_storage(character)) for character
                     in self.__layout if character != "="}
        functions["="] = lambda: self.__refresh_display(self.__calculator.calculate(self.__storage))
        self.__buttons = {character: ttk.Button(command=functions[character], text=character, master=self.__keypad) for
                          character in self.__layout}

Some guidelines to improve code quality

Hello!
I've checked out your project and I want to suggest you some refactoring tips

  1. Make a MainWindow class and simply avoid using global variables
class MainWindow(Tk):
  styler = ttk.Style()
  storage = ...
  current_left = ...

  ....

and you can configure styles and other gui things in init method, for ex.:

  ...
  def __init__(self):
    super().__init__()
    self.title("PyCalc")
    ...
    styler.theme_use("calm")
    ...

and next you can use storage or temporary operand variables in any method here or directly pass it in other objects, for ex.:

  def put_in_storage(): # cout
    storage[-1] = ...
    ... 

This step needs to separate the gui functionality and the core program logic so you can independently change them.

  1. Define a class with all control elements
class Controls:
  operators = [....]
  special = [...]
  ...

and make an instance of this class a field of your MainWindow class. Using this approach you can easily bind control elements like:

  def control_binding():
    for control_element in [str(x) for x in range(10)]: # or your controls list
      some_button= ttk.Button(keypad, text=control_element, command=lambda: cout(control_element))
      # or append this buttons to button list and like button_list.append(some_button)
    

instead of:

nine = ttk.Button(keypad, text='9', command=lambda: cout('9'))
eight = ttk.Button(keypad, text='8', command=lambda: cout('8'))
seven = ttk.Button(keypad, text='7', command=lambda: cout('7'))
six = ttk.Button(keypad, text='6', command=lambda: cout('6'))
five = ttk.Button(keypad, text='5', command=lambda: cout('5'))
four = ttk.Button(keypad, text='4', command=lambda: cout('4'))
three = ttk.Button(keypad, text='3', command=lambda: cout('3'))
two = ttk.Button(keypad, text='2', command=lambda: cout('2'))
one = ttk.Button(keypad, text='1', command=lambda: cout('1'))
zero = ttk.Button(keypad, text='0', command=lambda: cout('0'))

I think you would got a point.

  1. Make a class with calc methods
    This is another step to separate your program components. Also you can make an instanse of this class as a field of MainWindow to have a direct access.

  2. Elimenate nested "if" instructions
    For ex.:

if cond1:
  if cond2:
    if cond3:
     ...
    else:
  ..elses..

can be written as:

if not cond1:
   ...
   return
if not cond2:
  ...
  return

I think you would got a point.

I recommend you to read "Clean code" by Robert Martin. There are a lot of guidelines to improve your code quality with perfect argumentation.

Good luck!

Dynamic font size in display label

Currently display_label is hard coded Times 20 font. When characters to be displayed exceeds 17, initial characters are sliced off to prevent breaking of display_label (TLabel) widget (grid : row=0, column=0, columnspan=4).

A better approach would be to reduce the font size when characters to be displayed exceeds the width of display_label.
Note: Currently resizing the window in disabled. So the width of display_label is constant.

UI Design improvements (Styles and Themes)

UI design overhaul

This issue calls for discussion and PRs for various design upgrades to PyClac Graphical User Interface. Feel free to post your work and ideas in this thread.
Listed below are proposed areas for overhaul:

    • 🎨 Implementation of styles
    • 🎨 Additional color schemes
    • 🏗️ Button geometry
    • 🔉 Sound feedback during UI interaction
    • 🖊️ Font styles

Implementation of styles/Additional color schemes 🎨

PyCalc currently implements a standard theme in default_style_settings. New themes to be named as <name_of_theme>_style_settings under class GUI. Each widget's style can be chaged by calling styler.configure method with following arguments:

def newStyle_style_settings(self):
    self.styler.configure("TLabel",  [widget specific style settings...]) # for ttk.Label
    self.styler.configure("TButton",  [widget specific style settings...]) # for ttk.Button
    self.styler.configure("NewButton.TLabel",  [widget specific style settings...]) # style for specific button

Widget specific commands can be found here.

Button geometry 🏗️

Button geometry is a bit involved. Each widget in tkinter is made of many elements. For example possible button elements can be represented like this:

Possible elements of Button

TkDocs is an excellent place to have your feet dipped into widget elements its layout.

Sound feedback during UI interaction 🔉

Currently PyCalc has no audio feedback during keypad and button interaction. This area is open for implemneation ideas and sound selection.

Font styles 🖊️

All the available font families in tkinter can be obtained from font.families. Refer here for getting font families.
Note: tkinter named fonts are platform specific.

Switching Label to Entry

Separate issue for #3 .

Switching from Label to Entry seems more user-friendly but there are two options. The first one is to prohibit typing invalid symbols and the second one is to validate expression when user press "=".

Which one do you prefer?

Suggestions to imporve GUI

Currently the app's GUI is built on Python's themed tkinter standard library. Developers having good expertise on UI and familiarity with other GUI library are welcomed to suggest better implementations or if needed best practices on re-writing the whole GUI.
Cross-platform compatibility is to be taken into account.

Num-pad and keyboard bindings

Number pad bindings in Tkinter seem to be platform-specific 💻 . Please refer to query1 and query2, some discussions happened over there.

The following structure seems to be a good start to bind keysboard inputs ⌨️ :

def callback(e):
    if e.char in _layout.values():
        button_invoke(e.char)

gui_instance.bind("<Key>", callback)

Further where-to-implement discussion to re-use _layout defined in GUI._create_buttons is much needed.

Feature Advanced mode

Currently, there is no option for advanced/extended mode for additional operations. PyCalc is limited to addition, subtraction, multiplication, division, and decimal operations only. The goal is to extend to more functionalities by toggling an advanced or extended button. The following features may be taken into consideration:

    • brackets-open/close ( )
      • From cec1276 brackets are entred using the keyboard in Basic mode.
      • Added in commit be65811.
    • factorial !
      • Logic to be added.
    • logarithm log: -> provide option for changing base 10
      • Logic to be added.
    • trigonometric operations sin cos tan -> provide option for changing radians to degrees
      • Logic to be added.

Discussion on implementation ideas is welcome 😄 .

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.