mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
Depending on the definition of `i64` on a particular platform, there's an ambiguity when constructing a Crypto::SignedBigInteger from an integer literal. On serenity, using an int literal is just fine. On macOS, where i64 is long instead of long long, the compiler complains there's an abiguity when using a function-style cast to call a converting constructor between the i64 and double constructors for SignedBigInteger. This commit changes the construction of irrational constants to use user defined literals instead of integer literals, which removes the ambiguity and allows the code to compile on all platforms.
152 lines
6.3 KiB
C++
152 lines
6.3 KiB
C++
/*
|
|
* Copyright (c) 2019-2020, Sergey Bugaev <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "CalculatorWidget.h"
|
|
#include <LibCore/System.h>
|
|
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
|
#include <LibDesktop/Launcher.h>
|
|
#include <LibGUI/Action.h>
|
|
#include <LibGUI/ActionGroup.h>
|
|
#include <LibGUI/Application.h>
|
|
#include <LibGUI/Clipboard.h>
|
|
#include <LibGUI/Icon.h>
|
|
#include <LibGUI/InputBox.h>
|
|
#include <LibGUI/Menu.h>
|
|
#include <LibGUI/Menubar.h>
|
|
#include <LibGUI/Window.h>
|
|
#include <LibGfx/Bitmap.h>
|
|
#include <LibMain/Main.h>
|
|
#include <LibURL/URL.h>
|
|
|
|
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|
{
|
|
TRY(Core::System::pledge("stdio recvfd sendfd rpath unix"));
|
|
auto app = TRY(GUI::Application::create(arguments));
|
|
|
|
auto const man_file = "/usr/share/man/man1/Applications/Calculator.md";
|
|
|
|
TRY(Desktop::Launcher::add_allowed_handler_with_only_specific_urls("/bin/Help", { URL::create_with_file_scheme(man_file) }));
|
|
TRY(Desktop::Launcher::seal_allowlist());
|
|
|
|
TRY(Core::System::pledge("stdio recvfd sendfd rpath"));
|
|
TRY(Core::System::unveil("/res", "r"));
|
|
TRY(Core::System::unveil(nullptr, nullptr));
|
|
|
|
auto app_icon = GUI::Icon::default_icon("app-calculator"sv);
|
|
|
|
auto window = GUI::Window::construct();
|
|
window->set_title("Calculator");
|
|
window->set_resizable(false);
|
|
window->resize(250, 215);
|
|
|
|
auto widget = TRY(Calculator::CalculatorWidget::try_create());
|
|
window->set_main_widget(widget.ptr());
|
|
|
|
window->set_icon(app_icon.bitmap_for_size(16));
|
|
|
|
auto file_menu = window->add_menu("&File"_string);
|
|
file_menu->add_action(GUI::CommonActions::make_quit_action([](auto&) {
|
|
GUI::Application::the()->quit();
|
|
}));
|
|
|
|
auto edit_menu = window->add_menu("&Edit"_string);
|
|
edit_menu->add_action(GUI::CommonActions::make_copy_action([&](auto&) {
|
|
GUI::Clipboard::the().set_plain_text(widget->get_entry());
|
|
}));
|
|
edit_menu->add_action(GUI::CommonActions::make_paste_action([&](auto&) {
|
|
auto clipboard = GUI::Clipboard::the().fetch_data_and_type();
|
|
if (clipboard.mime_type == "text/plain") {
|
|
if (!clipboard.data.is_empty()) {
|
|
auto number_or_error = Crypto::BigFraction::from_string(StringView(clipboard.data));
|
|
if (!number_or_error.is_error())
|
|
widget->set_typed_entry(number_or_error.release_value());
|
|
}
|
|
}
|
|
}));
|
|
|
|
auto constants_menu = window->add_menu("&Constants"_string);
|
|
auto const power = Crypto::NumberTheory::Power("10"_bigint, "10"_bigint);
|
|
auto const pi = Crypto::BigFraction { "31415926535"_sbigint, power };
|
|
auto const eulers_number = Crypto::BigFraction { "27182818284"_sbigint, power };
|
|
auto const phi = Crypto::BigFraction { "16180339887"_sbigint, power };
|
|
|
|
constants_menu->add_action(GUI::Action::create("&Pi", TRY(Gfx::Bitmap::load_from_uri("resource://icons/calculator/pi.png"sv)), [&](auto&) {
|
|
widget->set_typed_entry(pi);
|
|
}));
|
|
constants_menu->add_action(GUI::Action::create("&Euler's Number", TRY(Gfx::Bitmap::load_from_uri("resource://icons/calculator/eulers_number.png"sv)), [&](auto&) {
|
|
widget->set_typed_entry(eulers_number);
|
|
}));
|
|
constants_menu->add_action(GUI::Action::create("&Phi", TRY(Gfx::Bitmap::load_from_uri("resource://icons/calculator/phi.png"sv)), [&](auto&) {
|
|
widget->set_typed_entry(phi);
|
|
}));
|
|
|
|
auto round_menu = window->add_menu("&Round"_string);
|
|
GUI::ActionGroup preview_actions;
|
|
|
|
static constexpr auto rounding_modes = Array { 0, 2, 4 };
|
|
|
|
Optional<unsigned> last_rounding_mode = 1;
|
|
for (unsigned i {}; i < rounding_modes.size(); ++i) {
|
|
auto round_action = GUI::Action::create_checkable(ByteString::formatted("To &{} Digits", rounding_modes[i]),
|
|
[&widget, rounding_mode = rounding_modes[i], &last_rounding_mode, i](auto&) {
|
|
widget->set_rounding_length(rounding_mode);
|
|
last_rounding_mode = i;
|
|
});
|
|
|
|
preview_actions.add_action(*round_action);
|
|
round_menu->add_action(*round_action);
|
|
}
|
|
|
|
constexpr auto format { "&Custom - {}..."sv };
|
|
auto round_custom = GUI::Action::create_checkable(ByteString::formatted(format, 0), [&](auto& action) {
|
|
int custom_rounding_length = widget->rounding_length();
|
|
auto result = GUI::InputBox::show_numeric(window, custom_rounding_length, 0, 100, "Digits to Round"sv);
|
|
if (!result.is_error() && result.value() == GUI::Dialog::ExecResult::OK) {
|
|
action.set_text(ByteString::formatted(format, custom_rounding_length));
|
|
widget->set_rounding_length(custom_rounding_length);
|
|
last_rounding_mode.clear();
|
|
} else if (last_rounding_mode.has_value())
|
|
round_menu->action_at(last_rounding_mode.value())
|
|
->activate();
|
|
});
|
|
|
|
widget->set_rounding_custom(round_custom, format);
|
|
|
|
auto shrink_action = GUI::Action::create("&Shrink...", TRY(Gfx::Bitmap::load_from_uri("resource://icons/16x16/edit-cut.png"sv)), [&](auto&) {
|
|
int shrink_length = widget->rounding_length();
|
|
auto result = GUI::InputBox::show_numeric(window, shrink_length, 0, 100, "Digits to Shrink"sv);
|
|
if (!result.is_error() && result.value() == GUI::Dialog::ExecResult::OK) {
|
|
round_custom->set_checked(true);
|
|
round_custom->set_text(ByteString::formatted(format, shrink_length));
|
|
widget->set_rounding_length(shrink_length);
|
|
widget->shrink(shrink_length);
|
|
}
|
|
});
|
|
|
|
preview_actions.add_action(*round_custom);
|
|
preview_actions.set_exclusive(true);
|
|
round_menu->add_action(*round_custom);
|
|
round_menu->add_action(*shrink_action);
|
|
|
|
round_menu->action_at(last_rounding_mode.value())->activate();
|
|
|
|
auto view_menu = window->add_menu("&View"_string);
|
|
view_menu->add_action(GUI::CommonActions::make_fullscreen_action([&](auto&) {
|
|
window->set_fullscreen(!window->is_fullscreen());
|
|
}));
|
|
|
|
auto help_menu = window->add_menu("&Help"_string);
|
|
help_menu->add_action(GUI::CommonActions::make_command_palette_action(window));
|
|
help_menu->add_action(GUI::CommonActions::make_help_action([&man_file](auto&) {
|
|
Desktop::Launcher::open(URL::create_with_file_scheme(man_file), "/bin/Help");
|
|
}));
|
|
help_menu->add_action(GUI::CommonActions::make_about_action("Calculator"_string, app_icon, window));
|
|
|
|
window->show();
|
|
|
|
return app->exec();
|
|
}
|