├── .gitignore
├── LICENSE
├── build.bat
├── docs
├── LICENSE
├── README.md
└── screenshot.png
├── requirements.txt
└── src
├── calculations.py
├── config.json
├── icon.ico
└── main.py
/.gitignore:
--------------------------------------------------------------------------------
1 | src/__pycache__/calculations.cpython-310.pyc
2 | desktop.ini
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Futura Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | cd src
2 | rmdir /s /q dist
3 | pyinstaller main.py --onedir --windowed --collect-data sv_ttk --icon "icon.ico" --add-data "config.json;."
4 | del main.spec
5 | xcopy icon.ico dist
6 | cd dist
7 | ren main.exe FluxCalc.exe
--------------------------------------------------------------------------------
/docs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 HuyHung1408
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
FluxCalc
9 |
10 |
11 |
12 |
13 | ## About FluxCalc:
14 | A very simple calculator with a modern UI made in Python thanks to the stunning [Sun-Valley-ttk-theme](https://github.com/rdbende/Sun-Valley-ttk-theme) and Segoe UI Variable font.
15 |
16 | ### Usage:
17 | - Ctrl + M to disable/enable Mica (only for Windows 11).
18 | >Disabled Mica by default since users reported some issues with it.
19 |
20 | ### Supported Platforms:
21 | - Windows 10* and Windows 11.
22 |
23 | >*Need the Segoe UI Variable font to work properly!
24 |
25 |
26 | ### Other awesome repositories:
27 | -
[TimerX](https://github.com/Futura-Py/TimerX)
29 | - [Sun-Valley-ttk-theme](https://github.com/rdbende/Sun-Valley-ttk-theme)
30 |
--------------------------------------------------------------------------------
/docs/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Futura-Py/FluxCalc/56aea799ad7a71d251bd2aa9d799870aa3045402/docs/screenshot.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | win32mica
2 | darkdetect
3 | ntkutils >= 2.2.1
4 | pyinstaller
5 | strsplit
6 | sv_ttk
--------------------------------------------------------------------------------
/src/calculations.py:
--------------------------------------------------------------------------------
1 | import strsplit
2 |
3 | calculation = ""
4 |
5 | def bracketcheck():
6 | global calculation
7 | if "(" in calculation:
8 | for i in range(10):
9 | if strsplit.before(calculation, "(").endswith(str(i)):
10 | calculation = strsplit.before(calculation, "(") + "*" + str(eval(strsplit.inbetween(calculation, "(", ")"))) + strsplit.after(calculation, ")")
11 | if "(" in calculation and strsplit.before(calculation, "(") == "":
12 | calculation = strsplit.after(calculation, "(")
13 | calculation = str(eval(strsplit.before(calculation, ")"))) + strsplit.after(calculation, ")")
14 | bracketcheck()
15 | else: pass
16 |
17 |
18 | def _btnClick(key):
19 | global calculation
20 | calculation = calculation + str(key)
21 | return calculation
22 |
23 | def _btnEqualsInput():
24 | global calculation
25 | try:
26 | bracketcheck()
27 | return [eval(calculation), calculation]
28 | except ZeroDivisionError:
29 | return ["r u dumb", ""]
30 | except:
31 | return ["Error", ""]
32 |
33 | def _backspace():
34 | global calculation
35 | calculation = calculation[:-1]
36 |
37 | def _square():
38 | global calculation
39 | try:
40 | int(calculation)
41 | squared = eval("{}*{}".format(calculation, calculation))
42 | if str(squared).endswith(".0"): squared = str(squared).rstrip(".0")
43 | return [squared, calculation + '²']
44 | except ValueError:
45 | if not calculation == "":
46 | return ["development", "feature still in"]
47 | else:
48 | return ["0", ""]
--------------------------------------------------------------------------------
/src/config.json:
--------------------------------------------------------------------------------
1 | {"mica": "False"}
--------------------------------------------------------------------------------
/src/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Futura-Py/FluxCalc/56aea799ad7a71d251bd2aa9d799870aa3045402/src/icon.ico
--------------------------------------------------------------------------------
/src/main.py:
--------------------------------------------------------------------------------
1 | from tkinter import BooleanVar, ttk, Label, StringVar, messagebox
2 | import tkinter as tk
3 | import darkdetect, sv_ttk, ntkutils
4 | import calculations as c
5 | import webbrowser
6 | import json
7 |
8 | #region functions
9 | def aot():
10 | if always_on_top.get() == 1:
11 | root.attributes('-topmost', True)
12 | else:
13 | root.attributes('-topmost', False)
14 |
15 | def btnClick(key):
16 | content.set(c._btnClick(key))
17 |
18 | def btnClearDisplay():
19 | content2.set("")
20 | content.set("")
21 | c.calculation = ""
22 |
23 | def backspace(event=None):
24 | c.calculation = c.calculation[:-1]
25 | content2.set("")
26 | content.set(c.calculation)
27 |
28 | def square():
29 | result = c._square()
30 | content.set(result[0])
31 | content2.set(result[1])
32 | c.calculation = ""
33 |
34 | x = StringVar
35 | x = 0
36 | def btnEqualsInput(event=None):
37 | global x
38 | result = c._btnEqualsInput()
39 | content.set(result[0])
40 | content2.set(result[1])
41 | if content.get() == 'r u dumb':
42 | x += 1
43 | if x == 2:
44 | content.set("")
45 | c.calculation = ""
46 | messagebox.showerror("hey!", "Stop dividing by zero!")
47 | if x == 3:
48 | content.set("")
49 | c.calculation = ""
50 | e = messagebox.askyesno("hey!", "Seriously? Stop")
51 | if e == 'yes':
52 | pass
53 | else:
54 | webbrowser.open('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
55 | if x == 4:
56 | content.set("")
57 | c.calculation = ""
58 | messagebox.showerror("Error", "FluxCalc will shut down if there is one more division by zero")
59 | if x == 5:
60 | content.set("")
61 | c.calculation = ""
62 | messagebox.showerror("Error", "FluxCalc will shut down in 5 seconds")
63 | root.destroy()
64 |
65 | def updateConfig():
66 | with open("config.json", "w") as jsonfile:
67 | json.dump(data, jsonfile)
68 | jsonfile.close()
69 |
70 | with open("config.json", "r") as config:
71 | data = json.load(config)
72 | #endregion
73 |
74 | #region window
75 | root=tk.Tk()
76 | root.resizable(False, False)
77 | root.geometry('318x480')
78 | root.title('')
79 | root.iconbitmap(r'icon.ico')
80 |
81 | if darkdetect.theme() == "Dark":
82 | sv_ttk.set_theme("dark")
83 | ntkutils.dark_title_bar(root)
84 | else:
85 | sv_ttk.set_theme("light")
86 |
87 | def setmica(event=None):
88 | if data['mica'] == 'True':
89 | data['mica'] = 'False'
90 | micaval = "Off"
91 | else:
92 | data['mica'] = 'True'
93 | micaval = "On"
94 |
95 | updateConfig()
96 | content2.set("Mica: " + micaval)
97 |
98 | if data['mica'] == 'True':
99 | ntkutils.blur_window_background(root)
100 | if darkdetect.theme() == "Dark":
101 | ntkutils.dark_title_bar(root)
102 | else:
103 | pass
104 |
105 | #endregion
106 |
107 | always_on_top = BooleanVar()
108 | content= StringVar()
109 | content2 = StringVar()
110 |
111 | #region widgets
112 | Display = Label(root, textvariable=content, font=('Segoe UI Variable Display Semibold','35'),anchor="e",width=11).place(x=0, y=60)
113 | Display2 =Label(root,textvariable=content2, font=('Segoe UI Variable Display Semibold','15'),anchor="e",width=11, fg='#707476').place(x=162,y=30)
114 |
115 | btn1=ttk.Button(root, text="1", command=lambda:btnClick(1)).place(x=4, y=368, height=53, width=76)
116 | btn2=ttk.Button(root, text="2", command=lambda:btnClick(2)).place(x=82, y=368, height=53, width=76)
117 | btn3=ttk.Button(root, text="3", command=lambda:btnClick(3)).place(x=160, y=368, height=53, width=76)
118 | btn4=ttk.Button(root, text="4", command=lambda:btnClick(4)).place(x=4, y=313, height=53, width=76)
119 | btn5=ttk.Button(root, text="5", command=lambda:btnClick(5)).place(x=82, y=313, height=53, width=76)
120 | btn6=ttk.Button(root, text="6", command=lambda:btnClick(6)).place(x=160, y=313, height=53, width=76)
121 | btn7=ttk.Button(root, text="7", command=lambda:btnClick(7)).place(x=4, y=258, height=53, width=76)
122 | btn8=ttk.Button(root, text="8", command=lambda:btnClick(8)).place(x=82, y=258, height=53, width=76)
123 | btn9=ttk.Button(root, text="9", command=lambda:btnClick(9)).place(x=160, y=258, height=53, width=76)
124 | btn0=ttk.Button(root, text="0", command=lambda:btnClick(0)).place(x=4, y=423, height=53, width=154)
125 |
126 | alwaysontop=ttk.Checkbutton(root, text="", variable = always_on_top,onvalue=1, offvalue=0, style="Toggle.TButton",command=lambda:aot()).place(x=4, y=148, height=53, width=76)
127 | openbtn=ttk.Button(root, text="(", command=lambda:btnClick('(')).place(x=82, y=148, height=53, width=76)
128 | closebtn=ttk.Button(root, text=")", command=lambda:btnClick(')')).place(x=160, y=148, height=53, width=76)
129 | btnClear=ttk.Button(root, text="C", command=lambda:btnClearDisplay()).place(x=82, y= 203, height=53, width=76)
130 | Backspace = ttk.Button(root, text='', command=lambda:backspace()).place(x=160, y=203, height=53, width=76)
131 | btndot=ttk.Button(root, text=".", command=lambda:btnClick('.')).place(x=160, y=423, height=53, width=76)
132 |
133 | Divsion=ttk.Button(root, text="", command=lambda:btnClick("/")).place(x=238, y=148, height=53, width=76)
134 | Multiple=ttk.Button(root, text="", command=lambda:btnClick("*")).place(x=238, y=203, height=53, width=76)
135 | Subtraction=ttk.Button(root, text="", command=lambda:btnClick("-")).place(x=238, y=258, height=53, width=76)
136 | Addition=ttk.Button(root, text="", command=lambda:btnClick("+")).place(x=238, y=313, height=53, width=76)
137 | btnsquare=ttk.Button(root, text="x²", command=lambda:square()).place(x=4, y=203, height=53, width=76)
138 | equal=ttk.Button(root, text="", command=lambda:btnEqualsInput()).place(x=238, y=368, height=108, width=76)
139 | #endregion
140 |
141 | #Keyboard binding
142 | root.bind('', btnEqualsInput)
143 | root.bind('', backspace)
144 | root.bind("1", lambda e:btnClick(1))
145 | root.bind("2", lambda e:btnClick(2))
146 | root.bind("3", lambda e:btnClick(3))
147 | root.bind("4", lambda e:btnClick(4))
148 | root.bind("5", lambda e:btnClick(5))
149 | root.bind("6", lambda e:btnClick(6))
150 | root.bind("7", lambda e:btnClick(7))
151 | root.bind("8", lambda e:btnClick(8))
152 | root.bind("9", lambda e:btnClick(9))
153 | root.bind("0", lambda e:btnClick(0))
154 | root.bind("<+>", lambda e:btnClick("+"))
155 | root.bind("-", lambda e:btnClick("-"))
156 | root.bind("<*>", lambda e:btnClick("*"))
157 | root.bind("/", lambda e:btnClick("/"))
158 | root.bind("=", lambda e:btnEqualsInput())
159 | root.bind("(", lambda e:btnClick("("))
160 | root.bind(")", lambda e:btnClick(")"))
161 | root.bind('', setmica)
162 | #endregion
163 |
164 | root.mainloop()
--------------------------------------------------------------------------------