summaryrefslogtreecommitdiff
path: root/Applications
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-01-12 12:05:23 +0100
committerAndreas Kling <kling@serenityos.org>2021-01-12 12:05:23 +0100
commitdc28c07fa526841e05e16161c74a6c23984f1dd5 (patch)
treed68796bc7708eba33fbf7247e1a92188ac5acf6f /Applications
parentaa939c4b4b8a7eb1d22b166ebb5fb737d6e66714 (diff)
downloadserenity-dc28c07fa526841e05e16161c74a6c23984f1dd5.zip
Applications: Move to Userland/Applications/
Diffstat (limited to 'Applications')
-rw-r--r--Applications/About/CMakeLists.txt12
-rw-r--r--Applications/About/main.cpp58
-rw-r--r--Applications/Browser/BookmarksBarWidget.cpp241
-rw-r--r--Applications/Browser/BookmarksBarWidget.h81
-rw-r--r--Applications/Browser/Browser.h35
-rw-r--r--Applications/Browser/BrowserConsoleClient.cpp130
-rw-r--r--Applications/Browser/BrowserConsoleClient.h60
-rw-r--r--Applications/Browser/BrowserWindow.gml15
-rw-r--r--Applications/Browser/CMakeLists.txt19
-rw-r--r--Applications/Browser/ConsoleWidget.cpp169
-rw-r--r--Applications/Browser/ConsoleWidget.h57
-rw-r--r--Applications/Browser/DownloadWidget.cpp182
-rw-r--r--Applications/Browser/DownloadWidget.h61
-rw-r--r--Applications/Browser/History.cpp73
-rw-r--r--Applications/Browser/History.h54
-rw-r--r--Applications/Browser/InspectorWidget.cpp94
-rw-r--r--Applications/Browser/InspectorWidget.h53
-rw-r--r--Applications/Browser/Tab.cpp550
-rw-r--r--Applications/Browser/Tab.gml22
-rw-r--r--Applications/Browser/Tab.h123
-rw-r--r--Applications/Browser/WindowActions.cpp82
-rw-r--r--Applications/Browser/WindowActions.h59
-rw-r--r--Applications/Browser/main.cpp254
-rw-r--r--Applications/CMakeLists.txt26
-rw-r--r--Applications/Calculator/CMakeLists.txt11
-rw-r--r--Applications/Calculator/Calculator.cpp143
-rw-r--r--Applications/Calculator/Calculator.h72
-rw-r--r--Applications/Calculator/CalculatorWidget.cpp208
-rw-r--r--Applications/Calculator/CalculatorWidget.h73
-rw-r--r--Applications/Calculator/CalculatorWindow.gml272
-rw-r--r--Applications/Calculator/Keypad.cpp171
-rw-r--r--Applications/Calculator/Keypad.h69
-rw-r--r--Applications/Calculator/main.cpp84
-rw-r--r--Applications/Calendar/AddEventDialog.cpp154
-rw-r--r--Applications/Calendar/AddEventDialog.h69
-rw-r--r--Applications/Calendar/CMakeLists.txt7
-rw-r--r--Applications/Calendar/main.cpp182
-rw-r--r--Applications/CrashReporter/CMakeLists.txt10
-rw-r--r--Applications/CrashReporter/CrashReporterWindow.gml95
-rw-r--r--Applications/CrashReporter/main.cpp179
-rw-r--r--Applications/Debugger/CMakeLists.txt6
-rw-r--r--Applications/Debugger/main.cpp313
-rw-r--r--Applications/DisplaySettings/CMakeLists.txt11
-rw-r--r--Applications/DisplaySettings/DisplaySettings.cpp264
-rw-r--r--Applications/DisplaySettings/DisplaySettings.h55
-rw-r--r--Applications/DisplaySettings/DisplaySettingsWindow.gml117
-rw-r--r--Applications/DisplaySettings/MonitorWidget.cpp118
-rw-r--r--Applications/DisplaySettings/MonitorWidget.h64
-rw-r--r--Applications/DisplaySettings/main.cpp82
-rw-r--r--Applications/FileManager/CMakeLists.txt13
-rw-r--r--Applications/FileManager/DesktopWidget.cpp47
-rw-r--r--Applications/FileManager/DesktopWidget.h45
-rw-r--r--Applications/FileManager/DirectoryView.cpp591
-rw-r--r--Applications/FileManager/DirectoryView.h190
-rw-r--r--Applications/FileManager/FileManagerWindow.gml53
-rw-r--r--Applications/FileManager/FileUtils.cpp280
-rw-r--r--Applications/FileManager/FileUtils.h50
-rw-r--r--Applications/FileManager/PropertiesWindow.cpp304
-rw-r--r--Applications/FileManager/PropertiesWindow.h98
-rw-r--r--Applications/FileManager/main.cpp974
-rw-r--r--Applications/FontEditor/.gitignore1
-rw-r--r--Applications/FontEditor/CMakeLists.txt11
-rw-r--r--Applications/FontEditor/FontEditor.cpp372
-rw-r--r--Applications/FontEditor/FontEditor.h58
-rw-r--r--Applications/FontEditor/GlyphEditorWidget.cpp125
-rw-r--r--Applications/FontEditor/GlyphEditorWidget.h60
-rw-r--r--Applications/FontEditor/GlyphMapWidget.cpp168
-rw-r--r--Applications/FontEditor/GlyphMapWidget.h69
-rw-r--r--Applications/FontEditor/main.cpp155
-rw-r--r--Applications/Help/CMakeLists.txt10
-rw-r--r--Applications/Help/History.cpp59
-rw-r--r--Applications/Help/History.h48
-rw-r--r--Applications/Help/ManualModel.cpp199
-rw-r--r--Applications/Help/ManualModel.h66
-rw-r--r--Applications/Help/ManualNode.h41
-rw-r--r--Applications/Help/ManualPageNode.cpp44
-rw-r--r--Applications/Help/ManualPageNode.h53
-rw-r--r--Applications/Help/ManualSectionNode.cpp66
-rw-r--r--Applications/Help/ManualSectionNode.h63
-rw-r--r--Applications/Help/main.cpp312
-rw-r--r--Applications/HexEditor/CMakeLists.txt8
-rw-r--r--Applications/HexEditor/HexEditor.cpp583
-rw-r--r--Applications/HexEditor/HexEditor.h105
-rw-r--r--Applications/HexEditor/HexEditorWidget.cpp241
-rw-r--r--Applications/HexEditor/HexEditorWidget.h65
-rw-r--r--Applications/HexEditor/main.cpp67
-rw-r--r--Applications/IRCClient/CMakeLists.txt14
-rw-r--r--Applications/IRCClient/IRCAppWindow.cpp375
-rw-r--r--Applications/IRCClient/IRCAppWindow.h76
-rw-r--r--Applications/IRCClient/IRCChannel.cpp144
-rw-r--r--Applications/IRCClient/IRCChannel.h94
-rw-r--r--Applications/IRCClient/IRCChannelMemberListModel.cpp81
-rw-r--r--Applications/IRCClient/IRCChannelMemberListModel.h53
-rw-r--r--Applications/IRCClient/IRCClient.cpp1188
-rw-r--r--Applications/IRCClient/IRCClient.h236
-rw-r--r--Applications/IRCClient/IRCLogBuffer.cpp98
-rw-r--r--Applications/IRCClient/IRCLogBuffer.h58
-rw-r--r--Applications/IRCClient/IRCQuery.cpp65
-rw-r--r--Applications/IRCClient/IRCQuery.h64
-rw-r--r--Applications/IRCClient/IRCWindow.cpp278
-rw-r--r--Applications/IRCClient/IRCWindow.h82
-rw-r--r--Applications/IRCClient/IRCWindowListModel.cpp91
-rw-r--r--Applications/IRCClient/IRCWindowListModel.h54
-rw-r--r--Applications/IRCClient/main.cpp109
-rw-r--r--Applications/KeyboardMapper/CMakeLists.txt8
-rw-r--r--Applications/KeyboardMapper/KeyButton.cpp96
-rw-r--r--Applications/KeyboardMapper/KeyButton.h49
-rw-r--r--Applications/KeyboardMapper/KeyPositions.h115
-rw-r--r--Applications/KeyboardMapper/KeyboardMapperWidget.cpp293
-rw-r--r--Applications/KeyboardMapper/KeyboardMapperWidget.h60
-rw-r--r--Applications/KeyboardMapper/main.cpp116
-rw-r--r--Applications/KeyboardSettings/CMakeLists.txt6
-rw-r--r--Applications/KeyboardSettings/CharacterMapFileListModel.h74
-rw-r--r--Applications/KeyboardSettings/main.cpp202
-rw-r--r--Applications/MouseSettings/CMakeLists.txt6
-rw-r--r--Applications/MouseSettings/main.cpp133
-rw-r--r--Applications/Piano/CMakeLists.txt14
-rw-r--r--Applications/Piano/KeysWidget.cpp328
-rw-r--r--Applications/Piano/KeysWidget.h62
-rw-r--r--Applications/Piano/KnobsWidget.cpp183
-rw-r--r--Applications/Piano/KnobsWidget.h76
-rw-r--r--Applications/Piano/MainWidget.cpp179
-rw-r--r--Applications/Piano/MainWidget.h74
-rw-r--r--Applications/Piano/Music.h329
-rw-r--r--Applications/Piano/RollWidget.cpp248
-rw-r--r--Applications/Piano/RollWidget.h64
-rw-r--r--Applications/Piano/SamplerWidget.cpp130
-rw-r--r--Applications/Piano/SamplerWidget.h62
-rw-r--r--Applications/Piano/Track.cpp369
-rw-r--r--Applications/Piano/Track.h104
-rw-r--r--Applications/Piano/TrackManager.cpp104
-rw-r--r--Applications/Piano/TrackManager.h74
-rw-r--r--Applications/Piano/WaveWidget.cpp88
-rw-r--r--Applications/Piano/WaveWidget.h47
-rw-r--r--Applications/Piano/main.cpp137
-rw-r--r--Applications/PixelPaint/BrushTool.cpp169
-rw-r--r--Applications/PixelPaint/BrushTool.h54
-rw-r--r--Applications/PixelPaint/BucketTool.cpp133
-rw-r--r--Applications/PixelPaint/BucketTool.h46
-rw-r--r--Applications/PixelPaint/CMakeLists.txt27
-rw-r--r--Applications/PixelPaint/CreateNewImageDialog.cpp91
-rw-r--r--Applications/PixelPaint/CreateNewImageDialog.h49
-rw-r--r--Applications/PixelPaint/CreateNewLayerDialog.cpp95
-rw-r--r--Applications/PixelPaint/CreateNewLayerDialog.h49
-rw-r--r--Applications/PixelPaint/EllipseTool.cpp137
-rw-r--r--Applications/PixelPaint/EllipseTool.h64
-rw-r--r--Applications/PixelPaint/EraseTool.cpp120
-rw-r--r--Applications/PixelPaint/EraseTool.h56
-rw-r--r--Applications/PixelPaint/FilterParams.h191
-rw-r--r--Applications/PixelPaint/Image.cpp331
-rw-r--r--Applications/PixelPaint/Image.h114
-rw-r--r--Applications/PixelPaint/ImageEditor.cpp418
-rw-r--r--Applications/PixelPaint/ImageEditor.h125
-rw-r--r--Applications/PixelPaint/Layer.cpp108
-rw-r--r--Applications/PixelPaint/Layer.h95
-rw-r--r--Applications/PixelPaint/LayerListWidget.cpp285
-rw-r--r--Applications/PixelPaint/LayerListWidget.h89
-rw-r--r--Applications/PixelPaint/LayerPropertiesWidget.cpp107
-rw-r--r--Applications/PixelPaint/LayerPropertiesWidget.h53
-rw-r--r--Applications/PixelPaint/LineTool.cpp156
-rw-r--r--Applications/PixelPaint/LineTool.h59
-rw-r--r--Applications/PixelPaint/MoveTool.cpp139
-rw-r--r--Applications/PixelPaint/MoveTool.h52
-rw-r--r--Applications/PixelPaint/PaletteWidget.cpp178
-rw-r--r--Applications/PixelPaint/PaletteWidget.h52
-rw-r--r--Applications/PixelPaint/PenTool.cpp128
-rw-r--r--Applications/PixelPaint/PenTool.h54
-rw-r--r--Applications/PixelPaint/PickerTool.cpp53
-rw-r--r--Applications/PixelPaint/PickerTool.h41
-rw-r--r--Applications/PixelPaint/RectangleTool.cpp137
-rw-r--r--Applications/PixelPaint/RectangleTool.h63
-rw-r--r--Applications/PixelPaint/SprayTool.cpp176
-rw-r--r--Applications/PixelPaint/SprayTool.h60
-rw-r--r--Applications/PixelPaint/Tool.cpp51
-rw-r--r--Applications/PixelPaint/Tool.h63
-rw-r--r--Applications/PixelPaint/ToolPropertiesWidget.cpp61
-rw-r--r--Applications/PixelPaint/ToolPropertiesWidget.h54
-rw-r--r--Applications/PixelPaint/ToolboxWidget.cpp140
-rw-r--r--Applications/PixelPaint/ToolboxWidget.h60
-rw-r--r--Applications/PixelPaint/main.cpp387
-rw-r--r--Applications/QuickShow/CMakeLists.txt7
-rw-r--r--Applications/QuickShow/QSWidget.cpp283
-rw-r--r--Applications/QuickShow/QSWidget.h89
-rw-r--r--Applications/QuickShow/main.cpp309
-rw-r--r--Applications/SoundPlayer/CMakeLists.txt9
-rw-r--r--Applications/SoundPlayer/PlaybackManager.cpp188
-rw-r--r--Applications/SoundPlayer/PlaybackManager.h77
-rw-r--r--Applications/SoundPlayer/SampleWidget.cpp82
-rw-r--r--Applications/SoundPlayer/SampleWidget.h47
-rw-r--r--Applications/SoundPlayer/SoundPlayerWidget.cpp194
-rw-r--r--Applications/SoundPlayer/SoundPlayerWidget.h94
-rw-r--r--Applications/SoundPlayer/main.cpp109
-rw-r--r--Applications/SpaceAnalyzer/CMakeLists.txt10
-rw-r--r--Applications/SpaceAnalyzer/SpaceAnalyzer.gml20
-rw-r--r--Applications/SpaceAnalyzer/TreeMapWidget.cpp376
-rw-r--r--Applications/SpaceAnalyzer/TreeMapWidget.h90
-rw-r--r--Applications/SpaceAnalyzer/main.cpp300
-rw-r--r--Applications/Spreadsheet/CMakeLists.txt28
-rw-r--r--Applications/Spreadsheet/Cell.cpp211
-rw-r--r--Applications/Spreadsheet/Cell.h138
-rw-r--r--Applications/Spreadsheet/CellSyntaxHighlighter.cpp81
-rw-r--r--Applications/Spreadsheet/CellSyntaxHighlighter.h47
-rw-r--r--Applications/Spreadsheet/CellType/Date.cpp68
-rw-r--r--Applications/Spreadsheet/CellType/Date.h42
-rw-r--r--Applications/Spreadsheet/CellType/Format.cpp69
-rw-r--r--Applications/Spreadsheet/CellType/Format.h35
-rw-r--r--Applications/Spreadsheet/CellType/Identity.cpp52
-rw-r--r--Applications/Spreadsheet/CellType/Identity.h42
-rw-r--r--Applications/Spreadsheet/CellType/Numeric.cpp76
-rw-r--r--Applications/Spreadsheet/CellType/Numeric.h42
-rw-r--r--Applications/Spreadsheet/CellType/String.cpp57
-rw-r--r--Applications/Spreadsheet/CellType/String.h42
-rw-r--r--Applications/Spreadsheet/CellType/Type.cpp63
-rw-r--r--Applications/Spreadsheet/CellType/Type.h64
-rw-r--r--Applications/Spreadsheet/CellTypeDialog.cpp483
-rw-r--r--Applications/Spreadsheet/CellTypeDialog.h69
-rw-r--r--Applications/Spreadsheet/CondFormatting.gml40
-rw-r--r--Applications/Spreadsheet/CondView.gml54
-rw-r--r--Applications/Spreadsheet/ConditionalFormatting.h73
-rw-r--r--Applications/Spreadsheet/Forward.h41
-rw-r--r--Applications/Spreadsheet/HelpWindow.cpp229
-rw-r--r--Applications/Spreadsheet/HelpWindow.h63
-rw-r--r--Applications/Spreadsheet/JSIntegration.cpp444
-rw-r--r--Applications/Spreadsheet/JSIntegration.h82
-rw-r--r--Applications/Spreadsheet/Position.h60
-rw-r--r--Applications/Spreadsheet/Readers/CSV.h43
-rw-r--r--Applications/Spreadsheet/Readers/Test/TestXSV.cpp110
-rw-r--r--Applications/Spreadsheet/Readers/XSV.cpp272
-rw-r--r--Applications/Spreadsheet/Readers/XSV.h208
-rw-r--r--Applications/Spreadsheet/Spreadsheet.cpp734
-rw-r--r--Applications/Spreadsheet/Spreadsheet.h188
-rw-r--r--Applications/Spreadsheet/SpreadsheetModel.cpp178
-rw-r--r--Applications/Spreadsheet/SpreadsheetModel.h60
-rw-r--r--Applications/Spreadsheet/SpreadsheetView.cpp334
-rw-r--r--Applications/Spreadsheet/SpreadsheetView.h168
-rw-r--r--Applications/Spreadsheet/SpreadsheetWidget.cpp347
-rw-r--r--Applications/Spreadsheet/SpreadsheetWidget.h86
-rw-r--r--Applications/Spreadsheet/Workbook.cpp190
-rw-r--r--Applications/Spreadsheet/Workbook.h78
-rw-r--r--Applications/Spreadsheet/Writers/CSV.h44
-rw-r--r--Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp96
-rw-r--r--Applications/Spreadsheet/Writers/XSV.h215
-rw-r--r--Applications/Spreadsheet/main.cpp253
-rw-r--r--Applications/SystemMonitor/CMakeLists.txt16
-rw-r--r--Applications/SystemMonitor/DevicesModel.cpp198
-rw-r--r--Applications/SystemMonitor/DevicesModel.h69
-rw-r--r--Applications/SystemMonitor/GraphWidget.cpp163
-rw-r--r--Applications/SystemMonitor/GraphWidget.h70
-rw-r--r--Applications/SystemMonitor/InterruptsWidget.cpp68
-rw-r--r--Applications/SystemMonitor/InterruptsWidget.h44
-rw-r--r--Applications/SystemMonitor/MemoryStatsWidget.cpp138
-rw-r--r--Applications/SystemMonitor/MemoryStatsWidget.h53
-rw-r--r--Applications/SystemMonitor/NetworkStatisticsWidget.cpp98
-rw-r--r--Applications/SystemMonitor/NetworkStatisticsWidget.h46
-rw-r--r--Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp74
-rw-r--r--Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h45
-rw-r--r--Applications/SystemMonitor/ProcessMemoryMapWidget.cpp141
-rw-r--r--Applications/SystemMonitor/ProcessMemoryMapWidget.h46
-rw-r--r--Applications/SystemMonitor/ProcessModel.cpp454
-rw-r--r--Applications/SystemMonitor/ProcessModel.h172
-rw-r--r--Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp57
-rw-r--r--Applications/SystemMonitor/ProcessUnveiledPathsWidget.h45
-rw-r--r--Applications/SystemMonitor/ThreadStackWidget.cpp68
-rw-r--r--Applications/SystemMonitor/ThreadStackWidget.h47
-rw-r--r--Applications/SystemMonitor/main.cpp670
-rw-r--r--Applications/Terminal/CMakeLists.txt9
-rw-r--r--Applications/Terminal/TerminalSettingsWindow.gml63
-rw-r--r--Applications/Terminal/main.cpp525
-rw-r--r--Applications/TextEditor/CMakeLists.txt10
-rw-r--r--Applications/TextEditor/TextEditorWidget.cpp667
-rw-r--r--Applications/TextEditor/TextEditorWidget.h123
-rw-r--r--Applications/TextEditor/TextEditorWindow.gml88
-rw-r--r--Applications/TextEditor/main.cpp93
-rw-r--r--Applications/ThemeEditor/CMakeLists.txt7
-rw-r--r--Applications/ThemeEditor/PreviewWidget.cpp176
-rw-r--r--Applications/ThemeEditor/PreviewWidget.h63
-rw-r--r--Applications/ThemeEditor/main.cpp136
-rw-r--r--Applications/Welcome/BackgroundWidget.cpp52
-rw-r--r--Applications/Welcome/BackgroundWidget.h41
-rw-r--r--Applications/Welcome/CMakeLists.txt9
-rw-r--r--Applications/Welcome/TextWidget.cpp140
-rw-r--r--Applications/Welcome/TextWidget.h65
-rw-r--r--Applications/Welcome/UnuncheckableButton.cpp35
-rw-r--r--Applications/Welcome/UnuncheckableButton.h40
-rw-r--r--Applications/Welcome/main.cpp234
285 files changed, 0 insertions, 37234 deletions
diff --git a/Applications/About/CMakeLists.txt b/Applications/About/CMakeLists.txt
deleted file mode 100644
index 0b3023c819..0000000000
--- a/Applications/About/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-set(SOURCES
- main.cpp
-)
-
-execute_process(COMMAND "git rev-parse --short HEAD" OUTPUT_VARIABLE GIT_COMMIT)
-execute_process(COMMAND "git rev-parse --abbrev-ref HEAD" OUTPUT_VARIABLE GIT_BRANCH)
-execute_process(COMMAND "git diff-index --quiet HEAD -- && echo tracked || echo untracked" OUTPUT_VARIABLE GIT_CHANGES)
-
-add_definitions(-DGIT_COMMIT="${GIT_COMMIT}" -DGIT_BRANCH="${GIT_BRANCH}" -DGIT_CHANGES="${GIT_CHANGES}")
-
-serenity_bin(About)
-target_link_libraries(About LibGUI)
diff --git a/Applications/About/main.cpp b/Applications/About/main.cpp
deleted file mode 100644
index b7e18caee3..0000000000
--- a/Applications/About/main.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <LibGUI/AboutDialog.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Icon.h>
-#include <LibGfx/Bitmap.h>
-#include <stdio.h>
-#include <sys/utsname.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept rpath unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept rpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- auto app_icon = GUI::Icon::default_icon("ladybug");
- GUI::AboutDialog::show("SerenityOS", nullptr, nullptr, app_icon.bitmap_for_size(32));
- return app->exec();
-}
diff --git a/Applications/Browser/BookmarksBarWidget.cpp b/Applications/Browser/BookmarksBarWidget.cpp
deleted file mode 100644
index ef9af48a60..0000000000
--- a/Applications/Browser/BookmarksBarWidget.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BookmarksBarWidget.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Event.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Model.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Palette.h>
-
-namespace Browser {
-
-static BookmarksBarWidget* s_the;
-
-BookmarksBarWidget& BookmarksBarWidget::the()
-{
- return *s_the;
-}
-
-BookmarksBarWidget::BookmarksBarWidget(const String& bookmarks_file, bool enabled)
-{
- s_the = this;
- set_layout<GUI::HorizontalBoxLayout>();
- layout()->set_spacing(0);
-
- set_fixed_height(20);
-
- if (!enabled)
- set_visible(false);
-
- m_additional = GUI::Button::construct();
- m_additional->set_button_style(Gfx::ButtonStyle::CoolBar);
- m_additional->set_text(">");
- m_additional->set_fixed_size(14, 20);
- m_additional->set_focus_policy(GUI::FocusPolicy::TabFocus);
- m_additional->on_click = [this](auto) {
- if (m_additional_menu) {
- m_additional_menu->popup(m_additional->relative_position().translated(relative_position().translated(m_additional->window()->position())));
- }
- };
-
- m_separator = GUI::Widget::construct();
-
- m_context_menu = GUI::Menu::construct();
- auto default_action = GUI::Action::create("Open", [this](auto&) {
- if (on_bookmark_click)
- on_bookmark_click(m_context_menu_url, Mod_None);
- });
- m_context_menu_default_action = default_action;
- m_context_menu->add_action(default_action);
- m_context_menu->add_action(GUI::Action::create("Open in new tab", [this](auto&) {
- if (on_bookmark_click)
- on_bookmark_click(m_context_menu_url, Mod_Ctrl);
- }));
- m_context_menu->add_action(GUI::Action::create("Delete", [this](auto&) {
- remove_bookmark(m_context_menu_url);
- }));
-
- Vector<GUI::JsonArrayModel::FieldSpec> fields;
- fields.empend("title", "Title", Gfx::TextAlignment::CenterLeft);
- fields.empend("url", "Url", Gfx::TextAlignment::CenterRight);
- set_model(GUI::JsonArrayModel::create(bookmarks_file, move(fields)));
- model()->update();
-}
-
-BookmarksBarWidget::~BookmarksBarWidget()
-{
- if (m_model)
- m_model->unregister_client(*this);
-}
-
-void BookmarksBarWidget::set_model(RefPtr<GUI::Model> model)
-{
- if (model == m_model)
- return;
- if (m_model)
- m_model->unregister_client(*this);
- m_model = move(model);
- m_model->register_client(*this);
-}
-
-void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event)
-{
- Widget::resize_event(event);
- update_content_size();
-}
-
-void BookmarksBarWidget::model_did_update(unsigned)
-{
- remove_all_children();
-
- m_bookmarks.clear();
-
- int width = 0;
- for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
-
- auto title = model()->index(item_index, 0).data().to_string();
- auto url = model()->index(item_index, 1).data().to_string();
-
- Gfx::IntRect rect { width, 0, font().width(title) + 32, height() };
-
- auto& button = add<GUI::Button>();
- m_bookmarks.append(button);
-
- button.set_button_style(Gfx::ButtonStyle::CoolBar);
- button.set_text(title);
- button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"));
- button.set_fixed_size(font().width(title) + 32, 20);
- button.set_relative_rect(rect);
- button.set_focus_policy(GUI::FocusPolicy::TabFocus);
- button.set_tooltip(url);
-
- button.on_click = [title, url, this](auto modifiers) {
- if (on_bookmark_click)
- on_bookmark_click(url, modifiers);
- };
-
- button.on_context_menu_request = [this, url](auto& context_menu_event) {
- m_context_menu_url = url;
- m_context_menu->popup(context_menu_event.screen_position(), m_context_menu_default_action);
- };
-
- width += rect.width();
- }
-
- add_child(*m_separator);
- add_child(*m_additional);
-
- update_content_size();
- update();
-}
-
-void BookmarksBarWidget::update_content_size()
-{
- int x_position = 0;
- m_last_visible_index = -1;
-
- for (size_t i = 0; i < m_bookmarks.size(); ++i) {
- auto& bookmark = m_bookmarks.at(i);
- if (x_position + bookmark.width() > width()) {
- m_last_visible_index = i;
- break;
- }
- bookmark.set_x(x_position);
- bookmark.set_visible(true);
- x_position += bookmark.width();
- }
-
- if (m_last_visible_index < 0) {
- m_additional->set_visible(false);
- } else {
- // hide all items > m_last_visible_index and create new bookmarks menu for them
- m_additional->set_visible(true);
- m_additional_menu = GUI::Menu::construct("Additional Bookmarks");
- for (size_t i = m_last_visible_index; i < m_bookmarks.size(); ++i) {
- auto& bookmark = m_bookmarks.at(i);
- bookmark.set_visible(false);
- m_additional_menu->add_action(GUI::Action::create(bookmark.text(),
- Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"),
- [&](auto&) {
- bookmark.on_click(0);
- }));
- }
- }
-}
-
-bool BookmarksBarWidget::contains_bookmark(const String& url)
-{
- for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
-
- auto item_title = model()->index(item_index, 0).data().to_string();
- auto item_url = model()->index(item_index, 1).data().to_string();
- if (item_url == url) {
- return true;
- }
- }
- return false;
-}
-
-bool BookmarksBarWidget::remove_bookmark(const String& url)
-{
- for (int item_index = 0; item_index < model()->row_count(); ++item_index) {
-
- auto item_title = model()->index(item_index, 0).data().to_string();
- auto item_url = model()->index(item_index, 1).data().to_string();
- if (item_url == url) {
- auto& json_model = *static_cast<GUI::JsonArrayModel*>(model());
-
- const auto item_removed = json_model.remove(item_index);
- if (item_removed)
- json_model.store();
-
- return item_removed;
- }
- }
-
- return false;
-}
-bool BookmarksBarWidget::add_bookmark(const String& url, const String& title)
-{
- Vector<JsonValue> values;
- values.append(title);
- values.append(url);
-
- auto& json_model = *static_cast<GUI::JsonArrayModel*>(model());
- if (json_model.add(move(values))) {
- json_model.store();
- return true;
- }
- return false;
-}
-
-}
diff --git a/Applications/Browser/BookmarksBarWidget.h b/Applications/Browser/BookmarksBarWidget.h
deleted file mode 100644
index 2eeed8fec5..0000000000
--- a/Applications/Browser/BookmarksBarWidget.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Forward.h>
-#include <LibGUI/Model.h>
-#include <LibGUI/Widget.h>
-
-namespace Browser {
-
-class BookmarksBarWidget final
- : public GUI::Widget
- , private GUI::ModelClient {
- C_OBJECT(BookmarksBarWidget);
-
-public:
- static BookmarksBarWidget& the();
-
- virtual ~BookmarksBarWidget() override;
-
- void set_model(RefPtr<GUI::Model>);
- GUI::Model* model() { return m_model.ptr(); }
- const GUI::Model* model() const { return m_model.ptr(); }
-
- Function<void(const String& url, unsigned modifiers)> on_bookmark_click;
- Function<void(const String&, const String&)> on_bookmark_hover;
-
- bool contains_bookmark(const String& url);
- bool remove_bookmark(const String& url);
- bool add_bookmark(const String& url, const String& title);
-
-private:
- BookmarksBarWidget(const String&, bool enabled);
-
- // ^GUI::ModelClient
- virtual void model_did_update(unsigned) override;
-
- // ^GUI::Widget
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- void update_content_size();
-
- RefPtr<GUI::Model> m_model;
- RefPtr<GUI::Button> m_additional;
- RefPtr<GUI::Widget> m_separator;
- RefPtr<GUI::Menu> m_additional_menu;
-
- RefPtr<GUI::Menu> m_context_menu;
- RefPtr<GUI::Action> m_context_menu_default_action;
- String m_context_menu_url;
-
- NonnullRefPtrVector<GUI::Button> m_bookmarks;
-
- int m_last_visible_index { -1 };
-};
-
-}
diff --git a/Applications/Browser/Browser.h b/Applications/Browser/Browser.h
deleted file mode 100644
index a4a4eefe1f..0000000000
--- a/Applications/Browser/Browser.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-
-namespace Browser {
-
-extern String g_home_url;
-
-}
diff --git a/Applications/Browser/BrowserConsoleClient.cpp b/Applications/Browser/BrowserConsoleClient.cpp
deleted file mode 100644
index ce1dd7e5cb..0000000000
--- a/Applications/Browser/BrowserConsoleClient.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BrowserConsoleClient.h"
-#include "ConsoleWidget.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/TextBox.h>
-#include <LibWeb/DOM/DocumentType.h>
-#include <LibWeb/DOM/ElementFactory.h>
-#include <LibWeb/DOM/Text.h>
-#include <LibWeb/DOMTreeModel.h>
-#include <LibWeb/HTML/HTMLBodyElement.h>
-
-namespace Browser {
-
-JS::Value BrowserConsoleClient::log()
-{
- m_console_widget.print_html(vm().join_arguments());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::info()
-{
- StringBuilder html;
- html.append("<span class=\"info\">");
- html.append("(i) ");
- html.append(vm().join_arguments());
- html.append("</span>");
- m_console_widget.print_html(html.string_view());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::debug()
-{
- StringBuilder html;
- html.append("<span class=\"debug\">");
- html.append("(d) ");
- html.append(vm().join_arguments());
- html.append("</span>");
- m_console_widget.print_html(html.string_view());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::warn()
-{
- StringBuilder html;
- html.append("<span class=\"warn\">");
- html.append("(w) ");
- html.append(vm().join_arguments());
- html.append("</span>");
- m_console_widget.print_html(html.string_view());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::error()
-{
- StringBuilder html;
- html.append("<span class=\"error\">");
- html.append("(e) ");
- html.append(vm().join_arguments());
- html.append("</span>");
- m_console_widget.print_html(html.string_view());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::clear()
-{
- m_console_widget.clear_output();
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::trace()
-{
- StringBuilder html;
- html.append(vm().join_arguments());
- auto trace = get_trace();
- for (auto& function_name : trace) {
- if (function_name.is_empty())
- function_name = "&lt;anonymous&gt;";
- html.appendff(" -> {}<br>", function_name);
- }
- m_console_widget.print_html(html.string_view());
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::count()
-{
- auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
- auto counter_value = m_console.counter_increment(label);
- m_console_widget.print_html(String::formatted("{}: {}", label, counter_value));
- return JS::js_undefined();
-}
-
-JS::Value BrowserConsoleClient::count_reset()
-{
- auto label = vm().argument_count() ? vm().argument(0).to_string_without_side_effects() : "default";
- if (m_console.counter_reset(label)) {
- m_console_widget.print_html(String::formatted("{}: 0", label));
- } else {
- m_console_widget.print_html(String::formatted("\"{}\" doesn't have a count", label));
- }
- return JS::js_undefined();
-}
-
-}
diff --git a/Applications/Browser/BrowserConsoleClient.h b/Applications/Browser/BrowserConsoleClient.h
deleted file mode 100644
index e87f6e32b0..0000000000
--- a/Applications/Browser/BrowserConsoleClient.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-#include <LibJS/Console.h>
-#include <LibJS/Forward.h>
-#include <LibWeb/InProcessWebView.h>
-
-namespace Browser {
-
-class ConsoleWidget;
-
-class BrowserConsoleClient final : public JS::ConsoleClient {
-public:
- BrowserConsoleClient(JS::Console& console, ConsoleWidget& console_widget)
- : ConsoleClient(console)
- , m_console_widget(console_widget)
- {
- }
-
-private:
- virtual JS::Value log() override;
- virtual JS::Value info() override;
- virtual JS::Value debug() override;
- virtual JS::Value warn() override;
- virtual JS::Value error() override;
- virtual JS::Value clear() override;
- virtual JS::Value trace() override;
- virtual JS::Value count() override;
- virtual JS::Value count_reset() override;
-
- ConsoleWidget& m_console_widget;
-};
-
-}
diff --git a/Applications/Browser/BrowserWindow.gml b/Applications/Browser/BrowserWindow.gml
deleted file mode 100644
index f6ec7ef1af..0000000000
--- a/Applications/Browser/BrowserWindow.gml
+++ /dev/null
@@ -1,15 +0,0 @@
-@GUI::Widget {
- name: "browser"
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- spacing: 2
- }
-
- @GUI::TabWidget {
- name: "tab_widget"
- container_padding: 0
- uniform_tabs: true
- text_alignment: "CenterLeft"
- }
-}
diff --git a/Applications/Browser/CMakeLists.txt b/Applications/Browser/CMakeLists.txt
deleted file mode 100644
index 4652ec8b11..0000000000
--- a/Applications/Browser/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-compile_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml)
-compile_gml(Tab.gml TabGML.h tab_gml)
-
-set(SOURCES
- BookmarksBarWidget.cpp
- BrowserConsoleClient.cpp
- ConsoleWidget.cpp
- DownloadWidget.cpp
- History.cpp
- InspectorWidget.cpp
- main.cpp
- Tab.cpp
- WindowActions.cpp
- BrowserWindowGML.h
- TabGML.h
-)
-
-serenity_app(Browser ICON app-browser)
-target_link_libraries(Browser LibWeb LibProtocol LibGUI LibDesktop)
diff --git a/Applications/Browser/ConsoleWidget.cpp b/Applications/Browser/ConsoleWidget.cpp
deleted file mode 100644
index 55c545dc55..0000000000
--- a/Applications/Browser/ConsoleWidget.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ConsoleWidget.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/TextBox.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibJS/Interpreter.h>
-#include <LibJS/MarkupGenerator.h>
-#include <LibJS/Parser.h>
-#include <LibJS/Runtime/Error.h>
-#include <LibWeb/DOM/DocumentType.h>
-#include <LibWeb/DOM/ElementFactory.h>
-#include <LibWeb/DOM/Text.h>
-#include <LibWeb/DOMTreeModel.h>
-#include <LibWeb/HTML/HTMLBodyElement.h>
-
-namespace Browser {
-
-ConsoleWidget::ConsoleWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- set_fill_with_background_color(true);
-
- auto base_document = Web::DOM::Document::create();
- base_document->append_child(adopt(*new Web::DOM::DocumentType(base_document)));
- auto html_element = base_document->create_element("html");
- base_document->append_child(html_element);
- auto head_element = base_document->create_element("head");
- html_element->append_child(head_element);
- auto body_element = base_document->create_element("body");
- html_element->append_child(body_element);
- m_output_container = body_element;
-
- m_output_view = add<Web::InProcessWebView>();
- m_output_view->set_document(base_document);
-
- auto& bottom_container = add<GUI::Widget>();
- bottom_container.set_layout<GUI::HorizontalBoxLayout>();
- bottom_container.set_fixed_height(22);
-
- m_input = bottom_container.add<GUI::TextBox>();
- m_input->set_syntax_highlighter(make<GUI::JSSyntaxHighlighter>());
- // FIXME: Syntax Highlighting breaks the cursor's position on non fixed-width fonts.
- m_input->set_font(Gfx::FontDatabase::default_fixed_width_font());
- m_input->set_history_enabled(true);
-
- m_input->on_return_pressed = [this] {
- auto js_source = m_input->text();
-
- // FIXME: An is_blank check to check if there is only whitespace would probably be preferable.
- if (js_source.is_empty())
- return;
-
- m_input->add_current_text_to_history();
- m_input->clear();
-
- print_source_line(js_source);
-
- auto parser = JS::Parser(JS::Lexer(js_source));
- auto program = parser.parse_program();
-
- StringBuilder output_html;
- if (parser.has_errors()) {
- auto error = parser.errors()[0];
- auto hint = error.source_location_hint(js_source);
- if (!hint.is_empty())
- output_html.append(String::formatted("<pre>{}</pre>", escape_html_entities(hint)));
- m_interpreter->vm().throw_exception<JS::SyntaxError>(m_interpreter->global_object(), error.to_string());
- } else {
- m_interpreter->run(m_interpreter->global_object(), *program);
- }
-
- if (m_interpreter->exception()) {
- output_html.append("Uncaught exception: ");
- output_html.append(JS::MarkupGenerator::html_from_value(m_interpreter->exception()->value()));
- print_html(output_html.string_view());
-
- m_interpreter->vm().clear_exception();
- return;
- }
-
- print_html(JS::MarkupGenerator::html_from_value(m_interpreter->vm().last_value()));
- };
-
- set_focus_proxy(m_input);
-
- auto& clear_button = bottom_container.add<GUI::Button>();
- clear_button.set_fixed_size(22, 22);
- clear_button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/delete.png"));
- clear_button.set_tooltip("Clear the console output");
- clear_button.on_click = [this](auto) {
- clear_output();
- };
-}
-
-ConsoleWidget::~ConsoleWidget()
-{
-}
-
-void ConsoleWidget::set_interpreter(WeakPtr<JS::Interpreter> interpreter)
-{
- if (m_interpreter.ptr() == interpreter.ptr())
- return;
-
- m_interpreter = interpreter;
- m_console_client = make<BrowserConsoleClient>(interpreter->global_object().console(), *this);
- interpreter->global_object().console().set_client(*m_console_client.ptr());
-
- clear_output();
-}
-
-void ConsoleWidget::print_source_line(const StringView& source)
-{
- StringBuilder html;
- html.append("<span class=\"repl-indicator\">");
- html.append("&gt; ");
- html.append("</span>");
-
- html.append(JS::MarkupGenerator::html_from_source(source));
-
- print_html(html.string_view());
-}
-
-void ConsoleWidget::print_html(const StringView& line)
-{
- auto paragraph = m_output_container->document().create_element("p");
- paragraph->set_inner_html(line);
-
- m_output_container->append_child(paragraph);
- m_output_container->document().invalidate_layout();
- m_output_container->document().update_layout();
-
- m_output_view->scroll_to_bottom();
-}
-
-void ConsoleWidget::clear_output()
-{
- m_output_container->remove_all_children();
- m_output_view->update();
-}
-
-}
diff --git a/Applications/Browser/ConsoleWidget.h b/Applications/Browser/ConsoleWidget.h
deleted file mode 100644
index 813ceed2ed..0000000000
--- a/Applications/Browser/ConsoleWidget.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2020, Hunter Salyer <thefalsehonesty@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "BrowserConsoleClient.h"
-#include "History.h"
-#include <LibGUI/Widget.h>
-#include <LibJS/Forward.h>
-#include <LibWeb/InProcessWebView.h>
-
-namespace Browser {
-
-class ConsoleWidget final : public GUI::Widget {
- C_OBJECT(ConsoleWidget)
-public:
- virtual ~ConsoleWidget();
-
- void set_interpreter(WeakPtr<JS::Interpreter>);
- void print_source_line(const StringView&);
- void print_html(const StringView&);
- void clear_output();
-
-private:
- ConsoleWidget();
-
- RefPtr<GUI::TextBox> m_input;
- RefPtr<Web::InProcessWebView> m_output_view;
- RefPtr<Web::DOM::Element> m_output_container;
- WeakPtr<JS::Interpreter> m_interpreter;
- OwnPtr<BrowserConsoleClient> m_console_client;
-};
-
-}
diff --git a/Applications/Browser/DownloadWidget.cpp b/Applications/Browser/DownloadWidget.cpp
deleted file mode 100644
index 39d931e216..0000000000
--- a/Applications/Browser/DownloadWidget.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DownloadWidget.h"
-#include <AK/NumberFormat.h>
-#include <AK/SharedBuffer.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/File.h>
-#include <LibCore/FileStream.h>
-#include <LibCore/StandardPaths.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/ImageWidget.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/ProgressBar.h>
-#include <LibGUI/Window.h>
-#include <LibProtocol/Client.h>
-#include <LibWeb/Loader/ResourceLoader.h>
-#include <math.h>
-
-namespace Browser {
-
-DownloadWidget::DownloadWidget(const URL& url)
- : m_url(url)
-{
- {
- StringBuilder builder;
- builder.append(Core::StandardPaths::downloads_directory());
- builder.append('/');
- builder.append(m_url.basename());
- m_destination_path = builder.to_string();
- }
-
- m_elapsed_timer.start();
- m_download = Web::ResourceLoader::the().protocol_client().start_download("GET", url.to_string());
- ASSERT(m_download);
- m_download->on_progress = [this](Optional<u32> total_size, u32 downloaded_size) {
- did_progress(total_size.value(), downloaded_size);
- };
-
- {
- auto file_or_error = Core::File::open(m_destination_path, Core::IODevice::WriteOnly);
- if (file_or_error.is_error()) {
- GUI::MessageBox::show(window(), String::formatted("Cannot open {} for writing", m_destination_path), "Download failed", GUI::MessageBox::Type::Error);
- window()->close();
- return;
- }
- m_output_file_stream = make<Core::OutputFileStream>(*file_or_error.value());
- }
-
- m_download->on_finish = [this](bool success, auto) { did_finish(success); };
- m_download->stream_into(*m_output_file_stream);
-
- set_fill_with_background_color(true);
- auto& layout = set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins({ 4, 4, 4, 4 });
-
- auto& animation_container = add<GUI::Widget>();
- animation_container.set_fixed_height(32);
- auto& animation_layout = animation_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& browser_image = animation_container.add<GUI::ImageWidget>();
- browser_image.load_from_file("/res/graphics/download-animation.gif");
- animation_layout.add_spacer();
-
- auto& source_label = add<GUI::Label>(String::formatted("From: {}", url));
- source_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- source_label.set_fixed_height(16);
-
- m_progress_bar = add<GUI::ProgressBar>();
- m_progress_bar->set_fixed_height(20);
-
- m_progress_label = add<GUI::Label>();
- m_progress_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
- m_progress_label->set_fixed_height(16);
-
- auto& destination_label = add<GUI::Label>(String::formatted("To: {}", m_destination_path));
- destination_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- destination_label.set_fixed_height(16);
-
- auto& button_container = add<GUI::Widget>();
- auto& button_container_layout = button_container.set_layout<GUI::HorizontalBoxLayout>();
- button_container_layout.add_spacer();
- m_cancel_button = button_container.add<GUI::Button>("Cancel");
- m_cancel_button->set_fixed_size(100, 22);
- m_cancel_button->on_click = [this](auto) {
- bool success = m_download->stop();
- ASSERT(success);
- window()->close();
- };
-
- m_close_button = button_container.add<GUI::Button>("OK");
- m_close_button->set_enabled(false);
- m_close_button->set_fixed_size(100, 22);
- m_close_button->on_click = [this](auto) {
- window()->close();
- };
-}
-
-DownloadWidget::~DownloadWidget()
-{
-}
-
-void DownloadWidget::did_progress(Optional<u32> total_size, u32 downloaded_size)
-{
- m_progress_bar->set_min(0);
- if (total_size.has_value()) {
- int percent = roundf(((float)downloaded_size / (float)total_size.value()) * 100.0f);
- window()->set_progress(percent);
- m_progress_bar->set_max(total_size.value());
- } else {
- m_progress_bar->set_max(0);
- }
- m_progress_bar->set_value(downloaded_size);
-
- {
- StringBuilder builder;
- builder.append("Downloaded ");
- builder.append(human_readable_size(downloaded_size));
- builder.appendff(" in {} sec", m_elapsed_timer.elapsed() / 1000);
- m_progress_label->set_text(builder.to_string());
- }
-
- {
- StringBuilder builder;
- if (total_size.has_value()) {
- int percent = roundf(((float)downloaded_size / (float)total_size.value()) * 100);
- builder.appendff("{}%", percent);
- } else {
- builder.append(human_readable_size(downloaded_size));
- }
- builder.append(" of ");
- builder.append(m_url.basename());
- window()->set_title(builder.to_string());
- }
-}
-
-void DownloadWidget::did_finish(bool success)
-{
- dbgln("did_finish, success={}", success);
-
- m_close_button->set_enabled(true);
- m_cancel_button->set_text("Open in Folder");
- m_cancel_button->on_click = [this](auto) {
- Desktop::Launcher::open(URL::create_with_file_protocol(Core::StandardPaths::downloads_directory()));
- window()->close();
- };
- m_cancel_button->update();
-
- if (!success) {
- GUI::MessageBox::show(window(), String::formatted("Download failed for some reason"), "Download failed", GUI::MessageBox::Type::Error);
- window()->close();
- return;
- }
-}
-
-}
diff --git a/Applications/Browser/DownloadWidget.h b/Applications/Browser/DownloadWidget.h
deleted file mode 100644
index 44fc21c60d..0000000000
--- a/Applications/Browser/DownloadWidget.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/URL.h>
-#include <LibCore/ElapsedTimer.h>
-#include <LibCore/FileStream.h>
-#include <LibGUI/ProgressBar.h>
-#include <LibGUI/Widget.h>
-#include <LibProtocol/Download.h>
-
-namespace Browser {
-
-class DownloadWidget final : public GUI::Widget {
- C_OBJECT(DownloadWidget);
-
-public:
- virtual ~DownloadWidget() override;
-
-private:
- explicit DownloadWidget(const URL&);
-
- void did_progress(Optional<u32> total_size, u32 downloaded_size);
- void did_finish(bool success);
-
- URL m_url;
- String m_destination_path;
- RefPtr<Protocol::Download> m_download;
- RefPtr<GUI::ProgressBar> m_progress_bar;
- RefPtr<GUI::Label> m_progress_label;
- RefPtr<GUI::Button> m_cancel_button;
- RefPtr<GUI::Button> m_close_button;
- OwnPtr<Core::OutputFileStream> m_output_file_stream;
- Core::ElapsedTimer m_elapsed_timer;
-};
-
-}
diff --git a/Applications/Browser/History.cpp b/Applications/Browser/History.cpp
deleted file mode 100644
index cecf28477c..0000000000
--- a/Applications/Browser/History.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "History.h"
-
-namespace Browser {
-
-void History::dump() const
-{
- dbgln("Dump {} items(s)", m_items.size());
- int i = 0;
- for (auto& item : m_items) {
- dbgln("[{}] {} {}", i, item, m_current == i ? '*' : ' ');
- ++i;
- }
-}
-
-void History::push(const URL& url)
-{
- m_items.shrink(m_current + 1);
- m_items.append(url);
- m_current++;
-}
-
-URL History::current() const
-{
- if (m_current == -1)
- return {};
- return m_items[m_current];
-}
-
-void History::go_back()
-{
- ASSERT(can_go_back());
- m_current--;
-}
-
-void History::go_forward()
-{
- ASSERT(can_go_forward());
- m_current++;
-}
-
-void History::clear()
-{
- m_items = {};
- m_current = -1;
-}
-
-}
diff --git a/Applications/Browser/History.h b/Applications/Browser/History.h
deleted file mode 100644
index 84fc4151d7..0000000000
--- a/Applications/Browser/History.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/URL.h>
-#include <AK/Vector.h>
-
-namespace Browser {
-
-class History {
-public:
- void dump() const;
-
- void push(const URL&);
- URL current() const;
-
- void go_back();
- void go_forward();
-
- bool can_go_back() { return m_current > 0; }
- bool can_go_forward() { return m_current + 1 < static_cast<int>(m_items.size()); }
-
- void clear();
-
-private:
- Vector<URL> m_items;
- int m_current { -1 };
-};
-
-}
diff --git a/Applications/Browser/InspectorWidget.cpp b/Applications/Browser/InspectorWidget.cpp
deleted file mode 100644
index 7e9111e513..0000000000
--- a/Applications/Browser/InspectorWidget.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "InspectorWidget.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/TreeView.h>
-#include <LibWeb/DOM/Document.h>
-#include <LibWeb/DOM/Element.h>
-#include <LibWeb/DOMTreeModel.h>
-#include <LibWeb/LayoutTreeModel.h>
-#include <LibWeb/StylePropertiesModel.h>
-
-namespace Browser {
-
-void InspectorWidget::set_inspected_node(Web::DOM::Node* node)
-{
- m_document->set_inspected_node(node);
- if (node && node->is_element()) {
- auto& element = downcast<Web::DOM::Element>(*node);
- if (element.specified_css_values()) {
- m_style_table_view->set_model(Web::StylePropertiesModel::create(*element.specified_css_values()));
- m_computed_style_table_view->set_model(Web::StylePropertiesModel::create(*element.computed_style()));
- }
- } else {
- m_style_table_view->set_model(nullptr);
- m_computed_style_table_view->set_model(nullptr);
- }
-}
-
-InspectorWidget::InspectorWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- auto& splitter = add<GUI::VerticalSplitter>();
-
- auto& top_tab_widget = splitter.add<GUI::TabWidget>();
-
- m_dom_tree_view = top_tab_widget.add_tab<GUI::TreeView>("DOM");
- m_dom_tree_view->on_selection = [this](auto& index) {
- auto* node = static_cast<Web::DOM::Node*>(index.internal_data());
- set_inspected_node(node);
- };
-
- m_layout_tree_view = top_tab_widget.add_tab<GUI::TreeView>("Layout");
- m_layout_tree_view->on_selection = [this](auto& index) {
- auto* node = static_cast<Web::Layout::Node*>(index.internal_data());
- set_inspected_node(node->dom_node());
- };
-
- auto& bottom_tab_widget = splitter.add<GUI::TabWidget>();
-
- m_style_table_view = bottom_tab_widget.add_tab<GUI::TableView>("Styles");
- m_computed_style_table_view = bottom_tab_widget.add_tab<GUI::TableView>("Computed");
-}
-
-InspectorWidget::~InspectorWidget()
-{
-}
-
-void InspectorWidget::set_document(Web::DOM::Document* document)
-{
- if (m_document == document)
- return;
- m_document = document;
- m_dom_tree_view->set_model(Web::DOMTreeModel::create(*document));
- m_layout_tree_view->set_model(Web::LayoutTreeModel::create(*document));
-}
-
-}
diff --git a/Applications/Browser/InspectorWidget.h b/Applications/Browser/InspectorWidget.h
deleted file mode 100644
index 37f0f95754..0000000000
--- a/Applications/Browser/InspectorWidget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-#include <LibWeb/Forward.h>
-
-namespace Browser {
-
-class InspectorWidget final : public GUI::Widget {
- C_OBJECT(InspectorWidget)
-public:
- virtual ~InspectorWidget();
-
- void set_document(Web::DOM::Document*);
-
-private:
- InspectorWidget();
-
- void set_inspected_node(Web::DOM::Node*);
-
- RefPtr<GUI::TreeView> m_dom_tree_view;
- RefPtr<GUI::TreeView> m_layout_tree_view;
- RefPtr<GUI::TableView> m_style_table_view;
- RefPtr<GUI::TableView> m_computed_style_table_view;
- RefPtr<Web::DOM::Document> m_document;
-};
-
-}
diff --git a/Applications/Browser/Tab.cpp b/Applications/Browser/Tab.cpp
deleted file mode 100644
index ea23d61d73..0000000000
--- a/Applications/Browser/Tab.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Tab.h"
-#include "BookmarksBarWidget.h"
-#include "Browser.h"
-#include "ConsoleWidget.h"
-#include "DownloadWidget.h"
-#include "InspectorWidget.h"
-#include "WindowActions.h"
-#include <AK/StringBuilder.h>
-#include <Applications/Browser/TabGML.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/StatusBar.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/Window.h>
-#include <LibJS/Interpreter.h>
-#include <LibWeb/CSS/Parser/CSSParser.h>
-#include <LibWeb/DOM/Element.h>
-#include <LibWeb/DOMTreeModel.h>
-#include <LibWeb/Dump.h>
-#include <LibWeb/InProcessWebView.h>
-#include <LibWeb/Layout/BlockBox.h>
-#include <LibWeb/Layout/InitialContainingBlockBox.h>
-#include <LibWeb/Layout/InlineNode.h>
-#include <LibWeb/Layout/Node.h>
-#include <LibWeb/Loader/ResourceLoader.h>
-#include <LibWeb/OutOfProcessWebView.h>
-#include <LibWeb/Page/Frame.h>
-
-namespace Browser {
-
-URL url_from_user_input(const String& input)
-{
- auto url = URL(input);
- if (url.is_valid())
- return url;
-
- StringBuilder builder;
- builder.append("http://");
- builder.append(input);
- return URL(builder.build());
-}
-
-static void start_download(const URL& url)
-{
- auto window = GUI::Window::construct();
- window->resize(300, 150);
- window->set_title(String::formatted("0% of {}", url.basename()));
- window->set_resizable(false);
- window->set_main_widget<DownloadWidget>(url);
- window->show();
- [[maybe_unused]] auto& unused = window.leak_ref();
-}
-
-Tab::Tab(Type type)
- : m_type(type)
-{
- load_from_gml(tab_gml);
-
- m_toolbar_container = *find_descendant_of_type_named<GUI::ToolBarContainer>("toolbar_container");
- auto& toolbar = *find_descendant_of_type_named<GUI::ToolBar>("toolbar");
-
- auto& webview_container = *find_descendant_of_type_named<GUI::Widget>("webview_container");
-
- if (m_type == Type::InProcessWebView)
- m_page_view = webview_container.add<Web::InProcessWebView>();
- else
- m_web_content_view = webview_container.add<Web::OutOfProcessWebView>();
-
- m_go_back_action = GUI::CommonActions::make_go_back_action([this](auto&) { go_back(); }, this);
- m_go_forward_action = GUI::CommonActions::make_go_forward_action([this](auto&) { go_forward(); }, this);
-
- toolbar.add_action(*m_go_back_action);
- toolbar.add_action(*m_go_forward_action);
-
- toolbar.add_action(GUI::CommonActions::make_go_home_action([this](auto&) { load(g_home_url); }, this));
- m_reload_action = GUI::CommonActions::make_reload_action([this](auto&) { reload(); }, this);
-
- toolbar.add_action(*m_reload_action);
-
- m_location_box = toolbar.add<GUI::TextBox>();
- m_location_box->set_placeholder("Address");
-
- m_location_box->on_return_pressed = [this] {
- auto url = url_from_user_input(m_location_box->text());
- load(url);
- view().set_focus(true);
- };
-
- m_location_box->add_custom_context_menu_action(GUI::Action::create("Paste & Go", [this](auto&) {
- m_location_box->set_text(GUI::Clipboard::the().data());
- m_location_box->on_return_pressed();
- }));
-
- m_bookmark_button = toolbar.add<GUI::Button>();
- m_bookmark_button->set_button_style(Gfx::ButtonStyle::CoolBar);
- m_bookmark_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/bookmark-contour.png"));
- m_bookmark_button->set_fixed_size(22, 22);
-
- m_bookmark_button->on_click = [this](auto) {
- auto url = this->url().to_string();
- if (BookmarksBarWidget::the().contains_bookmark(url)) {
- BookmarksBarWidget::the().remove_bookmark(url);
- } else {
- BookmarksBarWidget::the().add_bookmark(url, m_title);
- }
- update_bookmark_button(url);
- };
-
- hooks().on_load_start = [this](auto& url) {
- m_location_box->set_icon(nullptr);
- m_location_box->set_text(url.to_string());
-
- // don't add to history if back or forward is pressed
- if (!m_is_history_navigation)
- m_history.push(url);
- m_is_history_navigation = false;
-
- update_actions();
- update_bookmark_button(url.to_string());
- };
-
- hooks().on_link_click = [this](auto& url, auto& target, unsigned modifiers) {
- if (target == "_blank" || modifiers == Mod_Ctrl) {
- on_tab_open_request(url);
- } else {
- load(url);
- }
- };
-
- m_link_context_menu = GUI::Menu::construct();
- auto link_default_action = GUI::Action::create("Open", [this](auto&) {
- hooks().on_link_click(m_link_context_menu_url, "", 0);
- });
- m_link_context_menu->add_action(link_default_action);
- m_link_context_menu_default_action = link_default_action;
- m_link_context_menu->add_action(GUI::Action::create("Open in new tab", [this](auto&) {
- hooks().on_link_click(m_link_context_menu_url, "_blank", 0);
- }));
- m_link_context_menu->add_separator();
- m_link_context_menu->add_action(GUI::Action::create("Copy link", [this](auto&) {
- GUI::Clipboard::the().set_plain_text(m_link_context_menu_url.to_string());
- }));
- m_link_context_menu->add_separator();
- m_link_context_menu->add_action(GUI::Action::create("Download", [this](auto&) {
- start_download(m_link_context_menu_url);
- }));
-
- hooks().on_link_context_menu_request = [this](auto& url, auto& screen_position) {
- m_link_context_menu_url = url;
- m_link_context_menu->popup(screen_position, m_link_context_menu_default_action);
- };
-
- m_image_context_menu = GUI::Menu::construct();
- m_image_context_menu->add_action(GUI::Action::create("Open image", [this](auto&) {
- hooks().on_link_click(m_image_context_menu_url, "", 0);
- }));
- m_image_context_menu->add_action(GUI::Action::create("Open image in new tab", [this](auto&) {
- hooks().on_link_click(m_image_context_menu_url, "_blank", 0);
- }));
- m_image_context_menu->add_separator();
- m_image_context_menu->add_action(GUI::Action::create("Copy image", [this](auto&) {
- if (m_image_context_menu_bitmap.is_valid())
- GUI::Clipboard::the().set_bitmap(*m_image_context_menu_bitmap.bitmap());
- }));
- m_image_context_menu->add_action(GUI::Action::create("Copy image URL", [this](auto&) {
- GUI::Clipboard::the().set_plain_text(m_image_context_menu_url.to_string());
- }));
- m_image_context_menu->add_separator();
- m_image_context_menu->add_action(GUI::Action::create("Download", [this](auto&) {
- start_download(m_image_context_menu_url);
- }));
-
- hooks().on_image_context_menu_request = [this](auto& image_url, auto& screen_position, const Gfx::ShareableBitmap& shareable_bitmap) {
- m_image_context_menu_url = image_url;
- m_image_context_menu_bitmap = shareable_bitmap;
- m_image_context_menu->popup(screen_position);
- };
-
- hooks().on_link_middle_click = [this](auto& href, auto&, auto) {
- hooks().on_link_click(href, "_blank", 0);
- };
-
- hooks().on_title_change = [this](auto& title) {
- if (title.is_null()) {
- m_title = url().to_string();
- } else {
- m_title = title;
- }
- if (on_title_change)
- on_title_change(m_title);
- };
-
- hooks().on_favicon_change = [this](auto& icon) {
- m_icon = icon;
- m_location_box->set_icon(&icon);
- if (on_favicon_change)
- on_favicon_change(icon);
- };
-
- // FIXME: Support JS console in multi-process mode.
- if (m_type == Type::InProcessWebView) {
- hooks().on_set_document = [this](auto* document) {
- if (document && m_console_window) {
- auto* console_widget = static_cast<ConsoleWidget*>(m_console_window->main_widget());
- console_widget->set_interpreter(document->interpreter().make_weak_ptr());
- }
- };
- }
-
- auto focus_location_box_action = GUI::Action::create(
- "Focus location box", { Mod_Ctrl, Key_L }, [this](auto&) {
- m_location_box->select_all();
- m_location_box->set_focus(true);
- },
- this);
-
- m_statusbar = *find_descendant_of_type_named<GUI::StatusBar>("statusbar");
-
- hooks().on_link_hover = [this](auto& url) {
- if (url.is_valid())
- m_statusbar->set_text(url.to_string());
- else
- m_statusbar->set_text("");
- };
-
- hooks().on_url_drop = [this](auto& url) {
- load(url);
- };
-
- m_menubar = GUI::MenuBar::construct();
-
- auto& app_menu = m_menubar->add_menu("Browser");
- app_menu.add_action(WindowActions::the().create_new_tab_action());
- app_menu.add_action(GUI::Action::create(
- "Close tab", { Mod_Ctrl, Key_W }, Gfx::Bitmap::load_from_file("/res/icons/16x16/close-tab.png"), [this](auto&) {
- on_tab_close_request(*this);
- },
- this));
-
- app_menu.add_action(*m_reload_action);
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- }));
-
- auto& view_menu = m_menubar->add_menu("View");
- view_menu.add_action(GUI::CommonActions::make_fullscreen_action(
- [this](auto&) {
- window()->set_fullscreen(!window()->is_fullscreen());
-
- auto is_fullscreen = window()->is_fullscreen();
- auto* tab_widget = static_cast<GUI::TabWidget*>(parent_widget());
- tab_widget->set_bar_visible(!is_fullscreen && tab_widget->children().size() > 1);
- m_toolbar_container->set_visible(!is_fullscreen);
- m_statusbar->set_visible(!is_fullscreen);
- },
- this));
-
- auto view_source_action = GUI::Action::create(
- "View source", { Mod_Ctrl, Key_U }, [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- ASSERT(m_page_view->document());
- auto url = m_page_view->document()->url().to_string();
- auto source = m_page_view->document()->source();
- auto window = GUI::Window::construct();
- auto& editor = window->set_main_widget<GUI::TextEditor>();
- editor.set_text(source);
- editor.set_mode(GUI::TextEditor::ReadOnly);
- editor.set_ruler_visible(true);
- window->resize(640, 480);
- window->set_title(url);
- window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-text.png"));
- window->show();
- [[maybe_unused]] auto& unused = window.leak_ref();
- } else {
- TODO();
- }
- },
- this);
-
- auto inspect_dom_tree_action = GUI::Action::create(
- "Inspect DOM tree", { Mod_None, Key_F12 }, [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- if (!m_dom_inspector_window) {
- m_dom_inspector_window = GUI::Window::construct();
- m_dom_inspector_window->resize(300, 500);
- m_dom_inspector_window->set_title("DOM inspector");
- m_dom_inspector_window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/inspector-object.png"));
- m_dom_inspector_window->set_main_widget<InspectorWidget>();
- }
- auto* inspector_widget = static_cast<InspectorWidget*>(m_dom_inspector_window->main_widget());
- inspector_widget->set_document(m_page_view->document());
- m_dom_inspector_window->show();
- m_dom_inspector_window->move_to_front();
- } else {
- TODO();
- }
- },
- this);
-
- auto& inspect_menu = m_menubar->add_menu("Inspect");
- inspect_menu.add_action(*view_source_action);
- inspect_menu.add_action(*inspect_dom_tree_action);
-
- inspect_menu.add_action(GUI::Action::create(
- "Open JS Console", { Mod_Ctrl, Key_I }, [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- if (!m_console_window) {
- m_console_window = GUI::Window::construct();
- m_console_window->resize(500, 300);
- m_console_window->set_title("JS Console");
- m_console_window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-javascript.png"));
- m_console_window->set_main_widget<ConsoleWidget>();
- }
- auto* console_widget = static_cast<ConsoleWidget*>(m_console_window->main_widget());
- console_widget->set_interpreter(m_page_view->document()->interpreter().make_weak_ptr());
- m_console_window->show();
- m_console_window->move_to_front();
- } else {
- TODO();
- }
- },
- this));
-
- auto& debug_menu = m_menubar->add_menu("Debug");
- debug_menu.add_action(GUI::Action::create(
- "Dump DOM tree", [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- Web::dump_tree(*m_page_view->document());
- } else {
- TODO();
- }
- },
- this));
- debug_menu.add_action(GUI::Action::create(
- "Dump Layout tree", [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- Web::dump_tree(*m_page_view->document()->layout_node());
- } else {
- TODO();
- }
- },
- this));
- debug_menu.add_action(GUI::Action::create(
- "Dump Style sheets", [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- for (auto& sheet : m_page_view->document()->style_sheets().sheets()) {
- Web::dump_sheet(sheet);
- }
- } else {
- TODO();
- }
- },
- this));
- debug_menu.add_action(GUI::Action::create("Dump history", { Mod_Ctrl, Key_H }, [&](auto&) {
- m_history.dump();
- }));
- debug_menu.add_separator();
- auto line_box_borders_action = GUI::Action::create_checkable(
- "Line box borders", [this](auto& action) {
- if (m_type == Type::InProcessWebView) {
- m_page_view->set_should_show_line_box_borders(action.is_checked());
- m_page_view->update();
- } else {
- TODO();
- }
- },
- this);
- line_box_borders_action->set_checked(false);
- debug_menu.add_action(line_box_borders_action);
-
- debug_menu.add_separator();
- debug_menu.add_action(GUI::Action::create("Collect garbage", { Mod_Ctrl | Mod_Shift, Key_G }, [this](auto&) {
- if (m_type == Type::InProcessWebView) {
- if (auto* document = m_page_view->document()) {
- document->interpreter().heap().collect_garbage(JS::Heap::CollectionType::CollectGarbage, true);
- }
- } else {
- TODO();
- }
- }));
-
- auto& bookmarks_menu = m_menubar->add_menu("Bookmarks");
- bookmarks_menu.add_action(WindowActions::the().show_bookmarks_bar_action());
-
- auto& help_menu = m_menubar->add_menu("Help");
- help_menu.add_action(WindowActions::the().about_action());
-
- m_tab_context_menu = GUI::Menu::construct();
- m_tab_context_menu->add_action(GUI::Action::create("Reload Tab", [this](auto&) {
- m_reload_action->activate();
- }));
- m_tab_context_menu->add_action(GUI::Action::create("Close Tab", [this](auto&) {
- on_tab_close_request(*this);
- }));
-
- m_page_context_menu = GUI::Menu::construct();
- m_page_context_menu->add_action(*m_go_back_action);
- m_page_context_menu->add_action(*m_go_forward_action);
- m_page_context_menu->add_action(*m_reload_action);
- m_page_context_menu->add_separator();
- m_page_context_menu->add_action(*view_source_action);
- m_page_context_menu->add_action(*inspect_dom_tree_action);
- hooks().on_context_menu_request = [&](auto& screen_position) {
- m_page_context_menu->popup(screen_position);
- };
-}
-
-Tab::~Tab()
-{
-}
-
-void Tab::load(const URL& url, LoadType load_type)
-{
- m_is_history_navigation = (load_type == LoadType::HistoryNavigation);
-
- if (m_type == Type::InProcessWebView)
- m_page_view->load(url);
- else
- m_web_content_view->load(url);
-}
-
-URL Tab::url() const
-{
- if (m_type == Type::InProcessWebView)
- return m_page_view->url();
- return m_web_content_view->url();
-}
-
-void Tab::reload()
-{
- load(url());
-}
-
-void Tab::go_back()
-{
- m_history.go_back();
- update_actions();
- load(m_history.current(), LoadType::HistoryNavigation);
-}
-
-void Tab::go_forward()
-{
- m_history.go_forward();
- update_actions();
- load(m_history.current(), LoadType::HistoryNavigation);
-}
-
-void Tab::update_actions()
-{
- m_go_back_action->set_enabled(m_history.can_go_back());
- m_go_forward_action->set_enabled(m_history.can_go_forward());
-}
-
-void Tab::update_bookmark_button(const String& url)
-{
- if (BookmarksBarWidget::the().contains_bookmark(url)) {
- m_bookmark_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/bookmark-filled.png"));
- m_bookmark_button->set_tooltip("Remove Bookmark");
- } else {
- m_bookmark_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/bookmark-contour.png"));
- m_bookmark_button->set_tooltip("Add Bookmark");
- }
-}
-
-void Tab::did_become_active()
-{
- Web::ResourceLoader::the().on_load_counter_change = [this] {
- if (Web::ResourceLoader::the().pending_loads() == 0) {
- m_statusbar->set_text("");
- return;
- }
- m_statusbar->set_text(String::formatted("Loading ({} pending resources...)", Web::ResourceLoader::the().pending_loads()));
- };
-
- BookmarksBarWidget::the().on_bookmark_click = [this](auto& url, unsigned modifiers) {
- if (modifiers & Mod_Ctrl)
- on_tab_open_request(url);
- else
- load(url);
- };
-
- BookmarksBarWidget::the().on_bookmark_hover = [this](auto&, auto& url) {
- m_statusbar->set_text(url);
- };
-
- BookmarksBarWidget::the().remove_from_parent();
- m_toolbar_container->add_child(BookmarksBarWidget::the());
-
- auto is_fullscreen = window()->is_fullscreen();
- m_toolbar_container->set_visible(!is_fullscreen);
- m_statusbar->set_visible(!is_fullscreen);
-
- GUI::Application::the()->set_menubar(m_menubar);
-}
-
-void Tab::context_menu_requested(const Gfx::IntPoint& screen_position)
-{
- m_tab_context_menu->popup(screen_position);
-}
-
-GUI::Widget& Tab::view()
-{
- if (m_type == Type::InProcessWebView)
- return *m_page_view;
- return *m_web_content_view;
-}
-
-Web::WebViewHooks& Tab::hooks()
-{
- if (m_type == Type::InProcessWebView)
- return *m_page_view;
- return *m_web_content_view;
-}
-
-}
diff --git a/Applications/Browser/Tab.gml b/Applications/Browser/Tab.gml
deleted file mode 100644
index 24c7456d77..0000000000
--- a/Applications/Browser/Tab.gml
+++ /dev/null
@@ -1,22 +0,0 @@
-@GUI::Widget {
- layout: @GUI::VerticalBoxLayout {
- }
-
- @GUI::ToolBarContainer {
- name: "toolbar_container"
-
- @GUI::ToolBar {
- name: "toolbar"
- }
- }
-
- @GUI::Widget {
- name: "webview_container"
- layout: @GUI::VerticalBoxLayout {
- }
- }
-
- @GUI::StatusBar {
- name: "statusbar"
- }
-}
diff --git a/Applications/Browser/Tab.h b/Applications/Browser/Tab.h
deleted file mode 100644
index 79f86e4931..0000000000
--- a/Applications/Browser/Tab.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "History.h"
-#include <AK/URL.h>
-#include <LibGUI/Widget.h>
-#include <LibGfx/ShareableBitmap.h>
-#include <LibHTTP/HttpJob.h>
-#include <LibWeb/Forward.h>
-
-namespace Web {
-class OutOfProcessWebView;
-class WebViewHooks;
-}
-
-namespace Browser {
-
-class Tab final : public GUI::Widget {
- C_OBJECT(Tab);
-
-public:
- enum class Type {
- InProcessWebView,
- OutOfProcessWebView,
- };
-
- virtual ~Tab() override;
-
- URL url() const;
-
- enum class LoadType {
- Normal,
- HistoryNavigation,
- };
-
- void load(const URL&, LoadType = LoadType::Normal);
- void reload();
- void go_back();
- void go_forward();
-
- void did_become_active();
- void context_menu_requested(const Gfx::IntPoint& screen_position);
-
- Function<void(String)> on_title_change;
- Function<void(const URL&)> on_tab_open_request;
- Function<void(Tab&)> on_tab_close_request;
- Function<void(const Gfx::Bitmap&)> on_favicon_change;
-
- const String& title() const { return m_title; }
- const Gfx::Bitmap* icon() const { return m_icon; }
-
- GUI::Widget& view();
-
-private:
- explicit Tab(Type);
-
- Web::WebViewHooks& hooks();
- void update_actions();
- void update_bookmark_button(const String& url);
-
- Type m_type;
-
- History m_history;
-
- RefPtr<Web::InProcessWebView> m_page_view;
- RefPtr<Web::OutOfProcessWebView> m_web_content_view;
-
- RefPtr<GUI::Action> m_go_back_action;
- RefPtr<GUI::Action> m_go_forward_action;
- RefPtr<GUI::Action> m_reload_action;
- RefPtr<GUI::TextBox> m_location_box;
- RefPtr<GUI::Button> m_bookmark_button;
- RefPtr<GUI::Window> m_dom_inspector_window;
- RefPtr<GUI::Window> m_console_window;
- RefPtr<GUI::StatusBar> m_statusbar;
- RefPtr<GUI::MenuBar> m_menubar;
- RefPtr<GUI::ToolBarContainer> m_toolbar_container;
-
- RefPtr<GUI::Menu> m_link_context_menu;
- RefPtr<GUI::Action> m_link_context_menu_default_action;
- URL m_link_context_menu_url;
-
- RefPtr<GUI::Menu> m_image_context_menu;
- Gfx::ShareableBitmap m_image_context_menu_bitmap;
- URL m_image_context_menu_url;
-
- RefPtr<GUI::Menu> m_tab_context_menu;
- RefPtr<GUI::Menu> m_page_context_menu;
-
- String m_title;
- RefPtr<const Gfx::Bitmap> m_icon;
-
- bool m_is_history_navigation { false };
-};
-
-URL url_from_user_input(const String& input);
-
-}
diff --git a/Applications/Browser/WindowActions.cpp b/Applications/Browser/WindowActions.cpp
deleted file mode 100644
index ca0b12bd84..0000000000
--- a/Applications/Browser/WindowActions.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "WindowActions.h"
-#include <LibGUI/Icon.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-
-namespace Browser {
-
-static WindowActions* s_the;
-
-WindowActions& WindowActions::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-WindowActions::WindowActions(GUI::Window& window)
-{
- ASSERT(!s_the);
- s_the = this;
- m_create_new_tab_action = GUI::Action::create(
- "New tab", { Mod_Ctrl, Key_T }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new-tab.png"), [this](auto&) {
- if (on_create_new_tab)
- on_create_new_tab();
- },
- &window);
-
- m_next_tab_action = GUI::Action::create(
- "Next tab", { Mod_Ctrl, Key_PageDown }, [this](auto&) {
- if (on_next_tab)
- on_next_tab();
- },
- &window);
-
- m_previous_tab_action = GUI::Action::create(
- "Previous tab", { Mod_Ctrl, Key_PageUp }, [this](auto&) {
- if (on_previous_tab)
- on_previous_tab();
- },
- &window);
-
- m_about_action = GUI::Action::create(
- "About Browser", GUI::Icon::default_icon("app-browser").bitmap_for_size(16), [this](const GUI::Action&) {
- if (on_about)
- on_about();
- },
- &window);
- m_show_bookmarks_bar_action = GUI::Action::create_checkable(
- "Show bookmarks bar",
- [this](auto& action) {
- if (on_show_bookmarks_bar)
- on_show_bookmarks_bar(action);
- },
- &window);
-}
-
-}
diff --git a/Applications/Browser/WindowActions.h b/Applications/Browser/WindowActions.h
deleted file mode 100644
index 3212321837..0000000000
--- a/Applications/Browser/WindowActions.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Action.h>
-
-namespace Browser {
-
-class WindowActions {
-public:
- static WindowActions& the();
-
- WindowActions(GUI::Window&);
-
- Function<void()> on_create_new_tab;
- Function<void()> on_next_tab;
- Function<void()> on_previous_tab;
- Function<void()> on_about;
- Function<void(GUI::Action&)> on_show_bookmarks_bar;
-
- GUI::Action& create_new_tab_action() { return *m_create_new_tab_action; }
- GUI::Action& next_tab_action() { return *m_next_tab_action; }
- GUI::Action& previous_tab_action() { return *m_previous_tab_action; }
- GUI::Action& about_action() { return *m_about_action; }
- GUI::Action& show_bookmarks_bar_action() { return *m_show_bookmarks_bar_action; }
-
-private:
- RefPtr<GUI::Action> m_create_new_tab_action;
- RefPtr<GUI::Action> m_next_tab_action;
- RefPtr<GUI::Action> m_previous_tab_action;
- RefPtr<GUI::Action> m_about_action;
- RefPtr<GUI::Action> m_show_bookmarks_bar_action;
-};
-
-}
diff --git a/Applications/Browser/main.cpp b/Applications/Browser/main.cpp
deleted file mode 100644
index d83b68f5f4..0000000000
--- a/Applications/Browser/main.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BookmarksBarWidget.h"
-#include "Browser.h"
-#include "InspectorWidget.h"
-#include "Tab.h"
-#include "WindowActions.h"
-#include <AK/StringBuilder.h>
-#include <Applications/Browser/BrowserWindowGML.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/File.h>
-#include <LibCore/StandardPaths.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/AboutDialog.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibWeb/Loader/ContentFilter.h>
-#include <LibWeb/Loader/ResourceLoader.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-namespace Browser {
-
-String g_home_url;
-bool g_multi_process = false;
-
-static String bookmarks_file_path()
-{
- StringBuilder builder;
- builder.append(Core::StandardPaths::config_directory());
- builder.append("/bookmarks.json");
- return builder.to_string();
-}
-
-}
-
-int main(int argc, char** argv)
-{
- if (getuid() == 0) {
- warnln("Refusing to run as root");
- return 1;
- }
-
- if (pledge("stdio shared_buffer accept unix cpath rpath wpath fattr sendfd recvfd", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* specified_url = nullptr;
-
- Core::ArgsParser args_parser;
- args_parser.add_option(Browser::g_multi_process, "Multi-process mode", "multi-process", 'm');
- args_parser.add_positional_argument(specified_url, "URL to open", "url", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
-
- auto app = GUI::Application::construct(argc, argv);
-
- // Connect to the ProtocolServer immediately so we can drop the "unix" pledge.
- Web::ResourceLoader::the();
-
- // Connect to LaunchServer immediately and let it know that we won't ask for anything other than opening
- // the user's downloads directory.
- // FIXME: This should go away with a standalone download manager at some point.
- if (!Desktop::Launcher::add_allowed_url(URL::create_with_file_protocol(Core::StandardPaths::downloads_directory()))
- || !Desktop::Launcher::seal_allowlist()) {
- warnln("Failed to set up allowed launch URLs");
- return 1;
- }
-
- if (pledge("stdio shared_buffer accept unix cpath rpath wpath sendfd recvfd", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/home", "rwc") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/etc/passwd", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/image", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/webcontent", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- auto app_icon = GUI::Icon::default_icon("app-browser");
-
- auto m_config = Core::ConfigFile::get_for_app("Browser");
- Browser::g_home_url = m_config->read_entry("Preferences", "Home", "about:blank");
-
- auto ad_filter_list_or_error = Core::File::open(String::formatted("{}/BrowserContentFilters.txt", Core::StandardPaths::config_directory()), Core::IODevice::ReadOnly);
- if (!ad_filter_list_or_error.is_error()) {
- auto& ad_filter_list = *ad_filter_list_or_error.value();
- while (!ad_filter_list.eof()) {
- auto line = ad_filter_list.read_line();
- if (line.is_empty())
- continue;
- Web::ContentFilter::the().add_pattern(line);
- }
- }
-
- bool bookmarksbar_enabled = true;
- auto bookmarks_bar = Browser::BookmarksBarWidget::construct(Browser::bookmarks_file_path(), bookmarksbar_enabled);
-
- auto window = GUI::Window::construct();
- window->resize(640, 480);
- window->set_icon(app_icon.bitmap_for_size(16));
- window->set_title("Browser");
-
- auto& widget = window->set_main_widget<GUI::Widget>();
- widget.load_from_gml(browser_window_gml);
-
- auto& tab_widget = *widget.find_descendant_of_type_named<GUI::TabWidget>("tab_widget");
-
- auto default_favicon = Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png");
- ASSERT(default_favicon);
-
- tab_widget.on_change = [&](auto& active_widget) {
- auto& tab = static_cast<Browser::Tab&>(active_widget);
- window->set_title(String::formatted("{} - Browser", tab.title()));
- tab.did_become_active();
- };
-
- tab_widget.on_middle_click = [&](auto& clicked_widget) {
- auto& tab = static_cast<Browser::Tab&>(clicked_widget);
- tab.on_tab_close_request(tab);
- };
-
- tab_widget.on_context_menu_request = [&](auto& clicked_widget, const GUI::ContextMenuEvent& context_menu_event) {
- auto& tab = static_cast<Browser::Tab&>(clicked_widget);
- tab.context_menu_requested(context_menu_event.screen_position());
- };
-
- Browser::WindowActions window_actions(*window);
-
- Function<void(URL url, bool activate)> create_new_tab;
- create_new_tab = [&](auto url, auto activate) {
- auto type = Browser::g_multi_process ? Browser::Tab::Type::OutOfProcessWebView : Browser::Tab::Type::InProcessWebView;
- auto& new_tab = tab_widget.add_tab<Browser::Tab>("New tab", type);
-
- tab_widget.set_bar_visible(!window->is_fullscreen() && tab_widget.children().size() > 1);
- tab_widget.set_tab_icon(new_tab, default_favicon);
-
- new_tab.on_title_change = [&](auto title) {
- tab_widget.set_tab_title(new_tab, title);
- if (tab_widget.active_widget() == &new_tab)
- window->set_title(String::formatted("{} - Browser", title));
- };
-
- new_tab.on_favicon_change = [&](auto& bitmap) {
- tab_widget.set_tab_icon(new_tab, &bitmap);
- };
-
- new_tab.on_tab_open_request = [&](auto& url) {
- create_new_tab(url, true);
- };
-
- new_tab.on_tab_close_request = [&](auto& tab) {
- tab_widget.deferred_invoke([&](auto&) {
- tab_widget.remove_tab(tab);
- tab_widget.set_bar_visible(!window->is_fullscreen() && tab_widget.children().size() > 1);
- if (tab_widget.children().is_empty())
- app->quit();
- });
- };
-
- new_tab.load(url);
-
- dbgln("Added new tab {:p}, loading {}", &new_tab, url);
-
- if (activate)
- tab_widget.set_active_widget(&new_tab);
- };
-
- URL first_url = Browser::g_home_url;
- if (specified_url) {
- if (Core::File::exists(specified_url)) {
- first_url = URL::create_with_file_protocol(Core::File::real_path_for(specified_url));
- } else {
- first_url = Browser::url_from_user_input(specified_url);
- }
- }
-
- window_actions.on_create_new_tab = [&] {
- create_new_tab(Browser::g_home_url, true);
- };
-
- window_actions.on_next_tab = [&] {
- tab_widget.activate_next_tab();
- };
-
- window_actions.on_previous_tab = [&] {
- tab_widget.activate_previous_tab();
- };
-
- window_actions.on_about = [&] {
- GUI::AboutDialog::show("Browser", app_icon.bitmap_for_size(32), window);
- };
-
- window_actions.on_show_bookmarks_bar = [&](auto& action) {
- Browser::BookmarksBarWidget::the().set_visible(action.is_checked());
- };
- window_actions.show_bookmarks_bar_action().set_checked(bookmarksbar_enabled);
-
- create_new_tab(first_url, true);
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/CMakeLists.txt b/Applications/CMakeLists.txt
deleted file mode 100644
index 41803202e6..0000000000
--- a/Applications/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-add_subdirectory(About)
-add_subdirectory(Browser)
-add_subdirectory(Calculator)
-add_subdirectory(Calendar)
-add_subdirectory(CrashReporter)
-add_subdirectory(Debugger)
-add_subdirectory(DisplaySettings)
-add_subdirectory(FileManager)
-add_subdirectory(FontEditor)
-add_subdirectory(Help)
-add_subdirectory(HexEditor)
-add_subdirectory(IRCClient)
-add_subdirectory(KeyboardMapper)
-add_subdirectory(KeyboardSettings)
-add_subdirectory(MouseSettings)
-add_subdirectory(Piano)
-add_subdirectory(PixelPaint)
-add_subdirectory(QuickShow)
-add_subdirectory(SoundPlayer)
-add_subdirectory(SpaceAnalyzer)
-add_subdirectory(Spreadsheet)
-add_subdirectory(SystemMonitor)
-add_subdirectory(ThemeEditor)
-add_subdirectory(Terminal)
-add_subdirectory(TextEditor)
-add_subdirectory(Welcome)
diff --git a/Applications/Calculator/CMakeLists.txt b/Applications/Calculator/CMakeLists.txt
deleted file mode 100644
index d72624c308..0000000000
--- a/Applications/Calculator/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-compile_gml(CalculatorWindow.gml CalculatorGML.h calculator_gml)
-set(SOURCES
- main.cpp
- Calculator.cpp
- CalculatorWidget.cpp
- Keypad.cpp
- CalculatorGML.h
-)
-
-serenity_app(Calculator ICON app-calculator)
-target_link_libraries(Calculator LibGUI)
diff --git a/Applications/Calculator/Calculator.cpp b/Applications/Calculator/Calculator.cpp
deleted file mode 100644
index c324fb84b9..0000000000
--- a/Applications/Calculator/Calculator.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Calculator.h"
-#include <AK/Assertions.h>
-#include <math.h>
-
-Calculator::Calculator()
-{
-}
-
-Calculator::~Calculator()
-{
-}
-
-double Calculator::begin_operation(Operation operation, double argument)
-{
- double res = 0.0;
-
- switch (operation) {
- case Operation::None:
- ASSERT_NOT_REACHED();
-
- case Operation::Add:
- case Operation::Subtract:
- case Operation::Multiply:
- case Operation::Divide:
- m_saved_argument = argument;
- m_operation_in_progress = operation;
- return argument;
-
- case Operation::Sqrt:
- if (argument < 0.0) {
- m_has_error = true;
- return argument;
- }
- res = sqrt(argument);
- clear_operation();
- break;
- case Operation::Inverse:
- if (argument == 0.0) {
- m_has_error = true;
- return argument;
- }
- res = 1 / argument;
- clear_operation();
- break;
- case Operation::Percent:
- res = argument * 0.01;
- break;
- case Operation::ToggleSign:
- res = -argument;
- break;
-
- case Operation::MemClear:
- m_mem = 0.0;
- res = argument;
- break;
- case Operation::MemRecall:
- res = m_mem;
- break;
- case Operation::MemSave:
- m_mem = argument;
- res = argument;
- break;
- case Operation::MemAdd:
- m_mem += argument;
- res = m_mem;
- break;
- }
-
- return res;
-}
-
-double Calculator::finish_operation(double argument)
-{
- double res = 0.0;
-
- switch (m_operation_in_progress) {
- case Operation::None:
- return argument;
-
- case Operation::Add:
- res = m_saved_argument + argument;
- break;
- case Operation::Subtract:
- res = m_saved_argument - argument;
- break;
- case Operation::Multiply:
- res = m_saved_argument * argument;
- break;
- case Operation::Divide:
- if (argument == 0.0) {
- m_has_error = true;
- return argument;
- }
- res = m_saved_argument / argument;
- break;
-
- case Operation::Sqrt:
- case Operation::Inverse:
- case Operation::Percent:
- case Operation::ToggleSign:
- case Operation::MemClear:
- case Operation::MemRecall:
- case Operation::MemSave:
- case Operation::MemAdd:
- ASSERT_NOT_REACHED();
- }
-
- clear_operation();
- return res;
-}
-
-void Calculator::clear_operation()
-{
- m_operation_in_progress = Operation::None;
- m_saved_argument = 0.0;
- clear_error();
-}
diff --git a/Applications/Calculator/Calculator.h b/Applications/Calculator/Calculator.h
deleted file mode 100644
index c53e31c397..0000000000
--- a/Applications/Calculator/Calculator.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-// This type implements the regular calculator
-// behavior, such as performing arithmetic
-// operations and providing a memory cell.
-// It does not deal with number input; you
-// have to pass in already parsed double
-// values.
-
-class Calculator final {
-public:
- Calculator();
- ~Calculator();
-
- enum class Operation {
- None,
- Add,
- Subtract,
- Multiply,
- Divide,
-
- Sqrt,
- Inverse,
- Percent,
- ToggleSign,
-
- MemClear,
- MemRecall,
- MemSave,
- MemAdd
- };
-
- double begin_operation(Operation, double);
- double finish_operation(double);
-
- bool has_error() const { return m_has_error; }
-
- void clear_operation();
- void clear_error() { m_has_error = false; }
-
-private:
- Operation m_operation_in_progress { Operation::None };
- double m_saved_argument { 0.0 };
- double m_mem { 0.0 };
- bool m_has_error { false };
-};
diff --git a/Applications/Calculator/CalculatorWidget.cpp b/Applications/Calculator/CalculatorWidget.cpp
deleted file mode 100644
index 083edae93b..0000000000
--- a/Applications/Calculator/CalculatorWidget.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * Copyright (c) 2021 Glenford Williams <gw_dev@outlook.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CalculatorWidget.h"
-#include "Applications/Calculator/CalculatorGML.h"
-#include <AK/Assertions.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/TextBox.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/Palette.h>
-
-CalculatorWidget::CalculatorWidget()
-{
- load_from_gml(calculator_gml);
-
- m_entry = *find_descendant_of_type_named<GUI::TextBox>("entry_textbox");
- m_entry->set_relative_rect(5, 5, 244, 26);
- m_entry->set_text_alignment(Gfx::TextAlignment::CenterRight);
- m_entry->set_font(Gfx::FontDatabase::default_fixed_width_font());
-
- m_label = *find_descendant_of_type_named<GUI::Label>("label");
-
- m_label->set_frame_shadow(Gfx::FrameShadow::Sunken);
- m_label->set_frame_shape(Gfx::FrameShape::Container);
- m_label->set_frame_thickness(2);
-
- for (int i = 0; i < 10; i++) {
- m_digit_button[i] = *find_descendant_of_type_named<GUI::Button>(String::formatted("{}_button", i));
- add_digit_button(*m_digit_button[i], i);
- }
-
- m_mem_add_button = *find_descendant_of_type_named<GUI::Button>("mem_add_button");
- add_operation_button(*m_mem_add_button, Calculator::Operation::MemAdd);
-
- m_mem_save_button = *find_descendant_of_type_named<GUI::Button>("mem_save_button");
- add_operation_button(*m_mem_save_button, Calculator::Operation::MemSave);
-
- m_mem_recall_button = *find_descendant_of_type_named<GUI::Button>("mem_recall_button");
- add_operation_button(*m_mem_recall_button, Calculator::Operation::MemRecall);
-
- m_mem_clear_button = *find_descendant_of_type_named<GUI::Button>("mem_clear_button");
- add_operation_button(*m_mem_clear_button, Calculator::Operation::MemClear);
-
- m_clear_button = *find_descendant_of_type_named<GUI::Button>("clear_button");
- m_clear_button->on_click = [this](auto) {
- m_keypad.set_value(0.0);
- m_calculator.clear_operation();
- update_display();
- };
-
- m_clear_error_button = *find_descendant_of_type_named<GUI::Button>("clear_error_button");
- m_clear_error_button->on_click = [this](auto) {
- m_keypad.set_value(0.0);
- update_display();
- };
-
- m_backspace_button = *find_descendant_of_type_named<GUI::Button>("backspace_button");
- m_backspace_button->on_click = [this](auto) {
- m_keypad.type_backspace();
- update_display();
- };
-
- m_decimal_point_button = *find_descendant_of_type_named<GUI::Button>("decimal_button");
- m_decimal_point_button->on_click = [this](auto) {
- m_keypad.type_decimal_point();
- update_display();
- };
-
- m_sign_button = *find_descendant_of_type_named<GUI::Button>("sign_button");
- add_operation_button(*m_sign_button, Calculator::Operation::ToggleSign);
-
- m_add_button = *find_descendant_of_type_named<GUI::Button>("add_button");
- add_operation_button(*m_add_button, Calculator::Operation::Add);
-
- m_subtract_button = *find_descendant_of_type_named<GUI::Button>("subtract_button");
- add_operation_button(*m_subtract_button, Calculator::Operation::Subtract);
-
- m_multiply_button = *find_descendant_of_type_named<GUI::Button>("multiply_button");
- add_operation_button(*m_multiply_button, Calculator::Operation::Multiply);
-
- m_divide_button = *find_descendant_of_type_named<GUI::Button>("divide_button");
- add_operation_button(*m_divide_button, Calculator::Operation::Divide);
-
- m_sqrt_button = *find_descendant_of_type_named<GUI::Button>("sqrt_button");
- add_operation_button(*m_sqrt_button, Calculator::Operation::Sqrt);
-
- m_inverse_button = *find_descendant_of_type_named<GUI::Button>("inverse_button");
- add_operation_button(*m_inverse_button, Calculator::Operation::Inverse);
-
- m_percent_button = *find_descendant_of_type_named<GUI::Button>("mod_button");
- add_operation_button(*m_percent_button, Calculator::Operation::Percent);
-
- m_equals_button = *find_descendant_of_type_named<GUI::Button>("equal_button");
- m_equals_button->on_click = [this](auto) {
- double argument = m_keypad.value();
- double res = m_calculator.finish_operation(argument);
- m_keypad.set_value(res);
- update_display();
- };
-}
-
-CalculatorWidget::~CalculatorWidget()
-{
-}
-
-void CalculatorWidget::add_operation_button(GUI::Button& button, Calculator::Operation operation)
-{
- button.on_click = [this, operation](auto) {
- double argument = m_keypad.value();
- double res = m_calculator.begin_operation(operation, argument);
- m_keypad.set_value(res);
- update_display();
- };
-}
-
-void CalculatorWidget::add_digit_button(GUI::Button& button, int digit)
-{
- button.on_click = [this, digit](auto) {
- m_keypad.type_digit(digit);
- update_display();
- };
-}
-
-void CalculatorWidget::update_display()
-{
- m_entry->set_text(m_keypad.to_string());
- if (m_calculator.has_error())
- m_label->set_text("E");
- else
- m_label->set_text("");
-}
-
-void CalculatorWidget::keydown_event(GUI::KeyEvent& event)
-{
- //Clear button selection when we are typing
- m_equals_button->set_focus(true);
- m_equals_button->set_focus(false);
-
- if (event.key() == KeyCode::Key_Return) {
- m_keypad.set_value(m_calculator.finish_operation(m_keypad.value()));
-
- } else if (event.key() >= KeyCode::Key_0 && event.key() <= KeyCode::Key_9) {
- m_keypad.type_digit(atoi(event.text().characters()));
-
- } else if (event.key() == KeyCode::Key_Period) {
- m_keypad.type_decimal_point();
-
- } else if (event.key() == KeyCode::Key_Escape) {
- m_keypad.set_value(0.0);
- m_calculator.clear_operation();
-
- } else if (event.key() == KeyCode::Key_Backspace) {
- m_keypad.type_backspace();
-
- } else {
- Calculator::Operation operation;
-
- switch (event.key()) {
- case KeyCode::Key_Plus:
- operation = Calculator::Operation::Add;
- break;
- case KeyCode::Key_Minus:
- operation = Calculator::Operation::Subtract;
- break;
- case KeyCode::Key_Asterisk:
- operation = Calculator::Operation::Multiply;
- break;
- case KeyCode::Key_Slash:
- operation = Calculator::Operation::Divide;
- break;
- case KeyCode::Key_Percent:
- operation = Calculator::Operation::Percent;
- break;
- default:
- return;
- }
-
- m_keypad.set_value(m_calculator.begin_operation(operation, m_keypad.value()));
- }
-
- update_display();
-}
diff --git a/Applications/Calculator/CalculatorWidget.h b/Applications/Calculator/CalculatorWidget.h
deleted file mode 100644
index 31d9548b3c..0000000000
--- a/Applications/Calculator/CalculatorWidget.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * Copyright (c) 2021 Glenford Williams <gw_dev@outlook.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Calculator.h"
-#include "Keypad.h"
-#include <AK/Vector.h>
-#include <LibGUI/Widget.h>
-
-class CalculatorWidget final : public GUI::Widget {
- C_OBJECT(CalculatorWidget)
-public:
- virtual ~CalculatorWidget() override;
-
-private:
- CalculatorWidget();
- void add_operation_button(GUI::Button&, Calculator::Operation);
- void add_digit_button(GUI::Button&, int digit);
-
- void update_display();
-
- virtual void keydown_event(GUI::KeyEvent&) override;
-
- Calculator m_calculator;
- Keypad m_keypad;
-
- RefPtr<GUI::TextBox> m_entry;
- RefPtr<GUI::Label> m_label;
-
- RefPtr<GUI::Button> m_digit_button[10];
- RefPtr<GUI::Button> m_mem_add_button;
- RefPtr<GUI::Button> m_mem_save_button;
- RefPtr<GUI::Button> m_mem_recall_button;
- RefPtr<GUI::Button> m_mem_clear_button;
- RefPtr<GUI::Button> m_clear_button;
- RefPtr<GUI::Button> m_clear_error_button;
- RefPtr<GUI::Button> m_backspace_button;
- RefPtr<GUI::Button> m_decimal_point_button;
- RefPtr<GUI::Button> m_sign_button;
- RefPtr<GUI::Button> m_add_button;
- RefPtr<GUI::Button> m_subtract_button;
- RefPtr<GUI::Button> m_multiply_button;
- RefPtr<GUI::Button> m_divide_button;
- RefPtr<GUI::Button> m_sqrt_button;
- RefPtr<GUI::Button> m_inverse_button;
- RefPtr<GUI::Button> m_percent_button;
- RefPtr<GUI::Button> m_equals_button;
-};
diff --git a/Applications/Calculator/CalculatorWindow.gml b/Applications/Calculator/CalculatorWindow.gml
deleted file mode 100644
index 4763a4d8c2..0000000000
--- a/Applications/Calculator/CalculatorWindow.gml
+++ /dev/null
@@ -1,272 +0,0 @@
-@GUI::Widget {
- fixed_width: 254
- fixed_height: 213
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [10, 0, 10, 0]
- }
-
- @GUI::TextBox {
- name: "entry_textbox"
- }
-
- @GUI::Widget {
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- name: "label"
- fixed_width: 35
- fixed_height: 27
- }
-
- @GUI::Widget {
- fixed_width: 5
- }
-
- @GUI::Button {
- name: "backspace_button"
- text: "Backspace"
- fixed_width: 65
- fixed_height: 28
- foreground_color: "brown"
- }
-
- @GUI::Button {
- name: "clear_error_button"
- text: "CE"
- fixed_width: 55
- fixed_height: 28
- foreground_color: "brown"
- }
-
- @GUI::Button {
- name: "clear_button"
- text: "C"
- fixed_width: 60
- fixed_height: 28
- foreground_color: "brown"
- }
- }
-
- @GUI::Widget {
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Button {
- name: "mem_clear_button"
- text: "MC"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "red"
- }
-
- @GUI::Widget {
- fixed_width: 5
- }
-
- @GUI::Button {
- name: "7_button"
- text: "7"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "8_button"
- text: "8"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "9_button"
- text: "9"
- fixed_width: 35
- fixed_height: 28
- }
-
- @GUI::Button {
- name: "divide_button"
- text: "/"
- fixed_width: 35
- fixed_height: 28
- }
-
- @GUI::Button {
- name: "sqrt_button"
- text: "sqrt"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
- }
-
- @GUI::Widget {
- layout: @GUI::HorizontalBoxLayout {}
-
- @GUI::Button {
- name: "mem_recall_button"
- text: "MR"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "red"
- }
-
- @GUI::Widget {
- fixed_width: 5
- }
-
- @GUI::Button {
- name: "4_button"
- text: "4"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "5_button"
- text: "5"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "6_button"
- text: "6"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "multiply_button"
- text: "*"
- fixed_width: 35
- fixed_height: 28
- }
-
- @GUI::Button {
- name: "mod_button"
- text: "%"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
- }
-
- @GUI::Widget {
- layout: @GUI::HorizontalBoxLayout {}
-
- @GUI::Button {
- name: "mem_save_button"
- text: "MS"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "red"
- }
-
- @GUI::Widget {
- fixed_width: 5
- }
-
- @GUI::Button {
- name: "1_button"
- text: "1"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "2_button"
- text: "2"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "3_button"
- text: "3"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "subtract_button"
- text: "-"
- fixed_width: 35
- fixed_height: 28
- }
-
- @GUI::Button {
- name: "inverse_button"
- text: "1/x"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
- }
-
- @GUI::Widget {
- layout: @GUI::HorizontalBoxLayout {}
-
- @GUI::Button {
- name: "mem_add_button"
- text: "M+"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "red"
- }
-
- @GUI::Widget {
- fixed_width: 5
- }
-
- @GUI::Button {
- name: "0_button"
- text: "0"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "sign_button"
- text: "+/-"
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "decimal_button"
- text: "."
- fixed_width: 35
- fixed_height: 28
- foreground_color: "blue"
- }
-
- @GUI::Button {
- name: "add_button"
- text: "+"
- fixed_width: 35
- fixed_height: 28
- }
-
- @GUI::Button {
- name: "equal_button"
- text: "="
- fixed_width: 35
- fixed_height: 28
- foreground_color: "red"
- }
- }
-}
diff --git a/Applications/Calculator/Keypad.cpp b/Applications/Calculator/Keypad.cpp
deleted file mode 100644
index 9b2d672af5..0000000000
--- a/Applications/Calculator/Keypad.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Keypad.h"
-#include <AK/StringBuilder.h>
-#include <math.h>
-
-Keypad::Keypad()
-{
-}
-
-Keypad::~Keypad()
-{
-}
-
-void Keypad::type_digit(int digit)
-{
- switch (m_state) {
- case State::External:
- m_state = State::TypingInteger;
- m_negative = false;
- m_int_value = digit;
- m_frac_value = 0;
- m_frac_length = 0;
- break;
- case State::TypingInteger:
- ASSERT(m_frac_value == 0);
- ASSERT(m_frac_length == 0);
- m_int_value *= 10;
- m_int_value += digit;
- break;
- case State::TypingDecimal:
- if (m_frac_length > 6)
- break;
- m_frac_value *= 10;
- m_frac_value += digit;
- m_frac_length++;
- break;
- }
-}
-
-void Keypad::type_decimal_point()
-{
- switch (m_state) {
- case State::External:
- m_negative = false;
- m_int_value = 0;
- m_frac_value = 0;
- m_frac_length = 0;
- break;
- case State::TypingInteger:
- ASSERT(m_frac_value == 0);
- ASSERT(m_frac_length == 0);
- m_state = State::TypingDecimal;
- break;
- case State::TypingDecimal:
- // Ignore it.
- break;
- }
-}
-
-void Keypad::type_backspace()
-{
- switch (m_state) {
- case State::External:
- m_negative = false;
- m_int_value = 0;
- m_frac_value = 0;
- m_frac_length = 0;
- break;
- case State::TypingDecimal:
- if (m_frac_length > 0) {
- m_frac_value /= 10;
- m_frac_length--;
- break;
- }
- ASSERT(m_frac_value == 0);
- m_state = State::TypingInteger;
- [[fallthrough]];
- case State::TypingInteger:
- ASSERT(m_frac_value == 0);
- ASSERT(m_frac_length == 0);
- m_int_value /= 10;
- if (m_int_value == 0)
- m_negative = false;
- break;
- }
-}
-
-double Keypad::value() const
-{
- double res = 0.0;
-
- long frac = m_frac_value;
- for (int i = 0; i < m_frac_length; i++) {
- int digit = frac % 10;
- res += digit;
- res /= 10.0;
- frac /= 10;
- }
-
- res += m_int_value;
- if (m_negative)
- res = -res;
-
- return res;
-}
-
-void Keypad::set_value(double value)
-{
- m_state = State::External;
-
- if (value < 0.0) {
- m_negative = true;
- value = -value;
- } else
- m_negative = false;
-
- m_int_value = value;
- value -= m_int_value;
-
- m_frac_value = 0;
- m_frac_length = 0;
- while (value != 0) {
- value *= 10.0;
- int digit = value;
- m_frac_value *= 10;
- m_frac_value += digit;
- m_frac_length++;
- value -= digit;
-
- if (m_frac_length > 6)
- break;
- }
-}
-
-String Keypad::to_string() const
-{
- StringBuilder builder;
- if (m_negative)
- builder.append("-");
- builder.appendff("{}", m_int_value);
-
- if (m_frac_length > 0)
- builder.appendff(".{:0{}}", m_frac_value, m_frac_length);
-
- return builder.to_string();
-}
diff --git a/Applications/Calculator/Keypad.h b/Applications/Calculator/Keypad.h
deleted file mode 100644
index dae427a046..0000000000
--- a/Applications/Calculator/Keypad.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-
-// This type implements number typing and
-// displaying mechanics. It does not perform
-// any arithmetic operations or anything on
-// the values it deals with.
-
-class Keypad final {
-public:
- Keypad();
- ~Keypad();
-
- void type_digit(int digit);
- void type_decimal_point();
- void type_backspace();
-
- double value() const;
- void set_value(double);
-
- String to_string() const;
-
-private:
- // Internal representation of the current decimal value.
- bool m_negative { false };
- long m_int_value { 0 };
- long m_frac_value { 0 };
- int m_frac_length { 0 };
- // E.g. for -35.004200,
- // m_negative = true
- // m_int_value = 35
- // m_frac_value = 4200
- // m_frac_length = 6
-
- enum class State {
- External,
- TypingInteger,
- TypingDecimal
- };
-
- State m_state { State::External };
-};
diff --git a/Applications/Calculator/main.cpp b/Applications/Calculator/main.cpp
deleted file mode 100644
index 7ff18b94bf..0000000000
--- a/Applications/Calculator/main.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CalculatorWidget.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer rpath accept unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer rpath accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- auto app_icon = GUI::Icon::default_icon("app-calculator");
-
- auto window = GUI::Window::construct();
- window->set_title("Calculator");
- window->set_resizable(false);
- window->resize(254, 213);
-
- window->set_main_widget<CalculatorWidget>();
-
- window->show();
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Calculator");
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Calculator", app_icon));
-
- app->set_menubar(move(menubar));
-
- return app->exec();
-}
diff --git a/Applications/Calendar/AddEventDialog.cpp b/Applications/Calendar/AddEventDialog.cpp
deleted file mode 100644
index dbb70d33c1..0000000000
--- a/Applications/Calendar/AddEventDialog.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Ryan Grieb <ryan.m.grieb@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "AddEventDialog.h"
-#include <LibCore/DateTime.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/ComboBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Layout.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-
-static const char* short_month_names[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-
-AddEventDialog::AddEventDialog(Core::DateTime date_time, Window* parent_window)
- : Dialog(parent_window)
- , m_date_time(date_time)
-{
- resize(158, 100);
- set_title("Add Event");
- set_resizable(false);
- set_icon(parent_window->icon());
-
- auto& widget = set_main_widget<GUI::Widget>();
- widget.set_fill_with_background_color(true);
- widget.set_layout<GUI::VerticalBoxLayout>();
-
- auto& top_container = widget.add<GUI::Widget>();
- top_container.set_layout<GUI::VerticalBoxLayout>();
- top_container.set_fixed_height(45);
- top_container.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& add_label = top_container.add<GUI::Label>("Add title & date:");
- add_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- add_label.set_fixed_height(14);
- add_label.set_font(Gfx::FontDatabase::default_bold_font());
-
- auto& event_title_textbox = top_container.add<GUI::TextBox>();
- event_title_textbox.set_fixed_height(20);
-
- auto& middle_container = widget.add<GUI::Widget>();
- middle_container.set_layout<GUI::HorizontalBoxLayout>();
- middle_container.set_fixed_height(25);
- middle_container.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& starting_month_combo = middle_container.add<GUI::ComboBox>();
- starting_month_combo.set_only_allow_values_from_model(true);
- starting_month_combo.set_fixed_size(50, 20);
- starting_month_combo.set_model(MonthListModel::create());
- starting_month_combo.set_selected_index(m_date_time.month() - 1);
-
- auto& starting_day_combo = middle_container.add<GUI::SpinBox>();
- starting_day_combo.set_fixed_size(40, 20);
- starting_day_combo.set_value(m_date_time.day());
- starting_day_combo.set_min(1);
-
- auto& starting_year_combo = middle_container.add<GUI::SpinBox>();
- starting_year_combo.set_fixed_size(55, 20);
- starting_year_combo.set_range(0, 9999);
- starting_year_combo.set_value(m_date_time.year());
-
- widget.layout()->add_spacer();
-
- auto& button_container = widget.add<GUI::Widget>();
- button_container.set_fixed_height(20);
- button_container.set_layout<GUI::HorizontalBoxLayout>();
- button_container.layout()->add_spacer();
- auto& ok_button = button_container.add<GUI::Button>("OK");
- ok_button.set_fixed_size(80, 20);
- ok_button.on_click = [this](auto) {
- dbgln("TODO: Add event icon on specific tile");
- done(Dialog::ExecOK);
- };
-
- event_title_textbox.set_focus(true);
-}
-
-AddEventDialog::~AddEventDialog()
-{
-}
-
-AddEventDialog::MonthListModel::MonthListModel()
-{
-}
-
-AddEventDialog::MonthListModel::~MonthListModel()
-{
-}
-
-void AddEventDialog::MonthListModel::update()
-{
-}
-
-int AddEventDialog::MonthListModel::row_count(const GUI::ModelIndex&) const
-{
- return 12;
-}
-
-String AddEventDialog::MonthListModel::column_name(int column) const
-{
- switch (column) {
- case Column::Month:
- return "Month";
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-GUI::Variant AddEventDialog::MonthListModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- auto& month = short_month_names[index.row()];
- if (role == GUI::ModelRole::Display) {
- switch (index.column()) {
- case Column::Month:
- return month;
- default:
- ASSERT_NOT_REACHED();
- }
- }
- return {};
-}
diff --git a/Applications/Calendar/AddEventDialog.h b/Applications/Calendar/AddEventDialog.h
deleted file mode 100644
index c84e494527..0000000000
--- a/Applications/Calendar/AddEventDialog.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Ryan Grieb <ryan.m.grieb@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Calendar.h>
-#include <LibGUI/Dialog.h>
-#include <LibGUI/Model.h>
-#include <LibGUI/Window.h>
-
-class AddEventDialog final : public GUI::Dialog {
- C_OBJECT(AddEventDialog)
-public:
- virtual ~AddEventDialog() override;
-
- static void show(Core::DateTime date_time, Window* parent_window = nullptr)
- {
- auto dialog = AddEventDialog::construct(date_time, parent_window);
- dialog->exec();
- }
-
-private:
- AddEventDialog(Core::DateTime date_time, Window* parent_window = nullptr);
-
- class MonthListModel final : public GUI::Model {
- public:
- enum Column {
- Month,
- __Count,
- };
-
- static NonnullRefPtr<MonthListModel> create() { return adopt(*new MonthListModel); }
- virtual ~MonthListModel() override;
-
- virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
- virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return Column::__Count; }
- virtual String column_name(int) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual void update() override;
-
- private:
- MonthListModel();
- };
-
- Core::DateTime m_date_time;
-};
diff --git a/Applications/Calendar/CMakeLists.txt b/Applications/Calendar/CMakeLists.txt
deleted file mode 100644
index c23a6743cc..0000000000
--- a/Applications/Calendar/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- AddEventDialog.cpp
- main.cpp
-)
-
-serenity_app(Calendar ICON app-calendar)
-target_link_libraries(Calendar LibGUI)
diff --git a/Applications/Calendar/main.cpp b/Applications/Calendar/main.cpp
deleted file mode 100644
index aebc5c4fed..0000000000
--- a/Applications/Calendar/main.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Ryan Grieb <ryan.m.grieb@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "AddEventDialog.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Calendar.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
-
- if (pledge("stdio shared_buffer rpath accept unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer rpath accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- auto app_icon = GUI::Icon::default_icon("app-calendar");
- auto window = GUI::Window::construct();
- window->set_title("Calendar");
- window->resize(600, 480);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto& root_container = window->set_main_widget<GUI::Widget>();
- root_container.set_fill_with_background_color(true);
- root_container.set_layout<GUI::VerticalBoxLayout>();
-
- auto& toolbar_container = root_container.add<GUI::ToolBarContainer>();
- auto& toolbar = toolbar_container.add<GUI::ToolBar>();
-
- auto& calendar_container = root_container.add<GUI::Frame>();
- calendar_container.set_layout<GUI::VerticalBoxLayout>();
- calendar_container.layout()->set_margins({ 2, 2, 2, 2 });
- auto& calendar_widget = calendar_container.add<GUI::Calendar>(Core::DateTime::now());
-
- RefPtr<GUI::Button> selected_calendar_button;
-
- auto prev_date_action = GUI::Action::create("Previous date", { Mod_Alt, Key_Left }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-back.png"), [&](const GUI::Action&) {
- unsigned int target_month = calendar_widget.selected_month();
- unsigned int target_year = calendar_widget.selected_year();
-
- if (calendar_widget.mode() == GUI::Calendar::Month) {
- target_month--;
- if (calendar_widget.selected_month() <= 1) {
- target_month = 12;
- target_year--;
- }
- } else {
- target_year--;
- }
-
- calendar_widget.update_tiles(target_year, target_month);
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- });
-
- auto next_date_action = GUI::Action::create("Next date", { Mod_Alt, Key_Right }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"), [&](const GUI::Action&) {
- unsigned int target_month = calendar_widget.selected_month();
- unsigned int target_year = calendar_widget.selected_year();
-
- if (calendar_widget.mode() == GUI::Calendar::Month) {
- target_month++;
- if (calendar_widget.selected_month() >= 12) {
- target_month = 1;
- target_year++;
- }
- } else {
- target_year++;
- }
-
- calendar_widget.update_tiles(target_year, target_month);
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- });
-
- auto add_event_action = GUI::Action::create("Add event", {}, Gfx::Bitmap::load_from_file("/res/icons/16x16/add-event.png"), [&](const GUI::Action&) {
- AddEventDialog::show(calendar_widget.selected_date(), window);
- });
-
- auto jump_to_action = GUI::Action::create("Jump to today", {}, Gfx::Bitmap::load_from_file("/res/icons/16x16/calendar-date.png"), [&](const GUI::Action&) {
- if (calendar_widget.mode() == GUI::Calendar::Year)
- calendar_widget.toggle_mode();
- calendar_widget.set_selected_date(Core::DateTime::now());
- calendar_widget.update_tiles(Core::DateTime::now().year(), Core::DateTime::now().month());
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- });
-
- toolbar.add_action(prev_date_action);
- selected_calendar_button = toolbar.add<GUI::Button>(calendar_widget.selected_calendar_text());
- selected_calendar_button->set_fixed_width(70);
- selected_calendar_button->set_button_style(Gfx::ButtonStyle::CoolBar);
- selected_calendar_button->set_font(Gfx::FontDatabase::default_bold_fixed_width_font());
- selected_calendar_button->on_click = [&](auto) {
- calendar_widget.toggle_mode();
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- };
- toolbar.add_action(next_date_action);
- toolbar.add_separator();
- toolbar.add_action(jump_to_action);
- toolbar.add_action(add_event_action);
-
- calendar_widget.on_calendar_tile_click = [&] {
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- };
-
- calendar_widget.on_calendar_tile_doubleclick = [&] {
- AddEventDialog::show(calendar_widget.selected_date(), window);
- };
-
- calendar_widget.on_month_tile_click = [&] {
- selected_calendar_button->set_text(calendar_widget.selected_calendar_text());
- };
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Calendar");
- app_menu.add_action(GUI::Action::create("Add Event", { Mod_Ctrl | Mod_Shift, Key_E }, Gfx::Bitmap::load_from_file("/res/icons/16x16/add-event.png"),
- [&](const GUI::Action&) {
- AddEventDialog::show(calendar_widget.selected_date(), window);
- return;
- }));
-
- app_menu.add_separator();
-
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Calendar", app_icon));
-
- app->set_menubar(move(menubar));
- window->show();
- app->exec();
-}
diff --git a/Applications/CrashReporter/CMakeLists.txt b/Applications/CrashReporter/CMakeLists.txt
deleted file mode 100644
index d391aa6b84..0000000000
--- a/Applications/CrashReporter/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-compile_gml(CrashReporterWindow.gml CrashReporterWindowGML.h crash_reporter_window_gml)
-
-
-set(SOURCES
- main.cpp
- CrashReporterWindowGML.h
-)
-
-serenity_app(CrashReporter ICON app-crash-reporter)
-target_link_libraries(CrashReporter LibCore LibCoreDump LibDesktop LibGUI)
diff --git a/Applications/CrashReporter/CrashReporterWindow.gml b/Applications/CrashReporter/CrashReporterWindow.gml
deleted file mode 100644
index acca32bd13..0000000000
--- a/Applications/CrashReporter/CrashReporterWindow.gml
+++ /dev/null
@@ -1,95 +0,0 @@
-@GUI::Widget {
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [5, 5, 5, 5]
- }
-
- @GUI::Widget {
- fixed_height: 44
-
- layout: @GUI::HorizontalBoxLayout {
- spacing: 10
- }
-
- @GUI::ImageWidget {
- name: "icon"
- }
-
- @GUI::Label {
- name: "description"
- text_alignment: "CenterLeft"
- }
- }
-
- @GUI::Widget {
- fixed_height: 18
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Executable path:"
- text_alignment: "CenterLeft"
- fixed_width: 90
- }
-
- @GUI::LinkLabel {
- name: "executable_link"
- text_alignment: "CenterLeft"
- }
- }
-
- @GUI::Widget {
- fixed_height: 18
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Coredump path:"
- text_alignment: "CenterLeft"
- fixed_width: 90
- }
-
- @GUI::LinkLabel {
- name: "coredump_link"
- text_alignment: "CenterLeft"
- }
- }
-
- @GUI::Widget {
- fixed_height: 18
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Backtrace:"
- text_alignment: "CenterLeft"
- }
- }
-
- @GUI::TextEditor {
- name: "backtrace_text_editor"
- mode: "ReadOnly"
- }
-
- @GUI::Widget {
- fixed_height: 32
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- // HACK: We need something like Layout::add_spacer() in GML! :^)
- @GUI::Widget {
- }
-
- @GUI::Button {
- name: "close_button"
- text: "Close"
- fixed_width: 70
- fixed_height: 22
- }
- }
-}
diff --git a/Applications/CrashReporter/main.cpp b/Applications/CrashReporter/main.cpp
deleted file mode 100644
index 047a696ea3..0000000000
--- a/Applications/CrashReporter/main.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <AK/LexicalPath.h>
-#include <AK/StringBuilder.h>
-#include <AK/Types.h>
-#include <AK/URL.h>
-#include <Applications/CrashReporter/CrashReporterWindowGML.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCoreDump/Backtrace.h>
-#include <LibCoreDump/Reader.h>
-#include <LibDesktop/AppFile.h>
-#include <LibDesktop/Launcher.h>
-#include <LibELF/CoreDump.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/FileIconProvider.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/ImageWidget.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Layout.h>
-#include <LibGUI/LinkLabel.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Window.h>
-#include <string.h>
-
-static String build_backtrace(const CoreDump::Reader& coredump)
-{
- StringBuilder builder;
-
- auto assertion = coredump.metadata().get("assertion");
- if (assertion.has_value() && !assertion.value().is_empty()) {
- builder.append("ASSERTION FAILED: ");
- builder.append(assertion.value().characters());
- builder.append('\n');
- builder.append('\n');
- }
-
- auto first = true;
- for (auto& entry : coredump.backtrace().entries()) {
- if (first)
- first = false;
- else
- builder.append('\n');
- builder.append(entry.to_string());
- }
-
- return builder.build();
-}
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept cpath rpath unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* coredump_path = nullptr;
-
- Core::ArgsParser args_parser;
- args_parser.set_general_help("Show information from an application crash coredump.");
- args_parser.add_positional_argument(coredump_path, "Coredump path", "coredump-path");
- args_parser.parse(argc, argv);
-
- String backtrace;
- String executable_path;
- int pid { 0 };
- u8 termination_signal { 0 };
-
- {
- auto coredump = CoreDump::Reader::create(coredump_path);
- if (!coredump) {
- warnln("Could not open coredump '{}'", coredump_path);
- return 1;
- }
- auto& process_info = coredump->process_info();
- backtrace = build_backtrace(*coredump);
- executable_path = String(process_info.executable_path);
- pid = process_info.pid;
- termination_signal = process_info.termination_signal;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept rpath unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil(executable_path.characters(), "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/launch", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-crash-reporter");
-
- auto window = GUI::Window::construct();
- window->set_title("Crash Reporter");
- window->set_icon(app_icon.bitmap_for_size(16));
- window->resize(460, 340);
- window->center_on_screen();
-
- auto& widget = window->set_main_widget<GUI::Widget>();
- widget.load_from_gml(crash_reporter_window_gml);
-
- auto& icon_image_widget = *widget.find_descendant_of_type_named<GUI::ImageWidget>("icon");
- icon_image_widget.set_bitmap(GUI::FileIconProvider::icon_for_executable(executable_path).bitmap_for_size(32));
-
- auto app_name = LexicalPath(executable_path).basename();
- auto af = Desktop::AppFile::get_for_app(app_name);
- if (af->is_valid())
- app_name = af->name();
-
- auto& description_label = *widget.find_descendant_of_type_named<GUI::Label>("description");
- description_label.set_text(String::formatted("\"{}\" (PID {}) has crashed - {} (signal {})", app_name, pid, strsignal(termination_signal), termination_signal));
-
- auto& executable_link_label = *widget.find_descendant_of_type_named<GUI::LinkLabel>("executable_link");
- executable_link_label.set_text(LexicalPath::canonicalized_path(executable_path));
- executable_link_label.on_click = [&] {
- Desktop::Launcher::open(URL::create_with_file_protocol(LexicalPath(executable_path).dirname()));
- };
-
- auto& coredump_link_label = *widget.find_descendant_of_type_named<GUI::LinkLabel>("coredump_link");
- coredump_link_label.set_text(LexicalPath::canonicalized_path(coredump_path));
- coredump_link_label.on_click = [&] {
- Desktop::Launcher::open(URL::create_with_file_protocol(LexicalPath(coredump_path).dirname()));
- };
-
- auto& backtrace_text_editor = *widget.find_descendant_of_type_named<GUI::TextEditor>("backtrace_text_editor");
- backtrace_text_editor.set_text(backtrace);
- backtrace_text_editor.set_should_hide_unnecessary_scrollbars(true);
-
- auto& close_button = *widget.find_descendant_of_type_named<GUI::Button>("close_button");
- close_button.on_click = [&](auto) {
- app->quit();
- };
-
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/Debugger/CMakeLists.txt b/Applications/Debugger/CMakeLists.txt
deleted file mode 100644
index 7e6f200ea4..0000000000
--- a/Applications/Debugger/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(SOURCES
- main.cpp
-)
-
-serenity_bin(Debugger)
-target_link_libraries(Debugger LibCore LibDebug LibX86 LibLine)
diff --git a/Applications/Debugger/main.cpp b/Applications/Debugger/main.cpp
deleted file mode 100644
index ef5bbe9671..0000000000
--- a/Applications/Debugger/main.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <AK/Assertions.h>
-#include <AK/ByteBuffer.h>
-#include <AK/Demangle.h>
-#include <AK/LogStream.h>
-#include <AK/StringBuilder.h>
-#include <AK/kmalloc.h>
-#include <LibC/sys/arch/i386/regs.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/File.h>
-#include <LibDebug/DebugInfo.h>
-#include <LibDebug/DebugSession.h>
-#include <LibLine/Editor.h>
-#include <LibX86/Disassembler.h>
-#include <LibX86/Instruction.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-RefPtr<Line::Editor> editor;
-
-OwnPtr<Debug::DebugSession> g_debug_session;
-
-static void handle_sigint(int)
-{
- outln("Debugger: SIGINT");
-
- // The destructor of DebugSession takes care of detaching
- g_debug_session = nullptr;
-}
-
-static void handle_print_registers(const PtraceRegisters& regs)
-{
- outln("eax={:08x} ebx={:08x} ecx={:08x} edx={:08x}", regs.eax, regs.ebx, regs.ecx, regs.edx);
- outln("esp={:08x} ebp={:08x} esi={:08x} edi={:08x}", regs.esp, regs.ebp, regs.esi, regs.edi);
- outln("eip={:08x} eflags={:08x}", regs.eip, regs.eflags);
-}
-
-static bool handle_disassemble_command(const String& command, void* first_instruction)
-{
- auto parts = command.split(' ');
- size_t number_of_instructions_to_disassemble = 5;
- if (parts.size() == 2) {
- auto number = parts[1].to_uint();
- if (!number.has_value())
- return false;
- number_of_instructions_to_disassemble = number.value();
- }
-
- // FIXME: Instead of using a fixed "dump_size",
- // we can feed instructions to the disassembler one by one
- constexpr size_t dump_size = 0x100;
- ByteBuffer code;
- for (size_t i = 0; i < dump_size / sizeof(u32); ++i) {
- auto value = g_debug_session->peek(reinterpret_cast<u32*>(first_instruction) + i);
- if (!value.has_value())
- break;
- code.append(&value, sizeof(u32));
- }
-
- X86::SimpleInstructionStream stream(code.data(), code.size());
- X86::Disassembler disassembler(stream);
-
- for (size_t i = 0; i < number_of_instructions_to_disassemble; ++i) {
- auto offset = stream.offset();
- auto insn = disassembler.next();
- if (!insn.has_value())
- break;
-
- outln(" {:p} <+{}>:\t{}", offset + reinterpret_cast<size_t>(first_instruction), offset, insn.value().to_string(offset));
- }
-
- return true;
-}
-
-static bool insert_breakpoint_at_address(FlatPtr address)
-{
- return g_debug_session->insert_breakpoint((void*)address);
-}
-
-static bool insert_breakpoint_at_source_position(const String& file, size_t line)
-{
- auto result = g_debug_session->insert_breakpoint(file, line);
- if (!result.has_value()) {
- warnln("Could not insert breakpoint at {}:{}", file, line);
- return false;
- }
- outln("Breakpoint inserted [{}:{} ({}:{:p})]", result.value().file_name, result.value().line_number, result.value().library_name, result.value().address);
- return true;
-}
-
-static bool insert_breakpoint_at_symbol(const String& symbol)
-{
- auto result = g_debug_session->insert_breakpoint(symbol);
- if (!result.has_value()) {
- warnln("Could not insert breakpoint at symbol: {}", symbol);
- return false;
- }
- outln("Breakpoint inserted [{}:{:p}]", result.value().library_name, result.value().address);
- return true;
-}
-
-static bool handle_breakpoint_command(const String& command)
-{
- auto parts = command.split(' ');
- if (parts.size() != 2)
- return false;
-
- auto argument = parts[1];
- if (argument.is_empty())
- return false;
-
- if (argument.contains(":")) {
- auto source_arguments = argument.split(':');
- if (source_arguments.size() != 2)
- return false;
- auto line = source_arguments[1].to_uint();
- if (!line.has_value())
- return false;
- auto file = source_arguments[0];
- return insert_breakpoint_at_source_position(file, line.value());
- }
- if ((argument.starts_with("0x"))) {
- return insert_breakpoint_at_address(strtoul(argument.characters() + 2, nullptr, 16));
- }
-
- return insert_breakpoint_at_symbol(argument);
-}
-
-static bool handle_examine_command(const String& command)
-{
- auto parts = command.split(' ');
- if (parts.size() != 2)
- return false;
-
- auto argument = parts[1];
- if (argument.is_empty())
- return false;
-
- if (!(argument.starts_with("0x"))) {
- return false;
- }
- u32 address = strtoul(argument.characters() + 2, nullptr, 16);
- auto res = g_debug_session->peek((u32*)address);
- if (!res.has_value()) {
- printf("could not examine memory at address 0x%x\n", address);
- return true;
- }
- printf("0x%x\n", res.value());
- return true;
-}
-
-static void print_help()
-{
- out("Options:\n"
- "cont - Continue execution\n"
- "si - step to the next instruction\n"
- "sl - step to the next source line\n"
- "line - show the position of the current instruction in the source code\n"
- "regs - Print registers\n"
- "dis [number of instructions] - Print disassembly\n"
- "bp <address/symbol/file:line> - Insert a breakpoint\n"
- "x <address> - examine dword in memory\n");
-}
-
-int main(int argc, char** argv)
-{
- editor = Line::Editor::construct();
-
- if (pledge("stdio proc ptrace exec rpath tty sigaction cpath unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* command = nullptr;
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(command,
- "The program to be debugged, along with its arguments",
- "program", Core::ArgsParser::Required::Yes);
- args_parser.parse(argc, argv);
-
- auto result = Debug::DebugSession::exec_and_attach(command);
- if (!result) {
- warnln("Failed to start debugging session for: \"{}\"", command);
- exit(1);
- }
- g_debug_session = result.release_nonnull();
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(struct sigaction));
- sa.sa_handler = handle_sigint;
- sigaction(SIGINT, &sa, nullptr);
-
- Debug::DebugInfo::SourcePosition previous_source_position;
- bool in_step_line = false;
-
- g_debug_session->run(Debug::DebugSession::DesiredInitialDebugeeState::Stopped, [&](Debug::DebugSession::DebugBreakReason reason, Optional<PtraceRegisters> optional_regs) {
- if (reason == Debug::DebugSession::DebugBreakReason::Exited) {
- outln("Program exited.");
- return Debug::DebugSession::DebugDecision::Detach;
- }
-
- ASSERT(optional_regs.has_value());
- const PtraceRegisters& regs = optional_regs.value();
-
- auto symbol_at_ip = g_debug_session->symbolicate(regs.eip);
-
- auto source_position = g_debug_session->get_source_position(regs.eip);
-
- if (in_step_line) {
- bool no_source_info = !source_position.has_value();
- if (no_source_info || source_position.value() != previous_source_position) {
- if (no_source_info)
- outln("No source information for current instruction! stoppoing.");
- in_step_line = false;
- } else {
- return Debug::DebugSession::DebugDecision::SingleStep;
- }
- }
-
- if (symbol_at_ip.has_value())
- outln("Program is stopped at: {:p} ({}:{})", regs.eip, symbol_at_ip.value().library_name, symbol_at_ip.value().symbol);
- else
- outln("Program is stopped at: {:p}", regs.eip);
-
- if (source_position.has_value()) {
- previous_source_position = source_position.value();
- outln("Source location: {}:{}", source_position.value().file_path, source_position.value().line_number);
- } else {
- outln("(No source location information for the current instruction)");
- }
-
- for (;;) {
- auto command_result = editor->get_line("(sdb) ");
-
- if (command_result.is_error())
- return Debug::DebugSession::DebugDecision::Detach;
-
- auto& command = command_result.value();
-
- bool success = false;
- Optional<Debug::DebugSession::DebugDecision> decision;
-
- if (command.is_empty() && !editor->history().is_empty()) {
- command = editor->history().last().entry;
- }
- if (command == "cont") {
- decision = Debug::DebugSession::DebugDecision::Continue;
- success = true;
- } else if (command == "si") {
- decision = Debug::DebugSession::DebugDecision::SingleStep;
- success = true;
- } else if (command == "sl") {
- if (source_position.has_value()) {
- decision = Debug::DebugSession::DebugDecision::SingleStep;
- in_step_line = true;
- success = true;
- } else {
- outln("No source location information for the current instruction");
- }
- } else if (command == "regs") {
- handle_print_registers(regs);
- success = true;
-
- } else if (command.starts_with("dis")) {
- success = handle_disassemble_command(command, reinterpret_cast<void*>(regs.eip));
-
- } else if (command.starts_with("bp")) {
- success = handle_breakpoint_command(command);
- } else if (command.starts_with("x")) {
- success = handle_examine_command(command);
- }
-
- if (success && !command.is_empty()) {
- // Don't add repeated commands to history
- if (editor->history().is_empty() || editor->history().last().entry != command)
- editor->add_to_history(command);
- }
- if (!success) {
- print_help();
- }
- if (decision.has_value())
- return decision.value();
- }
- });
-}
diff --git a/Applications/DisplaySettings/CMakeLists.txt b/Applications/DisplaySettings/CMakeLists.txt
deleted file mode 100644
index b541894194..0000000000
--- a/Applications/DisplaySettings/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-compile_gml(DisplaySettingsWindow.gml DisplaySettingsWindowGML.h display_settings_window_gml)
-
-set(SOURCES
- DisplaySettings.cpp
- DisplaySettingsWindowGML.h
- main.cpp
- MonitorWidget.cpp
-)
-
-serenity_app(DisplaySettings ICON app-display-settings)
-target_link_libraries(DisplaySettings LibGUI)
diff --git a/Applications/DisplaySettings/DisplaySettings.cpp b/Applications/DisplaySettings/DisplaySettings.cpp
deleted file mode 100644
index ad68ebf827..0000000000
--- a/Applications/DisplaySettings/DisplaySettings.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Jesse Buhagiar <jooster669@gmail.com>
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DisplaySettings.h"
-#include <AK/StringBuilder.h>
-#include <Applications/DisplaySettings/DisplaySettingsWindowGML.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/DirIterator.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/ComboBox.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/ItemListModel.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/SystemTheme.h>
-
-REGISTER_WIDGET(DisplaySettings, MonitorWidget)
-
-DisplaySettingsWidget::DisplaySettingsWidget()
-{
- create_resolution_list();
- create_wallpaper_list();
-
- create_frame();
-
- load_current_settings();
-}
-
-void DisplaySettingsWidget::create_resolution_list()
-{
- // TODO: Find a better way to get the default resolution
- m_resolutions.append({ 640, 480 });
- m_resolutions.append({ 800, 600 });
- m_resolutions.append({ 1024, 768 });
- m_resolutions.append({ 1280, 720 });
- m_resolutions.append({ 1280, 768 });
- m_resolutions.append({ 1280, 1024 });
- m_resolutions.append({ 1360, 768 });
- m_resolutions.append({ 1368, 768 });
- m_resolutions.append({ 1440, 900 });
- m_resolutions.append({ 1600, 900 });
- m_resolutions.append({ 1920, 1080 });
- m_resolutions.append({ 2560, 1080 });
-}
-
-void DisplaySettingsWidget::create_wallpaper_list()
-{
- Core::DirIterator iterator("/res/wallpapers/", Core::DirIterator::Flags::SkipDots);
-
- m_wallpapers.append("Use background color");
-
- while (iterator.has_next()) {
- m_wallpapers.append(iterator.next_path());
- }
-
- m_modes.append("simple");
- m_modes.append("tile");
- m_modes.append("center");
- m_modes.append("scaled");
-}
-
-void DisplaySettingsWidget::create_frame()
-{
- load_from_gml(display_settings_window_gml);
-
- m_monitor_widget = *find_descendant_of_type_named<DisplaySettings::MonitorWidget>("monitor_widget");
-
- m_wallpaper_combo = *find_descendant_of_type_named<GUI::ComboBox>("wallpaper_combo");
- m_wallpaper_combo->set_only_allow_values_from_model(true);
- m_wallpaper_combo->set_model(*GUI::ItemListModel<AK::String>::create(m_wallpapers));
- m_wallpaper_combo->on_change = [this](auto& text, const GUI::ModelIndex& index) {
- String path = text;
- if (path.starts_with("/") && m_monitor_widget->set_wallpaper(path)) {
- m_monitor_widget->update();
- return;
- }
-
- if (index.row() == 0) {
- path = "";
- } else {
- if (index.is_valid()) {
- StringBuilder builder;
- builder.append("/res/wallpapers/");
- builder.append(path);
- path = builder.to_string();
- }
- }
-
- m_monitor_widget->set_wallpaper(path);
- m_monitor_widget->update();
- };
-
- auto& button = *find_descendant_of_type_named<GUI::Button>("wallpaper_open_button");
- button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/open.png"));
- button.on_click = [this](auto) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(nullptr, "Select wallpaper from file system.");
-
- if (!open_path.has_value())
- return;
-
- m_wallpaper_combo->set_only_allow_values_from_model(false);
- m_wallpaper_combo->set_text(open_path.value());
- m_wallpaper_combo->set_only_allow_values_from_model(true);
- };
-
- m_mode_combo = *find_descendant_of_type_named<GUI::ComboBox>("mode_combo");
- m_mode_combo->set_only_allow_values_from_model(true);
- m_mode_combo->set_model(*GUI::ItemListModel<AK::String>::create(m_modes));
- m_mode_combo->on_change = [this](auto&, const GUI::ModelIndex& index) {
- m_monitor_widget->set_wallpaper_mode(m_modes.at(index.row()));
- m_monitor_widget->update();
- };
-
- m_resolution_combo = *find_descendant_of_type_named<GUI::ComboBox>("resolution_combo");
- m_resolution_combo->set_only_allow_values_from_model(true);
- m_resolution_combo->set_model(*GUI::ItemListModel<Gfx::IntSize>::create(m_resolutions));
- m_resolution_combo->on_change = [this](auto&, const GUI::ModelIndex& index) {
- m_monitor_widget->set_desktop_resolution(m_resolutions.at(index.row()));
- m_monitor_widget->update();
- };
-
- m_color_input = *find_descendant_of_type_named<GUI::ColorInput>("color_input");
- m_color_input->set_color_has_alpha_channel(false);
- m_color_input->set_color_picker_title("Select color for desktop");
- m_color_input->on_change = [this] {
- m_monitor_widget->set_background_color(m_color_input->color());
- m_monitor_widget->update();
- };
-
- auto& ok_button = *find_descendant_of_type_named<GUI::Button>("ok_button");
- ok_button.on_click = [this](auto) {
- send_settings_to_window_server();
- GUI::Application::the()->quit();
- };
-
- auto& cancel_button = *find_descendant_of_type_named<GUI::Button>("cancel_button");
- cancel_button.on_click = [](auto) {
- GUI::Application::the()->quit();
- };
-
- auto& apply_button = *find_descendant_of_type_named<GUI::Button>("apply_button");
- apply_button.on_click = [this](auto) {
- send_settings_to_window_server();
- };
-}
-
-void DisplaySettingsWidget::load_current_settings()
-{
- auto ws_config(Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini"));
- auto wm_config = Core::ConfigFile::get_for_app("WindowManager");
-
- /// Wallpaper path ////////////////////////////////////////////////////////////////////////////
- /// Read wallpaper path from config file and set value to monitor widget and combo box.
- auto selected_wallpaper = wm_config->read_entry("Background", "Wallpaper", "");
- if (!selected_wallpaper.is_empty()) {
- m_monitor_widget->set_wallpaper(selected_wallpaper);
-
- Optional<size_t> optional_index;
- if (selected_wallpaper.starts_with("/res/wallpapers/")) {
- auto name_parts = selected_wallpaper.split('/', true);
- optional_index = m_wallpapers.find_first_index(name_parts[2]);
-
- if (optional_index.has_value()) {
- m_wallpaper_combo->set_selected_index(optional_index.value());
- }
- }
-
- if (!optional_index.has_value()) {
- m_wallpaper_combo->set_only_allow_values_from_model(false);
- m_wallpaper_combo->set_text(selected_wallpaper);
- m_wallpaper_combo->set_only_allow_values_from_model(true);
- }
- } else {
- m_wallpaper_combo->set_selected_index(0);
- }
-
- size_t index;
-
- /// Mode //////////////////////////////////////////////////////////////////////////////////////
- auto mode = ws_config->read_entry("Background", "Mode", "simple");
- if (!m_modes.contains_slow(mode)) {
- warnln("Invalid background mode '{}' in WindowServer config, falling back to 'simple'", mode);
- mode = "simple";
- }
- m_monitor_widget->set_wallpaper_mode(mode);
- index = m_modes.find_first_index(mode).value();
- m_mode_combo->set_selected_index(index);
-
- /// Resolution ////////////////////////////////////////////////////////////////////////////////
- Gfx::IntSize find_size;
-
- // Let's attempt to find the current resolution and select it!
- find_size.set_width(ws_config->read_num_entry("Screen", "Width", 1024));
- find_size.set_height(ws_config->read_num_entry("Screen", "Height", 768));
-
- index = m_resolutions.find_first_index(find_size).value_or(0);
- Gfx::IntSize m_current_resolution = m_resolutions.at(index);
- m_monitor_widget->set_desktop_resolution(m_current_resolution);
- m_resolution_combo->set_selected_index(index);
-
- /// Color /////////////////////////////////////////////////////////////////////////////////////
- /// If presend read from config file. If not paint with palet color.
- Color palette_desktop_color = palette().desktop_background();
-
- auto background_color = ws_config->read_entry("Background", "Color", "");
- if (!background_color.is_empty()) {
- auto opt_color = Color::from_string(background_color);
- if (opt_color.has_value())
- palette_desktop_color = opt_color.value();
- }
-
- m_color_input->set_color(palette_desktop_color);
- m_monitor_widget->set_background_color(palette_desktop_color);
-
- m_monitor_widget->update();
-}
-
-void DisplaySettingsWidget::send_settings_to_window_server()
-{
- auto result = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetResolution>(m_monitor_widget->desktop_resolution());
- if (!result->success()) {
- GUI::MessageBox::show(nullptr, String::formatted("Reverting to resolution {}x{}", result->resolution().width(), result->resolution().height()),
- "Unable to set resolution", GUI::MessageBox::Type::Error);
- }
-
- if (!m_monitor_widget->wallpaper().is_empty()) {
- GUI::Desktop::the().set_wallpaper(m_monitor_widget->wallpaper());
- } else {
- dbgln("Setting color input: __{}__", m_color_input->text());
- GUI::Desktop::the().set_wallpaper("");
- GUI::Desktop::the().set_background_color(m_color_input->text());
- }
-
- GUI::Desktop::the().set_wallpaper_mode(m_monitor_widget->wallpaper_mode());
-}
diff --git a/Applications/DisplaySettings/DisplaySettings.h b/Applications/DisplaySettings/DisplaySettings.h
deleted file mode 100644
index 30fb26ebed..0000000000
--- a/Applications/DisplaySettings/DisplaySettings.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Jesse Buhagiar <jooster669@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "MonitorWidget.h"
-#include <LibGUI/ColorInput.h>
-#include <LibGUI/ComboBox.h>
-
-class DisplaySettingsWidget : public GUI::Widget {
- C_OBJECT(DisplaySettingsWidget);
-
-public:
- DisplaySettingsWidget();
-
-private:
- void create_frame();
- void create_wallpaper_list();
- void create_resolution_list();
- void load_current_settings();
- void send_settings_to_window_server(); // Apply the settings to the Window Server
-
- Vector<String> m_wallpapers;
- Vector<String> m_modes;
- Vector<Gfx::IntSize> m_resolutions;
-
- RefPtr<DisplaySettings::MonitorWidget> m_monitor_widget;
- RefPtr<GUI::ComboBox> m_wallpaper_combo;
- RefPtr<GUI::ComboBox> m_mode_combo;
- RefPtr<GUI::ComboBox> m_resolution_combo;
- RefPtr<GUI::ColorInput> m_color_input;
-};
diff --git a/Applications/DisplaySettings/DisplaySettingsWindow.gml b/Applications/DisplaySettings/DisplaySettingsWindow.gml
deleted file mode 100644
index af9f204f03..0000000000
--- a/Applications/DisplaySettings/DisplaySettingsWindow.gml
+++ /dev/null
@@ -1,117 +0,0 @@
-@GUI::Widget {
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [4, 4, 4, 4]
- }
-
- @DisplaySettings::MonitorWidget {
- name: "monitor_widget"
- fixed_width: 338
- fixed_height: 248
- }
-
- @GUI::Widget {
- shrink_to_fit: true
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Wallpaper:"
- text_alignment: "CenterLeft"
- fixed_width: 70
- }
-
- @GUI::ComboBox {
- name: "wallpaper_combo"
- }
-
- @GUI::Button {
- name: "wallpaper_open_button"
- tooltip: "Select wallpaper from file system."
- button_style: "CoolBar"
- fixed_width: 22
- fixed_height: 22
- }
- }
-
- @GUI::Widget {
- shrink_to_fit: true
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Modes:"
- text_alignment: "CenterLeft"
- fixed_width: 70
- }
-
- @GUI::ComboBox {
- name: "mode_combo"
- }
- }
-
- @GUI::Widget {
- shrink_to_fit: true
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Resolution:"
- text_alignment: "CenterLeft"
- fixed_width: 70
- }
-
- @GUI::ComboBox {
- name: "resolution_combo"
- }
- }
-
-
- @GUI::Widget {
- shrink_to_fit: true
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Color:"
- text_alignment: "CenterLeft"
- fixed_width: 70
- }
-
- @GUI::ColorInput {
- name: "color_input"
- fixed_width: 90
- }
- }
-
- @GUI::Widget {
- }
-
- @GUI::Widget {
- shrink_to_fit: true
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Widget {
- }
-
- @GUI::Button {
- name: "ok_button"
- text: "OK"
- fixed_width: 60
- }
-
- @GUI::Button {
- name: "cancel_button"
- text: "Cancel"
- fixed_width: 60
- }
-
- @GUI::Button {
- name: "apply_button"
- text: "Apply"
- fixed_width: 60
- }
- }
-}
diff --git a/Applications/DisplaySettings/MonitorWidget.cpp b/Applications/DisplaySettings/MonitorWidget.cpp
deleted file mode 100644
index d6b809d449..0000000000
--- a/Applications/DisplaySettings/MonitorWidget.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "MonitorWidget.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/Bitmap.h>
-
-namespace DisplaySettings {
-
-MonitorWidget::MonitorWidget()
-{
- m_monitor_bitmap = Gfx::Bitmap::load_from_file("/res/graphics/monitor.png");
- m_monitor_rect = { 8, 9, 320, 180 };
-}
-
-bool MonitorWidget::set_wallpaper(String path)
-{
- auto bitmap_ptr = Gfx::Bitmap::load_from_file(path);
- if (!bitmap_ptr && !path.is_empty())
- return false;
- m_desktop_wallpaper_path = path;
- m_desktop_wallpaper_bitmap = bitmap_ptr;
- return true;
-}
-
-String MonitorWidget::wallpaper()
-{
- return m_desktop_wallpaper_path;
-}
-
-void MonitorWidget::set_wallpaper_mode(String mode)
-{
- m_desktop_wallpaper_mode = mode;
-}
-
-String MonitorWidget::wallpaper_mode()
-{
- return m_desktop_wallpaper_mode;
-}
-
-void MonitorWidget::set_desktop_resolution(Gfx::IntSize resolution)
-{
- m_desktop_resolution = resolution;
-}
-
-Gfx::IntSize MonitorWidget::desktop_resolution()
-{
- return m_desktop_resolution;
-}
-
-void MonitorWidget::set_background_color(Gfx::Color color)
-{
- m_desktop_color = color;
-}
-
-Gfx::Color MonitorWidget::background_color()
-{
- return m_desktop_color;
-}
-
-void MonitorWidget::paint_event(GUI::PaintEvent& event)
-{
- Gfx::IntRect screen_rect = { 0, 0, m_desktop_resolution.width(), m_desktop_resolution.height() };
- auto screen_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), m_desktop_resolution);
- GUI::Painter screen_painter(*screen_bitmap);
- screen_painter.fill_rect(screen_rect, m_desktop_color);
-
- if (!m_desktop_wallpaper_bitmap.is_null()) {
- if (m_desktop_wallpaper_mode == "simple") {
- screen_painter.blit({ 0, 0 }, *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect());
- } else if (m_desktop_wallpaper_mode == "center") {
- Gfx::IntPoint offset { screen_rect.width() / 2 - m_desktop_wallpaper_bitmap->size().width() / 2, screen_rect.height() / 2 - m_desktop_wallpaper_bitmap->size().height() / 2 };
- screen_painter.blit_offset(screen_rect.location(), *m_desktop_wallpaper_bitmap, screen_rect, offset);
- } else if (m_desktop_wallpaper_mode == "tile") {
- screen_painter.draw_tiled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap);
- } else if (m_desktop_wallpaper_mode == "scaled") {
- screen_painter.draw_scaled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect());
- } else {
- ASSERT_NOT_REACHED();
- }
- }
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- painter.blit({ 0, 0 }, *m_monitor_bitmap, m_monitor_bitmap->rect());
- painter.draw_scaled_bitmap(m_monitor_rect, *screen_bitmap, screen_bitmap->rect());
-
- if (!m_desktop_resolution.is_null()) {
- painter.draw_text(m_monitor_rect.translated(1, 1), m_desktop_resolution.to_string(), Gfx::TextAlignment::Center, Color::Black);
- painter.draw_text(m_monitor_rect, m_desktop_resolution.to_string(), Gfx::TextAlignment::Center, Color::White);
- }
-}
-
-}
diff --git a/Applications/DisplaySettings/MonitorWidget.h b/Applications/DisplaySettings/MonitorWidget.h
deleted file mode 100644
index 1961e91330..0000000000
--- a/Applications/DisplaySettings/MonitorWidget.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-namespace DisplaySettings {
-
-class MonitorWidget final : public GUI::Widget {
- C_OBJECT(MonitorWidget);
-
-public:
- bool set_wallpaper(String path);
- String wallpaper();
-
- void set_wallpaper_mode(String mode);
- String wallpaper_mode();
-
- void set_desktop_resolution(Gfx::IntSize resolution);
- Gfx::IntSize desktop_resolution();
-
- void set_background_color(Gfx::Color background_color);
- Gfx::Color background_color();
-
-private:
- MonitorWidget();
-
- virtual void paint_event(GUI::PaintEvent& event) override;
-
- Gfx::IntRect m_monitor_rect;
- RefPtr<Gfx::Bitmap> m_monitor_bitmap;
-
- String m_desktop_wallpaper_path;
- RefPtr<Gfx::Bitmap> m_desktop_wallpaper_bitmap;
- String m_desktop_wallpaper_mode;
- Gfx::IntSize m_desktop_resolution;
- Gfx::Color m_desktop_color;
-};
-
-}
diff --git a/Applications/DisplaySettings/main.cpp b/Applications/DisplaySettings/main.cpp
deleted file mode 100644
index 5018893470..0000000000
--- a/Applications/DisplaySettings/main.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Jesse Buhagiar <jooster669@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DisplaySettings.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio thread shared_buffer rpath accept cpath wpath unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread shared_buffer rpath accept cpath wpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-display-settings");
-
- // Let's create the tab pane that we'll hook our widgets up to :^)
- auto tab_widget = GUI::TabWidget::construct();
- tab_widget->add_tab<DisplaySettingsWidget>("Display Settings");
- tab_widget->set_fill_with_background_color(true); // No black backgrounds!
-
- auto window = GUI::Window::construct();
- dbgln("main window: {}", window);
- window->set_title("Display Settings");
- window->resize(360, 410);
- window->set_resizable(false);
- window->set_main_widget(tab_widget.ptr());
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Display Settings");
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](const GUI::Action&) {
- app->quit();
- }));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Display Settings", app_icon));
-
- app->set_menubar(move(menubar));
- window->show();
- return app->exec();
-}
diff --git a/Applications/FileManager/CMakeLists.txt b/Applications/FileManager/CMakeLists.txt
deleted file mode 100644
index d81fc89bef..0000000000
--- a/Applications/FileManager/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_gml(FileManagerWindow.gml FileManagerWindowGML.h file_manager_window_gml)
-
-set(SOURCES
- DesktopWidget.cpp
- DirectoryView.cpp
- FileManagerWindowGML.h
- FileUtils.cpp
- main.cpp
- PropertiesWindow.cpp
-)
-
-serenity_app(FileManager ICON filetype-folder)
-target_link_libraries(FileManager LibGUI LibDesktop)
diff --git a/Applications/FileManager/DesktopWidget.cpp b/Applications/FileManager/DesktopWidget.cpp
deleted file mode 100644
index 7ea01de9e8..0000000000
--- a/Applications/FileManager/DesktopWidget.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DesktopWidget.h"
-#include <LibGUI/Painter.h>
-
-namespace FileManager {
-
-DesktopWidget::DesktopWidget()
-{
-}
-
-DesktopWidget::~DesktopWidget()
-{
-}
-
-void DesktopWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.clear_rect(event.rect(), Color(0, 0, 0, 0));
-}
-
-}
diff --git a/Applications/FileManager/DesktopWidget.h b/Applications/FileManager/DesktopWidget.h
deleted file mode 100644
index a6fd5b614b..0000000000
--- a/Applications/FileManager/DesktopWidget.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-namespace FileManager {
-
-class DesktopWidget final : public GUI::Widget {
- C_OBJECT(DesktopWidget);
-
-public:
- virtual ~DesktopWidget() override;
-
-private:
- virtual void paint_event(GUI::PaintEvent&) override;
-
- DesktopWidget();
-};
-
-}
diff --git a/Applications/FileManager/DirectoryView.cpp b/Applications/FileManager/DirectoryView.cpp
deleted file mode 100644
index 6d47d89671..0000000000
--- a/Applications/FileManager/DirectoryView.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DirectoryView.h"
-#include "FileUtils.h"
-#include <AK/LexicalPath.h>
-#include <AK/NumberFormat.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/MimeData.h>
-#include <LibCore/StandardPaths.h>
-#include <LibGUI/FileIconProvider.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/ModelEditingDelegate.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <serenity.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <unistd.h>
-
-namespace FileManager {
-
-NonnullRefPtr<GUI::Action> LauncherHandler::create_launch_action(Function<void(const LauncherHandler&)> launch_handler)
-{
- auto icon = GUI::FileIconProvider::icon_for_executable(details().executable).bitmap_for_size(16);
- return GUI::Action::create(details().name, move(icon), [this, launch_handler = move(launch_handler)](auto&) {
- launch_handler(*this);
- });
-}
-
-RefPtr<LauncherHandler> DirectoryView::get_default_launch_handler(const NonnullRefPtrVector<LauncherHandler>& handlers)
-{
- // If this is an application, pick it first
- for (size_t i = 0; i < handlers.size(); i++) {
- if (handlers[i].details().launcher_type == Desktop::Launcher::LauncherType::Application)
- return handlers[i];
- }
- // If there's a handler preferred by the user, pick this first
- for (size_t i = 0; i < handlers.size(); i++) {
- if (handlers[i].details().launcher_type == Desktop::Launcher::LauncherType::UserPreferred)
- return handlers[i];
- }
- // Otherwise, use the user's default, if available
- for (size_t i = 0; i < handlers.size(); i++) {
- if (handlers[i].details().launcher_type == Desktop::Launcher::LauncherType::UserDefault)
- return handlers[i];
- }
- // If still no match, use the first one we find
- if (!handlers.is_empty()) {
- return handlers[0];
- }
-
- return {};
-}
-
-NonnullRefPtrVector<LauncherHandler> DirectoryView::get_launch_handlers(const URL& url)
-{
- NonnullRefPtrVector<LauncherHandler> handlers;
- for (auto& h : Desktop::Launcher::get_handlers_with_details_for_url(url)) {
- handlers.append(adopt(*new LauncherHandler(h)));
- }
- return handlers;
-}
-
-NonnullRefPtrVector<LauncherHandler> DirectoryView::get_launch_handlers(const String& path)
-{
- return get_launch_handlers(URL::create_with_file_protocol(path));
-}
-
-void DirectoryView::handle_activation(const GUI::ModelIndex& index)
-{
- if (!index.is_valid())
- return;
- dbgln("on activation: {},{}, this={:p}, m_model={:p}", index.row(), index.column(), this, m_model.ptr());
- auto& node = this->node(index);
- auto path = node.full_path();
-
- struct stat st;
- if (stat(path.characters(), &st) < 0) {
- perror("stat");
- return;
- }
-
- if (S_ISDIR(st.st_mode)) {
- if (is_desktop()) {
- Desktop::Launcher::open(URL::create_with_file_protocol(path));
- return;
- }
- open(path);
- return;
- }
-
- auto url = URL::create_with_file_protocol(path);
- auto launcher_handlers = get_launch_handlers(url);
- auto default_launcher = get_default_launch_handler(launcher_handlers);
- if (default_launcher) {
- launch(url, *default_launcher);
- } else {
- auto error_message = String::format("Could not open %s", path.characters());
- GUI::MessageBox::show(window(), error_message, "File Manager", GUI::MessageBox::Type::Error);
- }
-}
-
-DirectoryView::DirectoryView(Mode mode)
- : m_mode(mode)
- , m_model(GUI::FileSystemModel::create({}))
- , m_sorting_model(GUI::SortingProxyModel::create(m_model))
-{
- set_active_widget(nullptr);
- set_content_margins({ 2, 2, 2, 2 });
-
- setup_actions();
-
- m_error_label = add<GUI::Label>();
- m_error_label->set_font(m_error_label->font().bold_variant());
-
- setup_model();
-
- setup_icon_view();
- if (mode != Mode::Desktop) {
- setup_columns_view();
- setup_table_view();
- }
-
- set_view_mode(ViewMode::Icon);
-}
-
-const GUI::FileSystemModel::Node& DirectoryView::node(const GUI::ModelIndex& index) const
-{
- return model().node(m_sorting_model->map_to_source(index));
-}
-
-void DirectoryView::setup_model()
-{
- m_model->on_error = [this](int, const char* error_string) {
- auto failed_path = m_model->root_path();
- auto error_message = String::formatted("Could not read {}:\n{}", failed_path, error_string);
- m_error_label->set_text(error_message);
- set_active_widget(m_error_label);
-
- m_mkdir_action->set_enabled(false);
- m_touch_action->set_enabled(false);
-
- add_path_to_history(model().root_path());
-
- if (on_path_change)
- on_path_change(failed_path, false);
- };
-
- m_model->on_complete = [this] {
- if (m_table_view)
- m_table_view->selection().clear();
- if (m_icon_view)
- m_icon_view->selection().clear();
-
- add_path_to_history(model().root_path());
-
- bool can_write_in_path = access(model().root_path().characters(), W_OK) == 0;
-
- m_mkdir_action->set_enabled(can_write_in_path);
- m_touch_action->set_enabled(can_write_in_path);
-
- if (on_path_change)
- on_path_change(model().root_path(), can_write_in_path);
- };
-
- m_model->register_client(*this);
-
- m_model->on_thumbnail_progress = [this](int done, int total) {
- if (on_thumbnail_progress)
- on_thumbnail_progress(done, total);
- };
-
- if (is_desktop())
- m_model->set_root_path(Core::StandardPaths::desktop_directory());
-}
-
-void DirectoryView::setup_icon_view()
-{
- m_icon_view = add<GUI::IconView>();
- m_icon_view->set_should_hide_unnecessary_scrollbars(true);
- m_icon_view->set_selection_mode(GUI::AbstractView::SelectionMode::MultiSelection);
- m_icon_view->set_editable(true);
- m_icon_view->set_edit_triggers(GUI::AbstractView::EditTrigger::EditKeyPressed);
- m_icon_view->aid_create_editing_delegate = [](auto&) {
- return make<GUI::StringModelEditingDelegate>();
- };
-
- if (is_desktop()) {
- m_icon_view->set_frame_shape(Gfx::FrameShape::NoFrame);
- m_icon_view->set_scrollbars_enabled(false);
- m_icon_view->set_fill_with_background_color(false);
- m_icon_view->set_draw_item_text_with_shadow(true);
- m_icon_view->set_flow_direction(GUI::IconView::FlowDirection::TopToBottom);
- }
-
- m_icon_view->set_model(m_sorting_model);
- m_icon_view->set_model_column(GUI::FileSystemModel::Column::Name);
- m_icon_view->on_activation = [&](auto& index) {
- handle_activation(index);
- };
- m_icon_view->on_selection_change = [this] {
- handle_selection_change();
- };
- m_icon_view->on_context_menu_request = [this](auto& index, auto& event) {
- if (on_context_menu_request)
- on_context_menu_request(index, event);
- };
- m_icon_view->on_drop = [this](auto& index, auto& event) {
- handle_drop(index, event);
- };
-}
-
-void DirectoryView::setup_columns_view()
-{
- m_columns_view = add<GUI::ColumnsView>();
- m_columns_view->set_should_hide_unnecessary_scrollbars(true);
- m_columns_view->set_selection_mode(GUI::AbstractView::SelectionMode::MultiSelection);
- m_columns_view->set_editable(true);
- m_columns_view->set_edit_triggers(GUI::AbstractView::EditTrigger::EditKeyPressed);
- m_columns_view->aid_create_editing_delegate = [](auto&) {
- return make<GUI::StringModelEditingDelegate>();
- };
-
- m_columns_view->set_model(m_sorting_model);
- m_columns_view->set_model_column(GUI::FileSystemModel::Column::Name);
-
- m_columns_view->on_activation = [&](auto& index) {
- handle_activation(index);
- };
-
- m_columns_view->on_selection_change = [this] {
- handle_selection_change();
- };
-
- m_columns_view->on_context_menu_request = [this](auto& index, auto& event) {
- if (on_context_menu_request)
- on_context_menu_request(index, event);
- };
-
- m_columns_view->on_drop = [this](auto& index, auto& event) {
- handle_drop(index, event);
- };
-}
-
-void DirectoryView::setup_table_view()
-{
- m_table_view = add<GUI::TableView>();
- m_table_view->set_should_hide_unnecessary_scrollbars(true);
- m_table_view->set_selection_mode(GUI::AbstractView::SelectionMode::MultiSelection);
- m_table_view->set_editable(true);
- m_table_view->set_edit_triggers(GUI::AbstractView::EditTrigger::EditKeyPressed);
- m_table_view->aid_create_editing_delegate = [](auto&) {
- return make<GUI::StringModelEditingDelegate>();
- };
-
- m_table_view->set_model(m_sorting_model);
- m_table_view->set_key_column_and_sort_order(GUI::FileSystemModel::Column::Name, GUI::SortOrder::Ascending);
-
- m_table_view->on_activation = [&](auto& index) {
- handle_activation(index);
- };
-
- m_table_view->on_selection_change = [this] {
- handle_selection_change();
- };
-
- m_table_view->on_context_menu_request = [this](auto& index, auto& event) {
- if (on_context_menu_request)
- on_context_menu_request(index, event);
- };
-
- m_table_view->on_drop = [this](auto& index, auto& event) {
- handle_drop(index, event);
- };
-}
-
-DirectoryView::~DirectoryView()
-{
- m_model->unregister_client(*this);
-}
-
-void DirectoryView::model_did_update(unsigned flags)
-{
- if (flags & GUI::Model::UpdateFlag::InvalidateAllIndexes) {
- for_each_view_implementation([](auto& view) {
- view.selection().clear();
- });
- }
- update_statusbar();
-}
-
-void DirectoryView::set_view_mode(ViewMode mode)
-{
- if (m_view_mode == mode)
- return;
- m_view_mode = mode;
- update();
- if (mode == ViewMode::Table) {
- set_active_widget(m_table_view);
- return;
- }
- if (mode == ViewMode::Columns) {
- set_active_widget(m_columns_view);
- return;
- }
- if (mode == ViewMode::Icon) {
- set_active_widget(m_icon_view);
- return;
- }
- ASSERT_NOT_REACHED();
-}
-
-void DirectoryView::add_path_to_history(const StringView& path)
-{
- if (m_path_history.size() && m_path_history.at(m_path_history_position) == path)
- return;
-
- if (m_path_history_position < m_path_history.size())
- m_path_history.resize(m_path_history_position + 1);
-
- m_path_history.append(path);
- m_path_history_position = m_path_history.size() - 1;
-}
-
-void DirectoryView::open(const StringView& path)
-{
- if (model().root_path() == path) {
- model().update();
- return;
- }
-
- set_active_widget(&current_view());
- model().set_root_path(path);
-}
-
-void DirectoryView::set_status_message(const StringView& message)
-{
- if (on_status_message)
- on_status_message(message);
-}
-
-void DirectoryView::open_parent_directory()
-{
- auto path = String::formatted("{}/..", model().root_path());
- model().set_root_path(path);
-}
-
-void DirectoryView::refresh()
-{
- model().update();
-}
-
-void DirectoryView::open_previous_directory()
-{
- if (m_path_history_position > 0) {
- set_active_widget(&current_view());
- m_path_history_position--;
- model().set_root_path(m_path_history[m_path_history_position]);
- }
-}
-void DirectoryView::open_next_directory()
-{
- if (m_path_history_position < m_path_history.size() - 1) {
- set_active_widget(&current_view());
- m_path_history_position++;
- model().set_root_path(m_path_history[m_path_history_position]);
- }
-}
-
-void DirectoryView::update_statusbar()
-{
- // If we're triggered during widget construction, just ignore it.
- if (m_view_mode == ViewMode::Invalid)
- return;
-
- size_t total_size = model().node({}).total_size;
- if (current_view().selection().is_empty()) {
- set_status_message(String::formatted("{} item(s) ({})",
- model().row_count(),
- human_readable_size(total_size)));
- return;
- }
-
- int selected_item_count = current_view().selection().size();
- size_t selected_byte_count = 0;
-
- current_view().selection().for_each_index([&](auto& index) {
- auto& model = *current_view().model();
- auto size_index = model.index(index.row(), GUI::FileSystemModel::Column::Size, model.parent_index(index));
- auto file_size = size_index.data().to_i32();
- selected_byte_count += file_size;
- });
-
- StringBuilder builder;
- builder.append(String::number(selected_item_count));
- builder.append(" item");
- if (selected_item_count != 1)
- builder.append('s');
- builder.append(" selected (");
- builder.append(human_readable_size(selected_byte_count).characters());
- builder.append(')');
-
- if (selected_item_count == 1) {
- auto& node = this->node(current_view().selection().first());
- if (!node.symlink_target.is_empty()) {
- builder.append(" -> ");
- builder.append(node.symlink_target);
- }
- }
-
- set_status_message(builder.to_string());
-}
-
-void DirectoryView::set_should_show_dotfiles(bool show_dotfiles)
-{
- m_model->set_should_show_dotfiles(show_dotfiles);
-}
-
-void DirectoryView::launch(const URL&, const LauncherHandler& launcher_handler)
-{
- pid_t child;
- if (launcher_handler.details().launcher_type == Desktop::Launcher::LauncherType::Application) {
- const char* argv[] = { launcher_handler.details().name.characters(), nullptr };
- posix_spawn(&child, launcher_handler.details().executable.characters(), nullptr, nullptr, const_cast<char**>(argv), environ);
- if (disown(child) < 0)
- perror("disown");
- } else {
- for (auto& path : selected_file_paths()) {
- const char* argv[] = { launcher_handler.details().name.characters(), path.characters(), nullptr };
- posix_spawn(&child, launcher_handler.details().executable.characters(), nullptr, nullptr, const_cast<char**>(argv), environ);
- if (disown(child) < 0)
- perror("disown");
- }
- }
-}
-
-Vector<String> DirectoryView::selected_file_paths() const
-{
- Vector<String> paths;
- auto& view = current_view();
- auto& model = *view.model();
- view.selection().for_each_index([&](const GUI::ModelIndex& index) {
- auto parent_index = model.parent_index(index);
- auto name_index = model.index(index.row(), GUI::FileSystemModel::Column::Name, parent_index);
- auto path = name_index.data(GUI::ModelRole::Custom).to_string();
- paths.append(path);
- });
- return paths;
-}
-
-void DirectoryView::do_delete(bool should_confirm)
-{
- auto paths = selected_file_paths();
- ASSERT(!paths.is_empty());
- FileUtils::delete_paths(paths, should_confirm, window());
-}
-
-void DirectoryView::handle_selection_change()
-{
- update_statusbar();
-
- bool can_delete = !current_view().selection().is_empty() && access(path().characters(), W_OK) == 0;
- m_delete_action->set_enabled(can_delete);
- m_force_delete_action->set_enabled(can_delete);
-
- if (on_selection_change)
- on_selection_change(current_view());
-}
-
-void DirectoryView::setup_actions()
-{
- m_mkdir_action = GUI::Action::create("New directory...", { Mod_Ctrl | Mod_Shift, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/mkdir.png"), [&](const GUI::Action&) {
- String value;
- if (GUI::InputBox::show(value, window(), "Enter name:", "New directory") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto new_dir_path = LexicalPath::canonicalized_path(String::formatted("{}/{}", path(), value));
- int rc = mkdir(new_dir_path.characters(), 0777);
- if (rc < 0) {
- auto saved_errno = errno;
- GUI::MessageBox::show(window(), String::formatted("mkdir(\"{}\") failed: {}", new_dir_path, strerror(saved_errno)), "Error", GUI::MessageBox::Type::Error);
- }
- }
- });
-
- m_touch_action = GUI::Action::create("New file...", { Mod_Ctrl | Mod_Shift, Key_F }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new.png"), [&](const GUI::Action&) {
- String value;
- if (GUI::InputBox::show(value, window(), "Enter name:", "New file") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto new_file_path = LexicalPath::canonicalized_path(String::formatted("{}/{}", path(), value));
- struct stat st;
- int rc = stat(new_file_path.characters(), &st);
- if ((rc < 0 && errno != ENOENT)) {
- auto saved_errno = errno;
- GUI::MessageBox::show(window(), String::formatted("stat(\"{}\") failed: {}", new_file_path, strerror(saved_errno)), "Error", GUI::MessageBox::Type::Error);
- return;
- }
- if (rc == 0) {
- GUI::MessageBox::show(window(), String::formatted("{}: Already exists", new_file_path), "Error", GUI::MessageBox::Type::Error);
- return;
- }
- int fd = creat(new_file_path.characters(), 0666);
- if (fd < 0) {
- auto saved_errno = errno;
- GUI::MessageBox::show(window(), String::formatted("creat(\"{}\") failed: {}", new_file_path, strerror(saved_errno)), "Error", GUI::MessageBox::Type::Error);
- return;
- }
- rc = close(fd);
- ASSERT(rc >= 0);
- }
- });
-
- m_open_terminal_action = GUI::Action::create("Open Terminal here", Gfx::Bitmap::load_from_file("/res/icons/16x16/app-terminal.png"), [&](auto&) {
- posix_spawn_file_actions_t spawn_actions;
- posix_spawn_file_actions_init(&spawn_actions);
- posix_spawn_file_actions_addchdir(&spawn_actions, path().characters());
- pid_t pid;
- const char* argv[] = { "Terminal", nullptr };
- if ((errno = posix_spawn(&pid, "/bin/Terminal", &spawn_actions, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(pid) < 0)
- perror("disown");
- }
- posix_spawn_file_actions_destroy(&spawn_actions);
- });
-
- m_delete_action = GUI::CommonActions::make_delete_action([this](auto&) { do_delete(true); }, window());
-
- m_force_delete_action = GUI::Action::create(
- "Delete without confirmation", { Mod_Shift, Key_Delete },
- [this](auto&) { do_delete(false); },
- window());
-}
-
-void DirectoryView::handle_drop(const GUI::ModelIndex& index, const GUI::DropEvent& event)
-{
- if (!event.mime_data().has_urls())
- return;
- auto urls = event.mime_data().urls();
- if (urls.is_empty()) {
- dbgln("No files to drop");
- return;
- }
-
- auto& target_node = node(index);
- if (!target_node.is_directory())
- return;
-
- bool had_accepted_drop = false;
- for (auto& url_to_copy : urls) {
- if (!url_to_copy.is_valid() || url_to_copy.path() == target_node.full_path())
- continue;
- auto new_path = String::formatted("{}/{}", target_node.full_path(), LexicalPath(url_to_copy.path()).basename());
- if (url_to_copy.path() == new_path)
- continue;
-
- if (!FileUtils::copy_file_or_directory(url_to_copy.path(), new_path)) {
- auto error_message = String::formatted("Could not copy {} into {}.", url_to_copy.to_string(), new_path);
- GUI::MessageBox::show(window(), error_message, "File Manager", GUI::MessageBox::Type::Error);
- } else {
- had_accepted_drop = true;
- }
- }
- if (had_accepted_drop && on_accepted_drop)
- on_accepted_drop();
-}
-
-}
diff --git a/Applications/FileManager/DirectoryView.h b/Applications/FileManager/DirectoryView.h
deleted file mode 100644
index a72b63aaf5..0000000000
--- a/Applications/FileManager/DirectoryView.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/URL.h>
-#include <AK/Vector.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ColumnsView.h>
-#include <LibGUI/FileSystemModel.h>
-#include <LibGUI/IconView.h>
-#include <LibGUI/StackWidget.h>
-#include <LibGUI/TableView.h>
-#include <sys/stat.h>
-
-namespace FileManager {
-
-class LauncherHandler : public RefCounted<LauncherHandler> {
-public:
- LauncherHandler(const NonnullRefPtr<Desktop::Launcher::Details>& details)
- : m_details(details)
- {
- }
-
- NonnullRefPtr<GUI::Action> create_launch_action(Function<void(const LauncherHandler&)>);
- const Desktop::Launcher::Details& details() const { return *m_details; }
-
-private:
- NonnullRefPtr<Desktop::Launcher::Details> m_details;
-};
-
-class DirectoryView final
- : public GUI::StackWidget
- , private GUI::ModelClient {
- C_OBJECT(DirectoryView);
-
-public:
- enum class Mode {
- Desktop,
- Normal,
- };
-
- virtual ~DirectoryView() override;
-
- void open(const StringView& path);
- String path() const { return model().root_path(); }
- void open_parent_directory();
- void open_previous_directory();
- void open_next_directory();
- int path_history_size() const { return m_path_history.size(); }
- int path_history_position() const { return m_path_history_position; }
- static RefPtr<LauncherHandler> get_default_launch_handler(const NonnullRefPtrVector<LauncherHandler>& handlers);
- NonnullRefPtrVector<LauncherHandler> get_launch_handlers(const URL& url);
- NonnullRefPtrVector<LauncherHandler> get_launch_handlers(const String& path);
-
- void refresh();
-
- void launch(const AK::URL&, const LauncherHandler&);
-
- Function<void(const StringView& path, bool can_write_in_path)> on_path_change;
- Function<void(GUI::AbstractView&)> on_selection_change;
- Function<void(const GUI::ModelIndex&, const GUI::ContextMenuEvent&)> on_context_menu_request;
- Function<void(const StringView&)> on_status_message;
- Function<void(int done, int total)> on_thumbnail_progress;
- Function<void()> on_accepted_drop;
-
- enum ViewMode {
- Invalid,
- Table,
- Columns,
- Icon
- };
- void set_view_mode(ViewMode);
- ViewMode view_mode() const { return m_view_mode; }
-
- GUI::AbstractView& current_view()
- {
- switch (m_view_mode) {
- case ViewMode::Table:
- return *m_table_view;
- case ViewMode::Columns:
- return *m_columns_view;
- case ViewMode::Icon:
- return *m_icon_view;
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- const GUI::AbstractView& current_view() const
- {
- return const_cast<DirectoryView*>(this)->current_view();
- }
-
- template<typename Callback>
- void for_each_view_implementation(Callback callback)
- {
- if (m_icon_view)
- callback(*m_icon_view);
- if (m_table_view)
- callback(*m_table_view);
- if (m_columns_view)
- callback(*m_columns_view);
- }
-
- void set_should_show_dotfiles(bool);
-
- const GUI::FileSystemModel::Node& node(const GUI::ModelIndex&) const;
-
- bool is_desktop() const { return m_mode == Mode::Desktop; }
-
- Vector<String> selected_file_paths() const;
-
- GUI::Action& mkdir_action() { return *m_mkdir_action; }
- GUI::Action& touch_action() { return *m_touch_action; }
- GUI::Action& open_terminal_action() { return *m_open_terminal_action; }
- GUI::Action& delete_action() { return *m_delete_action; }
- GUI::Action& force_delete_action() { return *m_force_delete_action; }
-
-private:
- explicit DirectoryView(Mode);
-
- const GUI::FileSystemModel& model() const { return *m_model; }
- GUI::FileSystemModel& model() { return *m_model; }
-
- void handle_selection_change();
- void handle_drop(const GUI::ModelIndex&, const GUI::DropEvent&);
- void do_delete(bool should_confirm);
-
- // ^GUI::ModelClient
- virtual void model_did_update(unsigned) override;
-
- void setup_actions();
- void setup_model();
- void setup_icon_view();
- void setup_columns_view();
- void setup_table_view();
-
- void handle_activation(const GUI::ModelIndex&);
-
- void set_status_message(const StringView&);
- void update_statusbar();
-
- Mode m_mode { Mode::Normal };
- ViewMode m_view_mode { Invalid };
-
- NonnullRefPtr<GUI::FileSystemModel> m_model;
- NonnullRefPtr<GUI::SortingProxyModel> m_sorting_model;
- size_t m_path_history_position { 0 };
- Vector<String> m_path_history;
- void add_path_to_history(const StringView& path);
-
- RefPtr<GUI::Label> m_error_label;
-
- RefPtr<GUI::TableView> m_table_view;
- RefPtr<GUI::IconView> m_icon_view;
- RefPtr<GUI::ColumnsView> m_columns_view;
-
- RefPtr<GUI::Action> m_mkdir_action;
- RefPtr<GUI::Action> m_touch_action;
- RefPtr<GUI::Action> m_open_terminal_action;
- RefPtr<GUI::Action> m_delete_action;
- RefPtr<GUI::Action> m_force_delete_action;
-};
-
-}
diff --git a/Applications/FileManager/FileManagerWindow.gml b/Applications/FileManager/FileManagerWindow.gml
deleted file mode 100644
index a13218dd16..0000000000
--- a/Applications/FileManager/FileManagerWindow.gml
+++ /dev/null
@@ -1,53 +0,0 @@
-@GUI::Widget {
- fill_with_background_color: true
- layout: @GUI::VerticalBoxLayout {
- spacing: 2
- }
-
- @GUI::ToolBarContainer {
- @GUI::ToolBar {
- name: "main_toolbar"
- }
- @GUI::ToolBar {
- name: "location_toolbar"
- visible: false
-
- @GUI::Label {
- text: "Location: "
- autosize: true
- }
-
- @GUI::TextBox {
- name: "location_textbox"
- fixed_height: 22
- }
- }
- @GUI::ToolBar {
- name: "breadcrumb_toolbar"
-
- @GUI::BreadcrumbBar {
- name: "breadcrumb_bar"
- }
- }
- }
-
- @GUI::HorizontalSplitter {
- name: "splitter"
-
- @GUI::TreeView {
- name: "tree_view"
- fixed_width: 175
- }
-
- }
-
- @GUI::StatusBar {
- name: "statusbar"
-
- @GUI::ProgressBar {
- name: "progressbar"
- text: "Generating thumbnails: "
- visible: false
- }
- }
-}
diff --git a/Applications/FileManager/FileUtils.cpp b/Applications/FileManager/FileUtils.cpp
deleted file mode 100644
index 76d2ee0079..0000000000
--- a/Applications/FileManager/FileUtils.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "FileUtils.h"
-#include <AK/LexicalPath.h>
-#include <AK/ScopeGuard.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <LibGUI/MessageBox.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-namespace FileUtils {
-
-void delete_path(const String& path, GUI::Window* parent_window)
-{
- struct stat st;
- if (lstat(path.characters(), &st)) {
- GUI::MessageBox::show(parent_window,
- String::formatted("lstat({}) failed: {}", path, strerror(errno)),
- "Delete failed",
- GUI::MessageBox::Type::Error);
- }
-
- if (S_ISDIR(st.st_mode)) {
- String error_path;
- int error = FileUtils::delete_directory(path, error_path);
-
- if (error) {
- GUI::MessageBox::show(parent_window,
- String::formatted("Failed to delete directory \"{}\": {}", error_path, strerror(error)),
- "Delete failed",
- GUI::MessageBox::Type::Error);
- }
- } else if (unlink(path.characters()) < 0) {
- int saved_errno = errno;
- GUI::MessageBox::show(parent_window,
- String::formatted("unlink(\"{}\") failed: {}", path, strerror(saved_errno)),
- "Delete failed",
- GUI::MessageBox::Type::Error);
- }
-}
-
-void delete_paths(const Vector<String>& paths, bool should_confirm, GUI::Window* parent_window)
-{
- String message;
- if (paths.size() == 1) {
- message = String::formatted("Really delete {}?", LexicalPath(paths[0]).basename());
- } else {
- message = String::formatted("Really delete {} files?", paths.size());
- }
-
- if (should_confirm) {
- auto result = GUI::MessageBox::show(parent_window,
- message,
- "Confirm deletion",
- GUI::MessageBox::Type::Warning,
- GUI::MessageBox::InputType::OKCancel);
- if (result == GUI::MessageBox::ExecCancel)
- return;
- }
-
- for (auto& path : paths) {
- delete_path(path, parent_window);
- }
-}
-
-int delete_directory(String directory, String& file_that_caused_error)
-{
- Core::DirIterator iterator(directory, Core::DirIterator::SkipDots);
- if (iterator.has_error()) {
- file_that_caused_error = directory;
- return -1;
- }
-
- while (iterator.has_next()) {
- auto file_to_delete = String::formatted("{}/{}", directory, iterator.next_path());
- struct stat st;
-
- if (lstat(file_to_delete.characters(), &st)) {
- file_that_caused_error = file_to_delete;
- return errno;
- }
-
- if (S_ISDIR(st.st_mode)) {
- if (delete_directory(file_to_delete, file_to_delete)) {
- file_that_caused_error = file_to_delete;
- return errno;
- }
- } else if (unlink(file_to_delete.characters())) {
- file_that_caused_error = file_to_delete;
- return errno;
- }
- }
-
- if (rmdir(directory.characters())) {
- file_that_caused_error = directory;
- return errno;
- }
-
- return 0;
-}
-
-bool copy_file_or_directory(const String& src_path, const String& dst_path)
-{
- int duplicate_count = 0;
- while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) {
- ++duplicate_count;
- }
- if (duplicate_count != 0) {
- return copy_file_or_directory(src_path, get_duplicate_name(dst_path, duplicate_count));
- }
-
- auto source_or_error = Core::File::open(src_path, Core::IODevice::ReadOnly);
- if (source_or_error.is_error())
- return false;
-
- auto& source = *source_or_error.value();
-
- struct stat src_stat;
- int rc = fstat(source.fd(), &src_stat);
- if (rc < 0)
- return false;
-
- if (source.is_directory())
- return copy_directory(src_path, dst_path, src_stat);
-
- return copy_file(dst_path, src_stat, source);
-}
-
-bool copy_directory(const String& src_path, const String& dst_path, const struct stat& src_stat)
-{
- int rc = mkdir(dst_path.characters(), 0755);
- if (rc < 0) {
- return false;
- }
- Core::DirIterator di(src_path, Core::DirIterator::SkipDots);
- if (di.has_error()) {
- return false;
- }
- while (di.has_next()) {
- String filename = di.next_path();
- bool is_copied = copy_file_or_directory(
- String::formatted("{}/{}", src_path, filename),
- String::formatted("{}/{}", dst_path, filename));
- if (!is_copied) {
- return false;
- }
- }
-
- auto my_umask = umask(0);
- umask(my_umask);
- rc = chmod(dst_path.characters(), src_stat.st_mode & ~my_umask);
- if (rc < 0) {
- return false;
- }
- return true;
-}
-
-bool copy_file(const String& dst_path, const struct stat& src_stat, Core::File& source)
-{
- int dst_fd = creat(dst_path.characters(), 0666);
- if (dst_fd < 0) {
- if (errno != EISDIR) {
- return false;
- }
- auto dst_dir_path = String::formatted("{}/{}", dst_path, LexicalPath(source.filename()).basename());
- dst_fd = creat(dst_dir_path.characters(), 0666);
- if (dst_fd < 0) {
- return false;
- }
- }
-
- ScopeGuard close_fd_guard([dst_fd]() { close(dst_fd); });
-
- if (src_stat.st_size > 0) {
- if (ftruncate(dst_fd, src_stat.st_size) < 0) {
- perror("cp: ftruncate");
- return false;
- }
- }
-
- for (;;) {
- char buffer[32768];
- ssize_t nread = read(source.fd(), buffer, sizeof(buffer));
- if (nread < 0) {
- return false;
- }
- if (nread == 0)
- break;
- ssize_t remaining_to_write = nread;
- char* bufptr = buffer;
- while (remaining_to_write) {
- ssize_t nwritten = write(dst_fd, bufptr, remaining_to_write);
- if (nwritten < 0) {
- return false;
- }
- assert(nwritten > 0);
- remaining_to_write -= nwritten;
- bufptr += nwritten;
- }
- }
-
- auto my_umask = umask(0);
- umask(my_umask);
- int rc = fchmod(dst_fd, src_stat.st_mode & ~my_umask);
- if (rc < 0) {
- return false;
- }
-
- return true;
-}
-
-bool link_file(const String& src_path, const String& dst_path)
-{
- int duplicate_count = 0;
- while (access(get_duplicate_name(dst_path, duplicate_count).characters(), F_OK) == 0) {
- ++duplicate_count;
- }
- if (duplicate_count != 0) {
- return link_file(src_path, get_duplicate_name(dst_path, duplicate_count));
- }
- int rc = symlink(src_path.characters(), dst_path.characters());
- if (rc < 0) {
- return false;
- }
-
- return true;
-}
-
-String get_duplicate_name(const String& path, int duplicate_count)
-{
- if (duplicate_count == 0) {
- return path;
- }
- LexicalPath lexical_path(path);
- StringBuilder duplicated_name;
- duplicated_name.append('/');
- for (size_t i = 0; i < lexical_path.parts().size() - 1; ++i) {
- duplicated_name.appendff("{}/", lexical_path.parts()[i]);
- }
- auto prev_duplicate_tag = String::formatted("({})", duplicate_count);
- auto title = lexical_path.title();
- if (title.ends_with(prev_duplicate_tag)) {
- // remove the previous duplicate tag "(n)" so we can add a new tag.
- title = title.substring(0, title.length() - prev_duplicate_tag.length());
- }
- duplicated_name.appendff("{} ({})", lexical_path.title(), duplicate_count);
- if (!lexical_path.extension().is_empty()) {
- duplicated_name.appendff(".{}", lexical_path.extension());
- }
- return duplicated_name.build();
-}
-}
diff --git a/Applications/FileManager/FileUtils.h b/Applications/FileManager/FileUtils.h
deleted file mode 100644
index fcf6b483ac..0000000000
--- a/Applications/FileManager/FileUtils.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <LibCore/Forward.h>
-#include <LibGUI/Forward.h>
-#include <sys/stat.h>
-
-namespace FileUtils {
-
-enum class FileOperation {
- Copy = 0,
- Cut
-};
-
-void delete_path(const String&, GUI::Window*);
-void delete_paths(const Vector<String>&, bool should_confirm, GUI::Window*);
-int delete_directory(String directory, String& file_that_caused_error);
-bool copy_file_or_directory(const String& src_path, const String& dst_path);
-String get_duplicate_name(const String& path, int duplicate_count);
-bool copy_file(const String& dst_path, const struct stat& src_stat, Core::File&);
-bool copy_directory(const String& src_path, const String& dst_path, const struct stat& src_stat);
-bool link_file(const String& src_path, const String& dst_path);
-
-}
diff --git a/Applications/FileManager/PropertiesWindow.cpp b/Applications/FileManager/PropertiesWindow.cpp
deleted file mode 100644
index 8c0ff9f74e..0000000000
--- a/Applications/FileManager/PropertiesWindow.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PropertiesWindow.h"
-#include <AK/LexicalPath.h>
-#include <AK/StringBuilder.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/FileIconProvider.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/LinkLabel.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/SeparatorWidget.h>
-#include <LibGUI/TabWidget.h>
-#include <grp.h>
-#include <limits.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-PropertiesWindow::PropertiesWindow(const String& path, bool disable_rename, Window* parent_window)
- : Window(parent_window)
-{
- auto lexical_path = LexicalPath(path);
- ASSERT(lexical_path.is_valid());
-
- auto& main_widget = set_main_widget<GUI::Widget>();
- main_widget.set_layout<GUI::VerticalBoxLayout>();
- main_widget.layout()->set_margins({ 4, 4, 4, 4 });
- main_widget.set_fill_with_background_color(true);
-
- set_rect({ 0, 0, 360, 420 });
- set_resizable(false);
-
- auto& tab_widget = main_widget.add<GUI::TabWidget>();
-
- auto& general_tab = tab_widget.add_tab<GUI::Widget>("General");
- general_tab.set_layout<GUI::VerticalBoxLayout>();
- general_tab.layout()->set_margins({ 12, 8, 12, 8 });
- general_tab.layout()->set_spacing(10);
-
- auto& file_container = general_tab.add<GUI::Widget>();
- file_container.set_layout<GUI::HorizontalBoxLayout>();
- file_container.layout()->set_spacing(20);
- file_container.set_fixed_height(34);
-
- m_icon = file_container.add<GUI::ImageWidget>();
- m_icon->set_fixed_size(32, 32);
-
- m_name = lexical_path.basename();
- m_path = lexical_path.string();
- m_parent_path = lexical_path.dirname();
-
- m_name_box = file_container.add<GUI::TextBox>();
- m_name_box->set_text(m_name);
- m_name_box->set_mode(disable_rename ? GUI::TextBox::Mode::DisplayOnly : GUI::TextBox::Mode::Editable);
- m_name_box->on_change = [&]() {
- m_name_dirty = m_name != m_name_box->text();
- m_apply_button->set_enabled(m_name_dirty || m_permissions_dirty);
- };
-
- set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/properties.png"));
- general_tab.add<GUI::SeparatorWidget>(Gfx::Orientation::Horizontal);
-
- struct stat st;
- if (lstat(path.characters(), &st)) {
- perror("stat");
- return;
- }
-
- String owner_name;
- String group_name;
-
- if (auto* pw = getpwuid(st.st_uid)) {
- owner_name = pw->pw_name;
- } else {
- owner_name = "n/a";
- }
-
- if (auto* gr = getgrgid(st.st_gid)) {
- group_name = gr->gr_name;
- } else {
- group_name = "n/a";
- }
-
- m_mode = st.st_mode;
- m_old_mode = st.st_mode;
-
- auto properties = Vector<PropertyValuePair>();
- properties.append({ "Type:", get_description(m_mode) });
- auto parent_link = URL::create_with_file_protocol(m_parent_path);
- properties.append(PropertyValuePair { "Location:", path, Optional(parent_link) });
-
- if (S_ISLNK(m_mode)) {
- auto link_destination = Core::File::read_link(path);
- if (link_destination.is_null()) {
- perror("readlink");
- } else {
- auto link_directory = LexicalPath(link_destination);
- ASSERT(link_directory.is_valid());
- auto link_parent = URL::create_with_file_protocol(link_directory.dirname());
- properties.append({ "Link target:", link_destination, Optional(link_parent) });
- }
- }
-
- properties.append({ "Size:", String::formatted("{} bytes", st.st_size) });
- properties.append({ "Owner:", String::formatted("{} ({})", owner_name, st.st_uid) });
- properties.append({ "Group:", String::formatted("{} ({})", group_name, st.st_gid) });
- properties.append({ "Created at:", GUI::FileSystemModel::timestamp_string(st.st_ctime) });
- properties.append({ "Last modified:", GUI::FileSystemModel::timestamp_string(st.st_mtime) });
-
- make_property_value_pairs(properties, general_tab);
-
- general_tab.add<GUI::SeparatorWidget>(Gfx::Orientation::Horizontal);
-
- make_permission_checkboxes(general_tab, { S_IRUSR, S_IWUSR, S_IXUSR }, "Owner:", m_mode);
- make_permission_checkboxes(general_tab, { S_IRGRP, S_IWGRP, S_IXGRP }, "Group:", m_mode);
- make_permission_checkboxes(general_tab, { S_IROTH, S_IWOTH, S_IXOTH }, "Others:", m_mode);
-
- general_tab.layout()->add_spacer();
-
- auto& button_widget = main_widget.add<GUI::Widget>();
- button_widget.set_layout<GUI::HorizontalBoxLayout>();
- button_widget.set_fixed_height(24);
- button_widget.layout()->set_spacing(5);
-
- button_widget.layout()->add_spacer();
-
- make_button("OK", button_widget).on_click = [this](auto) {
- if (apply_changes())
- close();
- };
- make_button("Cancel", button_widget).on_click = [this](auto) {
- close();
- };
-
- m_apply_button = make_button("Apply", button_widget);
- m_apply_button->on_click = [this](auto) { apply_changes(); };
- m_apply_button->set_enabled(false);
-
- update();
-}
-
-PropertiesWindow::~PropertiesWindow()
-{
-}
-
-void PropertiesWindow::update()
-{
- m_icon->set_bitmap(GUI::FileIconProvider::icon_for_path(make_full_path(m_name), m_mode).bitmap_for_size(32));
- set_title(String::formatted("{} - Properties", m_name));
-}
-
-void PropertiesWindow::permission_changed(mode_t mask, bool set)
-{
- if (set) {
- m_mode |= mask;
- } else {
- m_mode &= ~mask;
- }
-
- m_permissions_dirty = m_mode != m_old_mode;
- m_apply_button->set_enabled(m_name_dirty || m_permissions_dirty);
-}
-
-String PropertiesWindow::make_full_path(const String& name)
-{
- return String::formatted("{}/{}", m_parent_path, name);
-}
-
-bool PropertiesWindow::apply_changes()
-{
- if (m_name_dirty) {
- String new_name = m_name_box->text();
- String new_file = make_full_path(new_name).characters();
-
- if (GUI::FilePicker::file_exists(new_file)) {
- GUI::MessageBox::show(this, String::formatted("A file \"{}\" already exists!", new_name), "Error", GUI::MessageBox::Type::Error);
- return false;
- }
-
- if (rename(make_full_path(m_name).characters(), new_file.characters())) {
- GUI::MessageBox::show(this, String::formatted("Could not rename file: {}!", strerror(errno)), "Error", GUI::MessageBox::Type::Error);
- return false;
- }
-
- m_name = new_name;
- m_name_dirty = false;
- update();
- }
-
- if (m_permissions_dirty) {
- if (chmod(make_full_path(m_name).characters(), m_mode)) {
- GUI::MessageBox::show(this, String::formatted("Could not update permissions: {}!", strerror(errno)), "Error", GUI::MessageBox::Type::Error);
- return false;
- }
-
- m_old_mode = m_mode;
- m_permissions_dirty = false;
- }
-
- update();
- m_apply_button->set_enabled(false);
- return true;
-}
-
-void PropertiesWindow::make_permission_checkboxes(GUI::Widget& parent, PermissionMasks masks, String label_string, mode_t mode)
-{
- auto& widget = parent.add<GUI::Widget>();
- widget.set_layout<GUI::HorizontalBoxLayout>();
- widget.set_fixed_height(16);
- widget.layout()->set_spacing(10);
-
- auto& label = widget.add<GUI::Label>(label_string);
- label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- struct stat st;
- if (lstat(m_path.characters(), &st)) {
- perror("stat");
- return;
- }
-
- auto can_edit_checkboxes = st.st_uid == getuid();
-
- auto& box_read = widget.add<GUI::CheckBox>("Read");
- box_read.set_checked(mode & masks.read);
- box_read.on_checked = [&, masks](bool checked) { permission_changed(masks.read, checked); };
- box_read.set_enabled(can_edit_checkboxes);
-
- auto& box_write = widget.add<GUI::CheckBox>("Write");
- box_write.set_checked(mode & masks.write);
- box_write.on_checked = [&, masks](bool checked) { permission_changed(masks.write, checked); };
- box_write.set_enabled(can_edit_checkboxes);
-
- auto& box_execute = widget.add<GUI::CheckBox>("Execute");
- box_execute.set_checked(mode & masks.execute);
- box_execute.on_checked = [&, masks](bool checked) { permission_changed(masks.execute, checked); };
- box_execute.set_enabled(can_edit_checkboxes);
-}
-
-void PropertiesWindow::make_property_value_pairs(const Vector<PropertyValuePair>& pairs, GUI::Widget& parent)
-{
- int max_width = 0;
- Vector<NonnullRefPtr<GUI::Label>> property_labels;
-
- property_labels.ensure_capacity(pairs.size());
- for (auto pair : pairs) {
- auto& label_container = parent.add<GUI::Widget>();
- label_container.set_layout<GUI::HorizontalBoxLayout>();
- label_container.set_fixed_height(14);
- label_container.layout()->set_spacing(12);
-
- auto& label_property = label_container.add<GUI::Label>(pair.property);
- label_property.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- if (!pair.link.has_value()) {
- label_container.add<GUI::Label>(pair.value).set_text_alignment(Gfx::TextAlignment::CenterLeft);
- } else {
- auto& link = label_container.add<GUI::LinkLabel>(pair.value);
- link.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- link.on_click = [pair]() {
- Desktop::Launcher::open(pair.link.value());
- };
- }
-
- max_width = max(max_width, label_property.font().width(pair.property));
- property_labels.append(label_property);
- }
-
- for (auto label : property_labels)
- label->set_fixed_width(max_width);
-}
-
-GUI::Button& PropertiesWindow::make_button(String text, GUI::Widget& parent)
-{
- auto& button = parent.add<GUI::Button>(text);
- button.set_fixed_size(70, 22);
- return button;
-}
diff --git a/Applications/FileManager/PropertiesWindow.h b/Applications/FileManager/PropertiesWindow.h
deleted file mode 100644
index d2801f8049..0000000000
--- a/Applications/FileManager/PropertiesWindow.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibCore/File.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Dialog.h>
-#include <LibGUI/FileSystemModel.h>
-#include <LibGUI/ImageWidget.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/TextBox.h>
-
-class PropertiesWindow final : public GUI::Window {
- C_OBJECT(PropertiesWindow);
-
-public:
- virtual ~PropertiesWindow() override;
-
-private:
- PropertiesWindow(const String& path, bool disable_rename, Window* parent = nullptr);
-
- struct PropertyValuePair {
- String property;
- String value;
- Optional<URL> link = {};
- };
-
- struct PermissionMasks {
- mode_t read;
- mode_t write;
- mode_t execute;
- };
-
- static const String get_description(const mode_t mode)
- {
- if (S_ISREG(mode))
- return "File";
- if (S_ISDIR(mode))
- return "Directory";
- if (S_ISLNK(mode))
- return "Symbolic link";
- if (S_ISCHR(mode))
- return "Character device";
- if (S_ISBLK(mode))
- return "Block device";
- if (S_ISFIFO(mode))
- return "FIFO (named pipe)";
- if (S_ISSOCK(mode))
- return "Socket";
- if (mode & S_IXUSR)
- return "Executable";
-
- return "Unknown";
- }
-
- GUI::Button& make_button(String, GUI::Widget& parent);
- void make_property_value_pairs(const Vector<PropertyValuePair>& pairs, GUI::Widget& parent);
- void make_permission_checkboxes(GUI::Widget& parent, PermissionMasks, String label_string, mode_t mode);
- void permission_changed(mode_t mask, bool set);
- bool apply_changes();
- void update();
- String make_full_path(const String& name);
-
- RefPtr<GUI::Button> m_apply_button;
- RefPtr<GUI::TextBox> m_name_box;
- RefPtr<GUI::ImageWidget> m_icon;
- String m_name;
- String m_parent_path;
- String m_path;
- mode_t m_mode { 0 };
- mode_t m_old_mode { 0 };
- bool m_permissions_dirty { false };
- bool m_name_dirty { false };
-};
diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp
deleted file mode 100644
index 9766876f21..0000000000
--- a/Applications/FileManager/main.cpp
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DesktopWidget.h"
-#include "DirectoryView.h"
-#include "FileUtils.h"
-#include "PropertiesWindow.h"
-#include <AK/LexicalPath.h>
-#include <AK/StringBuilder.h>
-#include <AK/URL.h>
-#include <Applications/FileManager/FileManagerWindowGML.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/MimeData.h>
-#include <LibCore/StandardPaths.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/BreadcrumbBar.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/FileIconProvider.h>
-#include <LibGUI/FileSystemModel.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/ProgressBar.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/StatusBar.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/TreeView.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Palette.h>
-#include <pthread.h>
-#include <serenity.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-using namespace FileManager;
-
-static int run_in_desktop_mode(RefPtr<Core::ConfigFile>);
-static int run_in_windowed_mode(RefPtr<Core::ConfigFile>, String initial_location);
-static void do_copy(const Vector<String>& selected_file_paths, FileUtils::FileOperation file_operation);
-static void do_paste(const String& target_directory, GUI::Window* window);
-static void do_create_link(const Vector<String>& selected_file_paths, GUI::Window* window);
-static void show_properties(const String& container_dir_path, const String& path, const Vector<String>& selected, GUI::Window* window);
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio thread shared_buffer accept unix cpath rpath wpath fattr proc exec sigaction", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_flags = SA_NOCLDWAIT;
- act.sa_handler = SIG_IGN;
- int rc = sigaction(SIGCHLD, &act, nullptr);
- if (rc < 0) {
- perror("sigaction");
- return 1;
- }
-
- RefPtr<Core::ConfigFile> config = Core::ConfigFile::get_for_app("FileManager");
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread shared_buffer accept cpath rpath wpath fattr proc exec unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (app->args().contains_slow("--desktop") || app->args().contains_slow("-d"))
- return run_in_desktop_mode(move(config));
-
- // our initial location is defined as, in order of precedence:
- // 1. the first command-line argument (e.g. FileManager /bin)
- // 2. the user's home directory
- // 3. the root directory
- String initial_location;
-
- if (argc >= 2) {
- char* buffer = realpath(argv[1], nullptr);
- initial_location = buffer;
- free(buffer);
- }
-
- if (initial_location.is_empty())
- initial_location = Core::StandardPaths::home_directory();
-
- if (initial_location.is_empty())
- initial_location = "/";
-
- return run_in_windowed_mode(move(config), initial_location);
-}
-
-void do_copy(const Vector<String>& selected_file_paths, FileUtils::FileOperation file_operation)
-{
- if (selected_file_paths.is_empty())
- ASSERT_NOT_REACHED();
-
- StringBuilder copy_text;
- if (file_operation == FileUtils::FileOperation::Cut) {
- copy_text.append("#cut\n"); // This exploits the comment lines in the text/uri-list specification, which might be a bit hackish
- }
- for (auto& path : selected_file_paths) {
- auto url = URL::create_with_file_protocol(path);
- copy_text.appendff("{}\n", url);
- }
- GUI::Clipboard::the().set_data(copy_text.build().bytes(), "text/uri-list");
-}
-
-void do_paste(const String& target_directory, GUI::Window* window)
-{
- auto data_and_type = GUI::Clipboard::the().data_and_type();
- if (data_and_type.mime_type != "text/uri-list") {
- dbgln("Cannot paste clipboard type {}", data_and_type.mime_type);
- return;
- }
- auto copied_lines = String::copy(data_and_type.data).split('\n');
- if (copied_lines.is_empty()) {
- dbgln("No files to paste");
- return;
- }
-
- bool should_delete_src = false;
- if (copied_lines[0] == "#cut") { // cut operation encoded as a text/uri-list commen
- should_delete_src = true;
- copied_lines.remove(0);
- }
-
- for (auto& uri_as_string : copied_lines) {
- if (uri_as_string.is_empty())
- continue;
- URL url = uri_as_string;
- if (!url.is_valid() || url.protocol() != "file") {
- dbgln("Cannot paste URI {}", uri_as_string);
- continue;
- }
-
- auto new_path = String::formatted("{}/{}", target_directory, url.basename());
- if (!FileUtils::copy_file_or_directory(url.path(), new_path)) {
- auto error_message = String::formatted("Could not paste {}.", url.path());
- GUI::MessageBox::show(window, error_message, "File Manager", GUI::MessageBox::Type::Error);
- } else if (should_delete_src) {
- FileUtils::delete_path(url.path(), window);
- }
- }
-}
-
-void do_create_link(const Vector<String>& selected_file_paths, GUI::Window* window)
-{
- auto path = selected_file_paths.first();
- auto destination = String::formatted("{}/{}", Core::StandardPaths::desktop_directory(), LexicalPath { path }.basename());
- if (!FileUtils::link_file(path, destination)) {
- GUI::MessageBox::show(window, "Could not create desktop shortcut", "File Manager",
- GUI::MessageBox::Type::Error);
- }
-}
-
-void show_properties(const String& container_dir_path, const String& path, const Vector<String>& selected, GUI::Window* window)
-{
- RefPtr<PropertiesWindow> properties;
- if (selected.is_empty()) {
- properties = window->add<PropertiesWindow>(path, true);
- } else {
- properties = window->add<PropertiesWindow>(selected.first(), access(container_dir_path.characters(), W_OK) != 0);
- }
- properties->on_close = [properties = properties.ptr()] {
- properties->remove_from_parent();
- };
- properties->center_on_screen();
- properties->show();
-}
-
-int run_in_desktop_mode([[maybe_unused]] RefPtr<Core::ConfigFile> config)
-{
- static constexpr const char* process_name = "FileManager (Desktop)";
- set_process_name(process_name, strlen(process_name));
- pthread_setname_np(pthread_self(), process_name);
-
- auto window = GUI::Window::construct();
- window->set_title("Desktop Manager");
- window->set_window_type(GUI::WindowType::Desktop);
- window->set_has_alpha_channel(true);
-
- auto& desktop_widget = window->set_main_widget<FileManager::DesktopWidget>();
- desktop_widget.set_layout<GUI::VerticalBoxLayout>();
-
- [[maybe_unused]] auto& directory_view = desktop_widget.add<DirectoryView>(DirectoryView::Mode::Desktop);
-
- auto copy_action = GUI::CommonActions::make_copy_action(
- [&](auto&) {
- auto paths = directory_view.selected_file_paths();
-
- if (paths.is_empty())
- ASSERT_NOT_REACHED();
-
- do_copy(paths, FileUtils::FileOperation::Copy);
- },
- window);
- copy_action->set_enabled(false);
-
- auto cut_action = GUI::CommonActions::make_cut_action(
- [&](auto&) {
- auto paths = directory_view.selected_file_paths();
-
- if (paths.is_empty())
- ASSERT_NOT_REACHED();
-
- do_copy(paths, FileUtils::FileOperation::Cut);
- },
- window);
- cut_action->set_enabled(false);
-
- directory_view.on_selection_change = [&](const GUI::AbstractView& view) {
- copy_action->set_enabled(!view.selection().is_empty());
- cut_action->set_enabled(!view.selection().is_empty());
- };
-
- auto properties_action
- = GUI::Action::create(
- "Properties", { Mod_Alt, Key_Return }, Gfx::Bitmap::load_from_file("/res/icons/16x16/properties.png"), [&](const GUI::Action&) {
- String path = directory_view.path();
- Vector<String> selected = directory_view.selected_file_paths();
-
- show_properties(path, path, selected, directory_view.window());
- },
- window);
-
- auto paste_action = GUI::CommonActions::make_paste_action(
- [&](const GUI::Action&) {
- do_paste(directory_view.path(), directory_view.window());
- },
- window);
- paste_action->set_enabled(GUI::Clipboard::the().mime_type() == "text/uri-list" && access(directory_view.path().characters(), W_OK) == 0);
-
- GUI::Clipboard::the().on_change = [&](const String& data_type) {
- paste_action->set_enabled(data_type == "text/uri-list" && access(directory_view.path().characters(), W_OK) == 0);
- };
-
- auto desktop_view_context_menu = GUI::Menu::construct("Directory View");
-
- auto file_manager_action = GUI::Action::create("Show in File Manager", {}, Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-folder.png"), [&](const GUI::Action&) {
- Desktop::Launcher::open(URL::create_with_file_protocol(directory_view.path()));
- });
-
- auto display_properties_action = GUI::Action::create("Display Settings", {}, Gfx::Bitmap::load_from_file("/res/icons/16x16/app-display-settings.png"), [&](const GUI::Action&) {
- Desktop::Launcher::open(URL::create_with_file_protocol("/bin/DisplaySettings"));
- });
-
- desktop_view_context_menu->add_action(directory_view.mkdir_action());
- desktop_view_context_menu->add_action(directory_view.touch_action());
- desktop_view_context_menu->add_action(paste_action);
- desktop_view_context_menu->add_separator();
- desktop_view_context_menu->add_action(file_manager_action);
- desktop_view_context_menu->add_action(directory_view.open_terminal_action());
- desktop_view_context_menu->add_separator();
- desktop_view_context_menu->add_action(display_properties_action);
-
- auto desktop_context_menu = GUI::Menu::construct("Directory View Directory");
- desktop_context_menu->add_action(copy_action);
- desktop_context_menu->add_action(cut_action);
- desktop_context_menu->add_action(paste_action);
- desktop_context_menu->add_action(directory_view.delete_action());
- desktop_context_menu->add_separator();
- desktop_context_menu->add_action(properties_action);
-
- directory_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
- if (!index.is_valid())
- desktop_view_context_menu->popup(event.screen_position());
- else
- desktop_context_menu->popup(event.screen_position());
- };
-
- auto wm_config = Core::ConfigFile::get_for_app("WindowManager");
- auto selected_wallpaper = wm_config->read_entry("Background", "Wallpaper", "");
- if (!selected_wallpaper.is_empty()) {
- GUI::Desktop::the().set_wallpaper(selected_wallpaper, false);
- }
-
- window->show();
- return GUI::Application::the()->exec();
-}
-
-int run_in_windowed_mode(RefPtr<Core::ConfigFile> config, String initial_location)
-{
- auto window = GUI::Window::construct();
- window->set_title("File Manager");
-
- auto left = config->read_num_entry("Window", "Left", 150);
- auto top = config->read_num_entry("Window", "Top", 75);
- auto width = config->read_num_entry("Window", "Width", 640);
- auto height = config->read_num_entry("Window", "Height", 480);
- window->set_rect({ left, top, width, height });
-
- auto& widget = window->set_main_widget<GUI::Widget>();
-
- widget.load_from_gml(file_manager_window_gml);
-
- auto& main_toolbar = *widget.find_descendant_of_type_named<GUI::ToolBar>("main_toolbar");
- auto& location_toolbar = *widget.find_descendant_of_type_named<GUI::ToolBar>("location_toolbar");
- location_toolbar.layout()->set_margins({ 6, 3, 6, 3 });
-
- auto& location_textbox = *widget.find_descendant_of_type_named<GUI::TextBox>("location_textbox");
-
- auto& breadcrumb_toolbar = *widget.find_descendant_of_type_named<GUI::ToolBar>("breadcrumb_toolbar");
- breadcrumb_toolbar.layout()->set_margins({});
- auto& breadcrumb_bar = *widget.find_descendant_of_type_named<GUI::BreadcrumbBar>("breadcrumb_bar");
-
- location_textbox.on_focusout = [&] {
- location_toolbar.set_visible(false);
- breadcrumb_toolbar.set_visible(true);
- };
-
- auto& splitter = *widget.find_descendant_of_type_named<GUI::HorizontalSplitter>("splitter");
- auto& tree_view = *widget.find_descendant_of_type_named<GUI::TreeView>("tree_view");
-
- auto directories_model = GUI::FileSystemModel::create({}, GUI::FileSystemModel::Mode::DirectoriesOnly);
- tree_view.set_model(directories_model);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Icon, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Size, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Owner, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Group, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Permissions, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::ModificationTime, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::Inode, true);
- tree_view.set_column_hidden(GUI::FileSystemModel::Column::SymlinkTarget, true);
- bool is_reacting_to_tree_view_selection_change = false;
-
- auto& directory_view = splitter.add<DirectoryView>(DirectoryView::Mode::Normal);
-
- location_textbox.on_escape_pressed = [&] {
- directory_view.set_focus(true);
- };
-
- // Open the root directory. FIXME: This is awkward.
- tree_view.toggle_index(directories_model->index(0, 0, {}));
-
- auto& statusbar = *widget.find_descendant_of_type_named<GUI::StatusBar>("statusbar");
-
- auto& progressbar = *widget.find_descendant_of_type_named<GUI::ProgressBar>("progressbar");
- progressbar.set_format(GUI::ProgressBar::Format::ValueSlashMax);
- progressbar.set_frame_shape(Gfx::FrameShape::Panel);
- progressbar.set_frame_shadow(Gfx::FrameShadow::Sunken);
- progressbar.set_frame_thickness(1);
-
- location_textbox.on_return_pressed = [&] {
- directory_view.open(location_textbox.text());
- };
-
- auto refresh_tree_view = [&] {
- directories_model->update();
-
- auto current_path = directory_view.path();
-
- struct stat st;
- // If the directory no longer exists, we find a parent that does.
- while (stat(current_path.characters(), &st) != 0) {
- directory_view.open_parent_directory();
- current_path = directory_view.path();
- if (current_path == directories_model->root_path()) {
- break;
- }
- }
-
- // Reselect the existing folder in the tree.
- auto new_index = directories_model->index(current_path, GUI::FileSystemModel::Column::Name);
- if (new_index.is_valid()) {
- tree_view.expand_all_parents_of(new_index);
- tree_view.set_cursor(new_index, GUI::AbstractView::SelectionUpdate::Set, true);
- }
-
- directory_view.refresh();
- };
-
- auto directory_context_menu = GUI::Menu::construct("Directory View Directory");
- auto directory_view_context_menu = GUI::Menu::construct("Directory View");
- auto tree_view_directory_context_menu = GUI::Menu::construct("Tree View Directory");
- auto tree_view_context_menu = GUI::Menu::construct("Tree View");
-
- auto open_parent_directory_action = GUI::Action::create("Open parent directory", { Mod_Alt, Key_Up }, Gfx::Bitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"), [&](const GUI::Action&) {
- directory_view.open_parent_directory();
- });
-
- RefPtr<GUI::Action> view_as_table_action;
- RefPtr<GUI::Action> view_as_icons_action;
- RefPtr<GUI::Action> view_as_columns_action;
-
- view_as_icons_action = GUI::Action::create_checkable(
- "Icon view", { Mod_Ctrl, KeyCode::Key_1 }, Gfx::Bitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&](const GUI::Action&) {
- directory_view.set_view_mode(DirectoryView::ViewMode::Icon);
- config->write_entry("DirectoryView", "ViewMode", "Icon");
- config->sync();
- },
- window);
-
- view_as_table_action = GUI::Action::create_checkable(
- "Table view", { Mod_Ctrl, KeyCode::Key_2 }, Gfx::Bitmap::load_from_file("/res/icons/16x16/table-view.png"), [&](const GUI::Action&) {
- directory_view.set_view_mode(DirectoryView::ViewMode::Table);
- config->write_entry("DirectoryView", "ViewMode", "Table");
- config->sync();
- },
- window);
-
- view_as_columns_action = GUI::Action::create_checkable(
- "Columns view", { Mod_Ctrl, KeyCode::Key_3 }, Gfx::Bitmap::load_from_file("/res/icons/16x16/columns-view.png"), [&](const GUI::Action&) {
- directory_view.set_view_mode(DirectoryView::ViewMode::Columns);
- config->write_entry("DirectoryView", "ViewMode", "Columns");
- config->sync();
- },
- window);
-
- auto view_type_action_group = make<GUI::ActionGroup>();
- view_type_action_group->set_exclusive(true);
- view_type_action_group->add_action(*view_as_icons_action);
- view_type_action_group->add_action(*view_as_table_action);
- view_type_action_group->add_action(*view_as_columns_action);
-
- auto tree_view_selected_file_paths = [&] {
- Vector<String> paths;
- auto& view = tree_view;
- view.selection().for_each_index([&](const GUI::ModelIndex& index) {
- paths.append(directories_model->full_path(index));
- });
- return paths;
- };
-
- auto select_all_action = GUI::Action::create("Select all", { Mod_Ctrl, KeyCode::Key_A }, [&](const GUI::Action&) {
- directory_view.current_view().select_all();
- });
-
- auto copy_action = GUI::CommonActions::make_copy_action(
- [&](auto&) {
- auto paths = directory_view.selected_file_paths();
-
- if (paths.is_empty())
- paths = tree_view_selected_file_paths();
-
- if (paths.is_empty())
- ASSERT_NOT_REACHED();
-
- do_copy(paths, FileUtils::FileOperation::Copy);
- refresh_tree_view();
- },
- window);
- copy_action->set_enabled(false);
-
- auto cut_action = GUI::CommonActions::make_cut_action(
- [&](auto&) {
- auto paths = directory_view.selected_file_paths();
-
- if (paths.is_empty())
- paths = tree_view_selected_file_paths();
-
- if (paths.is_empty())
- ASSERT_NOT_REACHED();
-
- do_copy(paths, FileUtils::FileOperation::Cut);
- refresh_tree_view();
- },
- window);
- cut_action->set_enabled(false);
-
- auto shortcut_action
- = GUI::Action::create(
- "Create desktop shortcut",
- {},
- Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-symlink.png"),
- [&](const GUI::Action&) {
- auto paths = directory_view.selected_file_paths();
- if (paths.is_empty()) {
- return;
- }
- do_create_link(paths, directory_view.window());
- },
- window);
-
- auto properties_action
- = GUI::Action::create(
- "Properties", { Mod_Alt, Key_Return }, Gfx::Bitmap::load_from_file("/res/icons/16x16/properties.png"), [&](const GUI::Action& action) {
- String container_dir_path;
- String path;
- Vector<String> selected;
- if (action.activator() == directory_context_menu || directory_view.active_widget()->is_focused()) {
- path = directory_view.path();
- container_dir_path = path;
- selected = directory_view.selected_file_paths();
- } else {
- path = directories_model->full_path(tree_view.selection().first());
- container_dir_path = LexicalPath(path).basename();
- selected = tree_view_selected_file_paths();
- }
-
- show_properties(container_dir_path, path, selected, directory_view.window());
- },
- window);
-
- auto paste_action = GUI::CommonActions::make_paste_action(
- [&](const GUI::Action& action) {
- String target_directory;
- if (action.activator() == directory_context_menu)
- target_directory = directory_view.selected_file_paths()[0];
- else
- target_directory = directory_view.path();
- do_paste(target_directory, directory_view.window());
- refresh_tree_view();
- },
- window);
-
- auto folder_specific_paste_action = GUI::CommonActions::make_paste_action(
- [&](const GUI::Action& action) {
- String target_directory;
- if (action.activator() == directory_context_menu)
- target_directory = directory_view.selected_file_paths()[0];
- else
- target_directory = directory_view.path();
- do_paste(target_directory, directory_view.window());
- refresh_tree_view();
- },
- window);
-
- auto go_back_action = GUI::CommonActions::make_go_back_action(
- [&](auto&) {
- directory_view.open_previous_directory();
- },
- window);
-
- auto go_forward_action = GUI::CommonActions::make_go_forward_action(
- [&](auto&) {
- directory_view.open_next_directory();
- },
- window);
-
- auto go_home_action = GUI::CommonActions::make_go_home_action(
- [&](auto&) {
- directory_view.open(Core::StandardPaths::home_directory());
- },
- window);
-
- GUI::Clipboard::the().on_change = [&](const String& data_type) {
- auto current_location = directory_view.path();
- paste_action->set_enabled(data_type == "text/uri-list" && access(current_location.characters(), W_OK) == 0);
- };
-
- auto tree_view_delete_action = GUI::CommonActions::make_delete_action(
- [&](auto&) {
- FileUtils::delete_paths(tree_view_selected_file_paths(), true, window);
- refresh_tree_view();
- },
- &tree_view);
-
- // This is a little awkward. The menu action does something different depending on which view has focus.
- // It would be nice to find a good abstraction for this instead of creating a branching action like this.
- auto focus_dependent_delete_action = GUI::CommonActions::make_delete_action([&](auto&) {
- if (tree_view.is_focused())
- tree_view_delete_action->activate();
- else
- directory_view.delete_action().activate();
- refresh_tree_view();
- });
- focus_dependent_delete_action->set_enabled(false);
-
- auto mkdir_action = GUI::Action::create("New directory...", { Mod_Ctrl | Mod_Shift, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/mkdir.png"), [&](const GUI::Action&) {
- directory_view.mkdir_action().activate();
- refresh_tree_view();
- });
-
- auto touch_action = GUI::Action::create("New file...", { Mod_Ctrl | Mod_Shift, Key_F }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new.png"), [&](const GUI::Action&) {
- directory_view.touch_action().activate();
- refresh_tree_view();
- });
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("File Manager");
- app_menu.add_action(mkdir_action);
- app_menu.add_action(touch_action);
- app_menu.add_action(copy_action);
- app_menu.add_action(cut_action);
- app_menu.add_action(paste_action);
- app_menu.add_action(focus_dependent_delete_action);
- app_menu.add_action(directory_view.open_terminal_action());
- app_menu.add_separator();
- app_menu.add_action(properties_action);
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- }));
-
- auto action_show_dotfiles = GUI::Action::create_checkable("Show dotfiles", { Mod_Ctrl, Key_H }, [&](auto& action) {
- directory_view.set_should_show_dotfiles(action.is_checked());
- refresh_tree_view();
- });
-
- auto& view_menu = menubar->add_menu("View");
- view_menu.add_action(*view_as_icons_action);
- view_menu.add_action(*view_as_table_action);
- view_menu.add_action(*view_as_columns_action);
- view_menu.add_separator();
- view_menu.add_action(action_show_dotfiles);
-
- auto go_to_location_action = GUI::Action::create("Go to location...", { Mod_Ctrl, Key_L }, [&](auto&) {
- location_toolbar.set_visible(true);
- breadcrumb_toolbar.set_visible(false);
- location_textbox.select_all();
- location_textbox.set_focus(true);
- });
-
- auto& go_menu = menubar->add_menu("Go");
- go_menu.add_action(go_back_action);
- go_menu.add_action(go_forward_action);
- go_menu.add_action(open_parent_directory_action);
- go_menu.add_action(go_home_action);
- go_menu.add_action(go_to_location_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("File Manager", GUI::Icon::default_icon("filetype-folder")));
-
- GUI::Application::the()->set_menubar(move(menubar));
-
- main_toolbar.add_action(go_back_action);
- main_toolbar.add_action(go_forward_action);
- main_toolbar.add_action(open_parent_directory_action);
- main_toolbar.add_action(go_home_action);
-
- main_toolbar.add_separator();
- main_toolbar.add_action(mkdir_action);
- main_toolbar.add_action(touch_action);
- main_toolbar.add_action(copy_action);
- main_toolbar.add_action(cut_action);
- main_toolbar.add_action(paste_action);
- main_toolbar.add_action(focus_dependent_delete_action);
- main_toolbar.add_action(directory_view.open_terminal_action());
-
- main_toolbar.add_separator();
- main_toolbar.add_action(*view_as_icons_action);
- main_toolbar.add_action(*view_as_table_action);
- main_toolbar.add_action(*view_as_columns_action);
-
- directory_view.on_path_change = [&](const String& new_path, bool can_write_in_path) {
- auto icon = GUI::FileIconProvider::icon_for_path(new_path);
- auto* bitmap = icon.bitmap_for_size(16);
- window->set_icon(bitmap);
- location_textbox.set_icon(bitmap);
-
- window->set_title(String::formatted("{} - File Manager", new_path));
- location_textbox.set_text(new_path);
-
- {
- LexicalPath lexical_path(new_path);
-
- auto segment_index_of_new_path_in_breadcrumb_bar = [&]() -> Optional<size_t> {
- for (size_t i = 0; i < breadcrumb_bar.segment_count(); ++i) {
- if (breadcrumb_bar.segment_data(i) == new_path)
- return i;
- }
- return {};
- }();
-
- if (segment_index_of_new_path_in_breadcrumb_bar.has_value()) {
- breadcrumb_bar.set_selected_segment(segment_index_of_new_path_in_breadcrumb_bar.value());
- } else {
- breadcrumb_bar.clear_segments();
-
- breadcrumb_bar.append_segment("/", GUI::FileIconProvider::icon_for_path("/").bitmap_for_size(16), "/");
- StringBuilder builder;
-
- for (auto& part : lexical_path.parts()) {
- // NOTE: We rebuild the path as we go, so we have something to pass to GUI::FileIconProvider.
- builder.append('/');
- builder.append(part);
-
- breadcrumb_bar.append_segment(part, GUI::FileIconProvider::icon_for_path(builder.string_view()).bitmap_for_size(16), builder.string_view());
- }
-
- breadcrumb_bar.set_selected_segment(breadcrumb_bar.segment_count() - 1);
-
- breadcrumb_bar.on_segment_click = [&](size_t segment_index) {
- directory_view.open(breadcrumb_bar.segment_data(segment_index));
- };
- }
- }
-
- if (!is_reacting_to_tree_view_selection_change) {
- auto new_index = directories_model->index(new_path, GUI::FileSystemModel::Column::Name);
- if (new_index.is_valid()) {
- tree_view.expand_all_parents_of(new_index);
- tree_view.set_cursor(new_index, GUI::AbstractView::SelectionUpdate::Set);
- }
- }
-
- struct stat st;
- if (lstat(new_path.characters(), &st)) {
- perror("stat");
- return;
- }
-
- paste_action->set_enabled(can_write_in_path && GUI::Clipboard::the().mime_type() == "text/uri-list");
- go_forward_action->set_enabled(directory_view.path_history_position() < directory_view.path_history_size() - 1);
- go_back_action->set_enabled(directory_view.path_history_position() > 0);
- open_parent_directory_action->set_enabled(new_path != "/");
- };
-
- directory_view.on_accepted_drop = [&]() {
- refresh_tree_view();
- };
-
- directory_view.on_status_message = [&](const StringView& message) {
- statusbar.set_text(message);
- };
-
- directory_view.on_thumbnail_progress = [&](int done, int total) {
- if (done == total) {
- progressbar.set_visible(false);
- return;
- }
- progressbar.set_range(0, total);
- progressbar.set_value(done);
- progressbar.set_visible(true);
- };
-
- directory_view.on_selection_change = [&](GUI::AbstractView& view) {
- auto& selection = view.selection();
- copy_action->set_enabled(!selection.is_empty());
- cut_action->set_enabled(!selection.is_empty());
- focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && tree_view.is_focused())
- || !directory_view.current_view().selection().is_empty());
- };
-
- directory_context_menu->add_action(copy_action);
- directory_context_menu->add_action(cut_action);
- directory_context_menu->add_action(folder_specific_paste_action);
- directory_context_menu->add_action(directory_view.delete_action());
- directory_context_menu->add_action(shortcut_action);
- directory_context_menu->add_separator();
- directory_context_menu->add_action(properties_action);
-
- directory_view_context_menu->add_action(mkdir_action);
- directory_view_context_menu->add_action(touch_action);
- directory_view_context_menu->add_action(paste_action);
- directory_view_context_menu->add_action(directory_view.open_terminal_action());
- directory_view_context_menu->add_separator();
- directory_view_context_menu->add_action(action_show_dotfiles);
- directory_view_context_menu->add_separator();
- directory_view_context_menu->add_action(properties_action);
-
- tree_view_directory_context_menu->add_action(copy_action);
- tree_view_directory_context_menu->add_action(cut_action);
- tree_view_directory_context_menu->add_action(paste_action);
- tree_view_directory_context_menu->add_action(tree_view_delete_action);
- tree_view_directory_context_menu->add_separator();
- tree_view_directory_context_menu->add_action(properties_action);
- tree_view_directory_context_menu->add_separator();
- tree_view_directory_context_menu->add_action(mkdir_action);
- tree_view_directory_context_menu->add_action(touch_action);
-
- RefPtr<GUI::Menu> file_context_menu;
- NonnullRefPtrVector<LauncherHandler> current_file_handlers;
- RefPtr<GUI::Action> file_context_menu_action_default_action;
-
- directory_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
- if (index.is_valid()) {
- auto& node = directory_view.node(index);
-
- if (node.is_directory()) {
- auto should_get_enabled = access(node.full_path().characters(), W_OK) == 0 && GUI::Clipboard::the().mime_type() == "text/uri-list";
- folder_specific_paste_action->set_enabled(should_get_enabled);
- directory_context_menu->popup(event.screen_position());
- } else {
- auto full_path = node.full_path();
- current_file_handlers = directory_view.get_launch_handlers(full_path);
-
- file_context_menu = GUI::Menu::construct("Directory View File");
- file_context_menu->add_action(copy_action);
- file_context_menu->add_action(cut_action);
- file_context_menu->add_action(paste_action);
- file_context_menu->add_action(directory_view.delete_action());
- file_context_menu->add_action(shortcut_action);
-
- file_context_menu->add_separator();
- bool added_open_menu_items = false;
- auto default_file_handler = directory_view.get_default_launch_handler(current_file_handlers);
- if (default_file_handler) {
- auto file_open_action = default_file_handler->create_launch_action([&, full_path = move(full_path)](auto& launcher_handler) {
- directory_view.launch(URL::create_with_file_protocol(full_path), launcher_handler);
- });
- if (default_file_handler->details().launcher_type == Desktop::Launcher::LauncherType::Application)
- file_open_action->set_text(String::formatted("Run {}", file_open_action->text()));
- else
- file_open_action->set_text(String::formatted("Open in {}", file_open_action->text()));
-
- file_context_menu_action_default_action = file_open_action;
-
- file_context_menu->add_action(move(file_open_action));
- added_open_menu_items = true;
- } else {
- file_context_menu_action_default_action.clear();
- }
-
- if (current_file_handlers.size() > 1) {
- added_open_menu_items = true;
- auto& file_open_with_menu = file_context_menu->add_submenu("Open with");
- for (auto& handler : current_file_handlers) {
- if (&handler == default_file_handler.ptr())
- continue;
- file_open_with_menu.add_action(handler.create_launch_action([&, full_path = move(full_path)](auto& launcher_handler) {
- directory_view.launch(URL::create_with_file_protocol(full_path), launcher_handler);
- }));
- }
- }
-
- if (added_open_menu_items)
- file_context_menu->add_separator();
-
- file_context_menu->add_action(properties_action);
- file_context_menu->popup(event.screen_position(), file_context_menu_action_default_action);
- }
- } else {
- directory_view_context_menu->popup(event.screen_position());
- }
- };
-
- tree_view.on_selection = [&](const GUI::ModelIndex& index) {
- if (directories_model->m_previously_selected_index.is_valid())
- directories_model->update_node_on_selection(directories_model->m_previously_selected_index, false);
-
- directories_model->update_node_on_selection(index, true);
- directories_model->m_previously_selected_index = index;
- };
-
- tree_view.on_selection_change = [&] {
- focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && tree_view.is_focused())
- || !directory_view.current_view().selection().is_empty());
-
- if (tree_view.selection().is_empty())
- return;
- auto path = directories_model->full_path(tree_view.selection().first());
- if (directory_view.path() == path)
- return;
- TemporaryChange change(is_reacting_to_tree_view_selection_change, true);
- directory_view.open(path);
- copy_action->set_enabled(!tree_view.selection().is_empty());
- cut_action->set_enabled(!tree_view.selection().is_empty());
- directory_view.delete_action().set_enabled(!tree_view.selection().is_empty());
- };
-
- tree_view.on_focus_change = [&]([[maybe_unused]] const bool has_focus, [[maybe_unused]] const GUI::FocusSource source) {
- focus_dependent_delete_action->set_enabled((!tree_view.selection().is_empty() && has_focus)
- || !directory_view.current_view().selection().is_empty());
- };
-
- tree_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
- if (index.is_valid()) {
- tree_view_directory_context_menu->popup(event.screen_position());
- }
- };
-
- auto copy_urls_to_directory = [&](const Vector<URL>& urls, const String& directory) {
- if (urls.is_empty()) {
- dbgln("No files to copy");
- return;
- }
- bool had_accepted_copy = false;
- for (auto& url_to_copy : urls) {
- if (!url_to_copy.is_valid() || url_to_copy.path() == directory)
- continue;
- auto new_path = String::formatted("{}/{}", directory, LexicalPath(url_to_copy.path()).basename());
- if (url_to_copy.path() == new_path)
- continue;
-
- if (!FileUtils::copy_file_or_directory(url_to_copy.path(), new_path)) {
- auto error_message = String::formatted("Could not copy {} into {}.", url_to_copy.to_string(), new_path);
- GUI::MessageBox::show(window, error_message, "File Manager", GUI::MessageBox::Type::Error);
- } else {
- had_accepted_copy = true;
- }
- }
- if (had_accepted_copy)
- refresh_tree_view();
- };
-
- breadcrumb_bar.on_segment_drop = [&](size_t segment_index, const GUI::DropEvent& event) {
- if (!event.mime_data().has_urls())
- return;
- copy_urls_to_directory(event.mime_data().urls(), breadcrumb_bar.segment_data(segment_index));
- };
-
- breadcrumb_bar.on_segment_drag_enter = [&](size_t, GUI::DragEvent& event) {
- if (event.mime_types().contains_slow("text/uri-list"))
- event.accept();
- };
-
- breadcrumb_bar.on_doubleclick = [&](const GUI::MouseEvent&) {
- go_to_location_action->activate();
- };
-
- tree_view.on_drop = [&](const GUI::ModelIndex& index, const GUI::DropEvent& event) {
- if (!event.mime_data().has_urls())
- return;
- auto& target_node = directories_model->node(index);
- if (!target_node.is_directory())
- return;
- copy_urls_to_directory(event.mime_data().urls(), target_node.full_path());
- };
-
- directory_view.open(initial_location);
- directory_view.set_focus(true);
-
- paste_action->set_enabled(GUI::Clipboard::the().mime_type() == "text/uri-list" && access(initial_location.characters(), W_OK) == 0);
-
- window->show();
-
- // Read directory read mode from config.
- auto dir_view_mode = config->read_entry("DirectoryView", "ViewMode", "Icon");
-
- if (dir_view_mode.contains("Table")) {
- directory_view.set_view_mode(DirectoryView::ViewMode::Table);
- view_as_table_action->set_checked(true);
- } else if (dir_view_mode.contains("Columns")) {
- directory_view.set_view_mode(DirectoryView::ViewMode::Columns);
- view_as_columns_action->set_checked(true);
- } else {
- directory_view.set_view_mode(DirectoryView::ViewMode::Icon);
- view_as_icons_action->set_checked(true);
- }
-
- // Write window position to config file on close request.
- window->on_close_request = [&] {
- config->write_num_entry("Window", "Left", window->x());
- config->write_num_entry("Window", "Top", window->y());
- config->write_num_entry("Window", "Width", window->width());
- config->write_num_entry("Window", "Height", window->height());
- config->sync();
-
- return GUI::Window::CloseRequestDecision::Close;
- };
-
- return GUI::Application::the()->exec();
-}
diff --git a/Applications/FontEditor/.gitignore b/Applications/FontEditor/.gitignore
deleted file mode 100644
index 0e7af5b54f..0000000000
--- a/Applications/FontEditor/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-UI_*.h
diff --git a/Applications/FontEditor/CMakeLists.txt b/Applications/FontEditor/CMakeLists.txt
deleted file mode 100644
index 569ab9a9bd..0000000000
--- a/Applications/FontEditor/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-set(SOURCES
- FontEditor.cpp
- GlyphEditorWidget.cpp
- GlyphMapWidget.cpp
- main.cpp
-)
-
-serenity_app(FontEditor ICON app-font-editor)
-target_link_libraries(FontEditor LibGUI LibDesktop LibGfx)
diff --git a/Applications/FontEditor/FontEditor.cpp b/Applications/FontEditor/FontEditor.cpp
deleted file mode 100644
index 56cbf3e06b..0000000000
--- a/Applications/FontEditor/FontEditor.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "FontEditor.h"
-#include "GlyphEditorWidget.h"
-#include "GlyphMapWidget.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/BitmapFont.h>
-#include <LibGfx/Palette.h>
-#include <stdlib.h>
-
-FontEditorWidget::FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&& edited_font)
- : m_edited_font(move(edited_font))
- , m_path(path)
-{
- set_fill_with_background_color(true);
- set_layout<GUI::VerticalBoxLayout>();
-
- // Top
- auto& main_container = add<GUI::Widget>();
- main_container.set_layout<GUI::HorizontalBoxLayout>();
- main_container.layout()->set_margins({ 4, 4, 4, 4 });
- main_container.set_background_role(Gfx::ColorRole::SyntaxKeyword);
-
- // Top-Left Glyph Editor and info
- auto& editor_container = main_container.add<GUI::Widget>();
- editor_container.set_layout<GUI::VerticalBoxLayout>();
- editor_container.layout()->set_margins({ 4, 4, 4, 4 });
- editor_container.set_background_role(Gfx::ColorRole::SyntaxKeyword);
-
- m_glyph_editor_widget = editor_container.add<GlyphEditorWidget>(*m_edited_font);
- m_glyph_editor_widget->set_fixed_size(m_glyph_editor_widget->preferred_width(), m_glyph_editor_widget->preferred_height());
-
- editor_container.set_fixed_width(m_glyph_editor_widget->preferred_width());
-
- auto& glyph_width_label = editor_container.add<GUI::Label>();
- glyph_width_label.set_fixed_height(22);
- glyph_width_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- glyph_width_label.set_text("Glyph width:");
-
- auto& glyph_width_spinbox = editor_container.add<GUI::SpinBox>();
- glyph_width_spinbox.set_min(0);
- glyph_width_spinbox.set_max(32);
- glyph_width_spinbox.set_value(0);
- glyph_width_spinbox.set_enabled(!m_edited_font->is_fixed_width());
-
- auto& info_label = editor_container.add<GUI::Label>();
- info_label.set_fixed_height(22);
- info_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- info_label.set_text("info_label");
-
- /// Top-Right glyph map and font meta data
-
- auto& map_and_test_container = main_container.add<GUI::Widget>();
- map_and_test_container.set_layout<GUI::VerticalBoxLayout>();
- map_and_test_container.layout()->set_margins({ 4, 4, 4, 4 });
-
- m_glyph_map_widget = map_and_test_container.add<GlyphMapWidget>(*m_edited_font);
- m_glyph_map_widget->set_fixed_size(m_glyph_map_widget->preferred_width(), m_glyph_map_widget->preferred_height());
-
- auto& font_mtest_group_box = map_and_test_container.add<GUI::GroupBox>();
- font_mtest_group_box.set_layout<GUI::VerticalBoxLayout>();
- font_mtest_group_box.layout()->set_margins({ 5, 15, 5, 5 });
- font_mtest_group_box.set_fixed_height(2 * m_edited_font->glyph_height() + 50);
- font_mtest_group_box.set_title("Test");
-
- auto& demo_label_1 = font_mtest_group_box.add<GUI::Label>();
- demo_label_1.set_font(m_edited_font);
- demo_label_1.set_text("quick fox jumps nightly above wizard.");
-
- auto& demo_label_2 = font_mtest_group_box.add<GUI::Label>();
- demo_label_2.set_font(m_edited_font);
- demo_label_2.set_text("QUICK FOX JUMPS NIGHTLY ABOVE WIZARD!");
-
- auto& font_metadata_group_box = map_and_test_container.add<GUI::GroupBox>();
- font_metadata_group_box.set_layout<GUI::VerticalBoxLayout>();
- font_metadata_group_box.layout()->set_margins({ 5, 15, 5, 5 });
- font_metadata_group_box.set_fixed_height(275);
- font_metadata_group_box.set_title("Font metadata");
-
- //// Name Row
- auto& namecontainer = font_metadata_group_box.add<GUI::Widget>();
- namecontainer.set_layout<GUI::HorizontalBoxLayout>();
- namecontainer.set_fixed_height(22);
-
- auto& name_label = namecontainer.add<GUI::Label>();
- name_label.set_fixed_width(100);
- name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- name_label.set_text("Name:");
-
- auto& name_textbox = namecontainer.add<GUI::TextBox>();
- name_textbox.set_text(m_edited_font->name());
- name_textbox.on_change = [&] {
- m_edited_font->set_name(name_textbox.text());
- };
-
- //// Family Row
- auto& family_container = font_metadata_group_box.add<GUI::Widget>();
- family_container.set_layout<GUI::HorizontalBoxLayout>();
- family_container.set_fixed_height(22);
-
- auto& family_label = family_container.add<GUI::Label>();
- family_label.set_fixed_width(100);
- family_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- family_label.set_text("Family:");
-
- auto& family_textbox = family_container.add<GUI::TextBox>();
- family_textbox.set_text(m_edited_font->family());
- family_textbox.on_change = [&] {
- m_edited_font->set_family(family_textbox.text());
- };
-
- //// Presentation size Row
- auto& presentation_size_container = font_metadata_group_box.add<GUI::Widget>();
- presentation_size_container.set_layout<GUI::HorizontalBoxLayout>();
- presentation_size_container.set_fixed_height(22);
-
- auto& presentation_size_label = presentation_size_container.add<GUI::Label>();
- presentation_size_label.set_fixed_width(100);
- presentation_size_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- presentation_size_label.set_text("Presentation size:");
-
- auto& presentation_size_spinbox = presentation_size_container.add<GUI::SpinBox>();
- presentation_size_spinbox.set_min(0);
- presentation_size_spinbox.set_max(255);
- presentation_size_spinbox.set_value(m_edited_font->presentation_size());
-
- //// Weight Row
- auto& weight_container = font_metadata_group_box.add<GUI::Widget>();
- weight_container.set_layout<GUI::HorizontalBoxLayout>();
- weight_container.set_fixed_height(22);
-
- auto& weight_label = weight_container.add<GUI::Label>();
- weight_label.set_fixed_width(100);
- weight_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- weight_label.set_text("Weight:");
-
- auto& weight_spinbox = weight_container.add<GUI::SpinBox>();
- weight_spinbox.set_min(0);
- weight_spinbox.set_max(65535);
- weight_spinbox.set_value(m_edited_font->weight());
-
- //// Glyph spacing Row
- auto& glyph_spacing_container = font_metadata_group_box.add<GUI::Widget>();
- glyph_spacing_container.set_layout<GUI::HorizontalBoxLayout>();
- glyph_spacing_container.set_fixed_height(22);
-
- auto& glyph_spacing = glyph_spacing_container.add<GUI::Label>();
- glyph_spacing.set_fixed_width(100);
- glyph_spacing.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- glyph_spacing.set_text("Glyph spacing:");
-
- auto& spacing_spinbox = glyph_spacing_container.add<GUI::SpinBox>();
- spacing_spinbox.set_min(0);
- spacing_spinbox.set_max(255);
- spacing_spinbox.set_value(m_edited_font->glyph_spacing());
-
- //// Glyph Height Row
- auto& glyph_height_container = font_metadata_group_box.add<GUI::Widget>();
- glyph_height_container.set_layout<GUI::HorizontalBoxLayout>();
- glyph_height_container.set_fixed_height(22);
-
- auto& glyph_height = glyph_height_container.add<GUI::Label>();
- glyph_height.set_fixed_width(100);
- glyph_height.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- glyph_height.set_text("Glyph height:");
-
- auto& glyph_height_spinbox = glyph_height_container.add<GUI::SpinBox>();
- glyph_height_spinbox.set_min(0);
- glyph_height_spinbox.set_max(255);
- glyph_height_spinbox.set_value(m_edited_font->glyph_height());
- glyph_height_spinbox.set_enabled(false);
-
- //// Glyph width Row
- auto& glyph_weight_container = font_metadata_group_box.add<GUI::Widget>();
- glyph_weight_container.set_layout<GUI::HorizontalBoxLayout>();
- glyph_weight_container.set_fixed_height(22);
-
- auto& glyph_header_width_label = glyph_weight_container.add<GUI::Label>();
- glyph_header_width_label.set_fixed_width(100);
- glyph_header_width_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- glyph_header_width_label.set_text("Glyph width:");
-
- auto& glyph_header_width_spinbox = glyph_weight_container.add<GUI::SpinBox>();
- glyph_header_width_spinbox.set_min(0);
- glyph_header_width_spinbox.set_max(255);
- glyph_header_width_spinbox.set_value(m_edited_font->glyph_fixed_width());
- glyph_header_width_spinbox.set_enabled(false);
-
- //// Baseline Row
- auto& baseline_container = font_metadata_group_box.add<GUI::Widget>();
- baseline_container.set_layout<GUI::HorizontalBoxLayout>();
- baseline_container.set_fixed_height(22);
-
- auto& baseline_label = baseline_container.add<GUI::Label>();
- baseline_label.set_fixed_width(100);
- baseline_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- baseline_label.set_text("Baseline:");
-
- auto& baseline_spinbox = baseline_container.add<GUI::SpinBox>();
- baseline_spinbox.set_min(0);
- baseline_spinbox.set_max(m_edited_font->glyph_height() - 1);
- baseline_spinbox.set_value(m_edited_font->baseline());
-
- //// Mean line Row
- auto& mean_line_container = font_metadata_group_box.add<GUI::Widget>();
- mean_line_container.set_layout<GUI::HorizontalBoxLayout>();
- mean_line_container.set_fixed_height(22);
-
- auto& mean_line_label = mean_line_container.add<GUI::Label>();
- mean_line_label.set_fixed_width(100);
- mean_line_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- mean_line_label.set_text("Mean Line:");
-
- auto& mean_line_spinbox = mean_line_container.add<GUI::SpinBox>();
- mean_line_spinbox.set_min(0);
- mean_line_spinbox.set_max(m_edited_font->glyph_height() - 1);
- mean_line_spinbox.set_value(m_edited_font->mean_line());
-
- //// Fixed checkbox Row
- auto& fixed_width_checkbox = font_metadata_group_box.add<GUI::CheckBox>();
- fixed_width_checkbox.set_text("Fixed width");
- fixed_width_checkbox.set_checked(m_edited_font->is_fixed_width());
-
- // Bottom
- auto& bottom_container = add<GUI::Widget>();
- bottom_container.set_layout<GUI::HorizontalBoxLayout>();
- bottom_container.layout()->set_margins({ 8, 0, 8, 8 });
- bottom_container.set_fixed_height(32);
-
- bottom_container.layout()->add_spacer();
-
- auto& save_button = bottom_container.add<GUI::Button>();
- save_button.set_fixed_size(80, 22);
- save_button.set_text("Save");
- save_button.on_click = [this](auto) { save_as(m_path); };
-
- auto& quit_button = bottom_container.add<GUI::Button>();
- quit_button.set_fixed_size(80, 22);
- quit_button.set_text("Quit");
- quit_button.on_click = [](auto) {
- exit(0);
- };
-
- // Event hanglers
- auto update_demo = [&] {
- demo_label_1.update();
- demo_label_2.update();
- };
-
- auto calculate_prefed_sizes = [&] {
- int right_site_width = m_edited_font->width("QUICK FOX JUMPS NIGHTLY ABOVE WIZARD!") + 20;
- right_site_width = max(right_site_width, m_glyph_map_widget->preferred_width());
-
- m_preferred_width = m_glyph_editor_widget->width() + right_site_width + 20;
- m_preferred_height = m_glyph_map_widget->relative_rect().height() + 2 * m_edited_font->glyph_height() + 380;
- };
-
- m_glyph_editor_widget->on_glyph_altered = [this, update_demo](u8 glyph) {
- m_glyph_map_widget->update_glyph(glyph);
- update_demo();
- };
-
- m_glyph_map_widget->on_glyph_selected = [&](size_t glyph) {
- m_glyph_editor_widget->set_glyph(glyph);
- glyph_width_spinbox.set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
- StringBuilder builder;
- builder.appendff("{:#02x} (", glyph);
- if (glyph < 128) {
- builder.append(glyph);
- } else {
- builder.append(128 | 64 | (glyph / 64));
- builder.append(128 | (glyph % 64));
- }
- builder.append(')');
- info_label.set_text(builder.to_string());
- };
-
- fixed_width_checkbox.on_checked = [&, update_demo](bool checked) {
- m_edited_font->set_fixed_width(checked);
- glyph_width_spinbox.set_enabled(!m_edited_font->is_fixed_width());
- glyph_width_spinbox.set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
- m_glyph_editor_widget->update();
- update_demo();
- };
-
- glyph_width_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_glyph_width(m_glyph_map_widget->selected_glyph(), value);
- m_glyph_editor_widget->update();
- m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_glyph());
- update_demo();
- };
-
- weight_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_weight(value);
- update_demo();
- };
-
- presentation_size_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_presentation_size(value);
- update_demo();
- };
-
- spacing_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_glyph_spacing(value);
- update_demo();
- };
-
- baseline_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_baseline(value);
- m_glyph_editor_widget->update();
- update_demo();
- };
-
- mean_line_spinbox.on_change = [this, update_demo](int value) {
- m_edited_font->set_mean_line(value);
- m_glyph_editor_widget->update();
- update_demo();
- };
-
- // init widget
- calculate_prefed_sizes();
- m_glyph_map_widget->set_selected_glyph('A');
-}
-
-FontEditorWidget::~FontEditorWidget()
-{
-}
-
-bool FontEditorWidget::save_as(const String& path)
-{
- auto ret_val = m_edited_font->write_to_file(path);
- if (!ret_val) {
- GUI::MessageBox::show(window(), "The font file could not be saved.", "Save failed", GUI::MessageBox::Type::Error);
- return false;
- }
- m_path = path;
- return true;
-}
diff --git a/Applications/FontEditor/FontEditor.h b/Applications/FontEditor/FontEditor.h
deleted file mode 100644
index ed904e8e7d..0000000000
--- a/Applications/FontEditor/FontEditor.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <LibGUI/Widget.h>
-#include <LibGfx/BitmapFont.h>
-
-class GlyphEditorWidget;
-class GlyphMapWidget;
-
-class FontEditorWidget final : public GUI::Widget {
- C_OBJECT(FontEditorWidget)
-public:
- virtual ~FontEditorWidget() override;
-
- int preferred_width() { return m_preferred_width; }
- int preferred_height() { return m_preferred_height; }
-
- bool save_as(const String&);
-
- const String& path() { return m_path; }
-
-private:
- FontEditorWidget(const String& path, RefPtr<Gfx::BitmapFont>&&);
- RefPtr<Gfx::BitmapFont> m_edited_font;
-
- RefPtr<GlyphMapWidget> m_glyph_map_widget;
- RefPtr<GlyphEditorWidget> m_glyph_editor_widget;
-
- String m_path;
- int m_preferred_width;
- int m_preferred_height;
-};
diff --git a/Applications/FontEditor/GlyphEditorWidget.cpp b/Applications/FontEditor/GlyphEditorWidget.cpp
deleted file mode 100644
index 6f545c1ccd..0000000000
--- a/Applications/FontEditor/GlyphEditorWidget.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "GlyphEditorWidget.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/BitmapFont.h>
-#include <LibGfx/Palette.h>
-
-GlyphEditorWidget::GlyphEditorWidget(Gfx::BitmapFont& mutable_font)
- : m_font(mutable_font)
-{
- set_relative_rect({ 0, 0, preferred_width(), preferred_height() });
-}
-
-GlyphEditorWidget::~GlyphEditorWidget()
-{
-}
-
-void GlyphEditorWidget::set_glyph(int glyph)
-{
- if (m_glyph == glyph)
- return;
- m_glyph = glyph;
- update();
-}
-
-void GlyphEditorWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(frame_inner_rect());
- painter.add_clip_rect(event.rect());
- painter.fill_rect(frame_inner_rect(), palette().base());
- painter.translate(frame_thickness(), frame_thickness());
-
- painter.translate(-1, -1);
- for (int y = 1; y < font().glyph_height(); ++y) {
- int y_below = y - 1;
- bool bold_line = y_below == font().baseline() || y_below == font().mean_line();
- painter.draw_line({ 0, y * m_scale }, { font().max_glyph_width() * m_scale, y * m_scale }, palette().threed_shadow2(), bold_line ? 2 : 1);
- }
-
- for (int x = 1; x < font().max_glyph_width(); ++x)
- painter.draw_line({ x * m_scale, 0 }, { x * m_scale, font().glyph_height() * m_scale }, palette().threed_shadow2());
-
- auto bitmap = font().glyph_bitmap(m_glyph);
-
- for (int y = 0; y < font().glyph_height(); ++y) {
- for (int x = 0; x < font().max_glyph_width(); ++x) {
- Gfx::IntRect rect { x * m_scale, y * m_scale, m_scale, m_scale };
- if (x >= font().glyph_width(m_glyph)) {
- painter.fill_rect(rect, palette().threed_shadow1());
- } else {
- if (bitmap.bit_at(x, y))
- painter.fill_rect(rect, palette().base_text());
- }
- }
- }
-}
-
-void GlyphEditorWidget::mousedown_event(GUI::MouseEvent& event)
-{
- draw_at_mouse(event);
-}
-
-void GlyphEditorWidget::mousemove_event(GUI::MouseEvent& event)
-{
- if (event.buttons() & (GUI::MouseButton::Left | GUI::MouseButton::Right))
- draw_at_mouse(event);
-}
-
-void GlyphEditorWidget::draw_at_mouse(const GUI::MouseEvent& event)
-{
- bool set = event.buttons() & GUI::MouseButton::Left;
- bool unset = event.buttons() & GUI::MouseButton::Right;
- if (!(set ^ unset))
- return;
- int x = (event.x() - 1) / m_scale;
- int y = (event.y() - 1) / m_scale;
- auto bitmap = font().glyph_bitmap(m_glyph);
- if (x < 0 || x >= bitmap.width())
- return;
- if (y < 0 || y >= bitmap.height())
- return;
- if (bitmap.bit_at(x, y) == set)
- return;
- bitmap.set_bit_at(x, y, set);
- if (on_glyph_altered)
- on_glyph_altered(m_glyph);
- update();
-}
-
-int GlyphEditorWidget::preferred_width() const
-{
- return frame_thickness() * 2 + font().max_glyph_width() * m_scale - 1;
-}
-
-int GlyphEditorWidget::preferred_height() const
-{
- return frame_thickness() * 2 + font().glyph_height() * m_scale - 1;
-}
diff --git a/Applications/FontEditor/GlyphEditorWidget.h b/Applications/FontEditor/GlyphEditorWidget.h
deleted file mode 100644
index a54c551642..0000000000
--- a/Applications/FontEditor/GlyphEditorWidget.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <LibGUI/Frame.h>
-#include <LibGfx/BitmapFont.h>
-
-class GlyphEditorWidget final : public GUI::Frame {
- C_OBJECT(GlyphEditorWidget)
-public:
- virtual ~GlyphEditorWidget() override;
-
- int glyph() const { return m_glyph; }
- void set_glyph(int);
-
- int preferred_width() const;
- int preferred_height() const;
-
- Gfx::BitmapFont& font() { return *m_font; }
- const Gfx::BitmapFont& font() const { return *m_font; }
-
- Function<void(u8)> on_glyph_altered;
-
-private:
- GlyphEditorWidget(Gfx::BitmapFont&);
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
-
- void draw_at_mouse(const GUI::MouseEvent&);
-
- RefPtr<Gfx::BitmapFont> m_font;
- int m_glyph { 0 };
- int m_scale { 10 };
-};
diff --git a/Applications/FontEditor/GlyphMapWidget.cpp b/Applications/FontEditor/GlyphMapWidget.cpp
deleted file mode 100644
index ed6a65493f..0000000000
--- a/Applications/FontEditor/GlyphMapWidget.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "GlyphMapWidget.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/BitmapFont.h>
-#include <LibGfx/Palette.h>
-
-GlyphMapWidget::GlyphMapWidget(Gfx::BitmapFont& mutable_font)
- : m_font(mutable_font)
-{
- m_glyph_count = mutable_font.glyph_count();
- set_relative_rect({ 0, 0, preferred_width(), preferred_height() });
- set_focus_policy(GUI::FocusPolicy::StrongFocus);
-}
-
-GlyphMapWidget::~GlyphMapWidget()
-{
-}
-
-int GlyphMapWidget::preferred_width() const
-{
- return columns() * (font().max_glyph_width() + m_horizontal_spacing) + 2 + frame_thickness() * 2;
-}
-
-int GlyphMapWidget::preferred_height() const
-{
- return rows() * (font().glyph_height() + m_vertical_spacing) + 2 + frame_thickness() * 2;
-}
-
-void GlyphMapWidget::set_selected_glyph(int glyph)
-{
- if (m_selected_glyph == glyph)
- return;
- m_selected_glyph = glyph;
- if (on_glyph_selected)
- on_glyph_selected(glyph);
- update();
-}
-
-Gfx::IntRect GlyphMapWidget::get_outer_rect(int glyph) const
-{
- int row = glyph / columns();
- int column = glyph % columns();
- return Gfx::IntRect {
- column * (font().max_glyph_width() + m_horizontal_spacing) + 1,
- row * (font().glyph_height() + m_vertical_spacing) + 1,
- font().max_glyph_width() + m_horizontal_spacing,
- font().glyph_height() + m_horizontal_spacing
- }
- .translated(frame_thickness(), frame_thickness());
-}
-
-void GlyphMapWidget::update_glyph(int glyph)
-{
- update(get_outer_rect(glyph));
-}
-
-void GlyphMapWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- painter.set_font(font());
- painter.fill_rect(frame_inner_rect(), palette().base());
-
- for (int glyph = 0; glyph < m_glyph_count; ++glyph) {
- Gfx::IntRect outer_rect = get_outer_rect(glyph);
- Gfx::IntRect inner_rect(
- outer_rect.x() + m_horizontal_spacing / 2,
- outer_rect.y() + m_vertical_spacing / 2,
- font().max_glyph_width(),
- font().glyph_height());
- if (glyph == m_selected_glyph) {
- painter.fill_rect(outer_rect, is_focused() ? palette().selection() : palette().inactive_selection());
- painter.draw_glyph(inner_rect.location(), glyph, is_focused() ? palette().selection_text() : palette().inactive_selection_text());
- } else {
- painter.draw_glyph(inner_rect.location(), glyph, palette().base_text());
- }
- }
-}
-
-void GlyphMapWidget::mousedown_event(GUI::MouseEvent& event)
-{
- GUI::Frame::mousedown_event(event);
-
- // FIXME: This is a silly loop.
- for (int glyph = 0; glyph < m_glyph_count; ++glyph) {
- if (get_outer_rect(glyph).contains(event.position())) {
- set_selected_glyph(glyph);
- break;
- }
- }
-}
-
-void GlyphMapWidget::keydown_event(GUI::KeyEvent& event)
-{
- GUI::Frame::keydown_event(event);
-
- if (event.key() == KeyCode::Key_Up) {
- if (selected_glyph() >= m_columns) {
- set_selected_glyph(selected_glyph() - m_columns);
- return;
- }
- }
- if (event.key() == KeyCode::Key_Down) {
- if (selected_glyph() < m_glyph_count - m_columns) {
- set_selected_glyph(selected_glyph() + m_columns);
- return;
- }
- }
- if (event.key() == KeyCode::Key_Left) {
- if (selected_glyph() > 0) {
- set_selected_glyph(selected_glyph() - 1);
- return;
- }
- }
- if (event.key() == KeyCode::Key_Right) {
- if (selected_glyph() < m_glyph_count - 1) {
- set_selected_glyph(selected_glyph() + 1);
- return;
- }
- }
- if (event.ctrl() && event.key() == KeyCode::Key_Home) {
- set_selected_glyph(0);
- return;
- }
- if (event.ctrl() && event.key() == KeyCode::Key_End) {
- set_selected_glyph(m_glyph_count - 1);
- return;
- }
- if (!event.ctrl() && event.key() == KeyCode::Key_Home) {
- set_selected_glyph(selected_glyph() / m_columns * m_columns);
- return;
- }
- if (!event.ctrl() && event.key() == KeyCode::Key_End) {
- int new_selection = selected_glyph() / m_columns * m_columns + (m_columns - 1);
- int max = m_glyph_count - 1;
- new_selection = clamp(new_selection, 0, max);
- set_selected_glyph(new_selection);
- return;
- }
-}
diff --git a/Applications/FontEditor/GlyphMapWidget.h b/Applications/FontEditor/GlyphMapWidget.h
deleted file mode 100644
index 2c8443a251..0000000000
--- a/Applications/FontEditor/GlyphMapWidget.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/StdLibExtras.h>
-#include <LibGUI/Frame.h>
-#include <LibGfx/BitmapFont.h>
-
-class GlyphMapWidget final : public GUI::Frame {
- C_OBJECT(GlyphMapWidget)
-public:
- virtual ~GlyphMapWidget() override;
-
- int selected_glyph() const { return m_selected_glyph; }
- void set_selected_glyph(int);
-
- int rows() const { return ceil_div(m_glyph_count, m_columns); }
- int columns() const { return m_columns; }
-
- int preferred_width() const;
- int preferred_height() const;
-
- Gfx::BitmapFont& font() { return *m_font; }
- const Gfx::BitmapFont& font() const { return *m_font; }
-
- void update_glyph(int);
-
- Function<void(int)> on_glyph_selected;
-
-private:
- explicit GlyphMapWidget(Gfx::BitmapFont&);
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void keydown_event(GUI::KeyEvent&) override;
-
- Gfx::IntRect get_outer_rect(int glyph) const;
-
- RefPtr<Gfx::BitmapFont> m_font;
- int m_glyph_count;
- int m_columns { 32 };
- int m_horizontal_spacing { 2 };
- int m_vertical_spacing { 2 };
- int m_selected_glyph { 0 };
-};
diff --git a/Applications/FontEditor/main.cpp b/Applications/FontEditor/main.cpp
deleted file mode 100644
index f0a72d1d29..0000000000
--- a/Applications/FontEditor/main.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "FontEditor.h"
-#include <AK/URL.h>
-#include <LibCore/ArgsParser.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/BitmapFont.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/Point.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer thread rpath accept unix cpath wpath fattr unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer thread rpath accept cpath wpath unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (!Desktop::Launcher::add_allowed_handler_with_only_specific_urls(
- "/bin/Help",
- { URL::create_with_file_protocol("/usr/share/man/man1/FontEditor.md") })
- || !Desktop::Launcher::seal_allowlist()) {
- warnln("Failed to set up allowed launch URLs");
- return 1;
- }
-
- if (pledge("stdio shared_buffer thread rpath accept cpath wpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* path = nullptr;
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(path, "The font file for editing.", "file", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
-
- RefPtr<Gfx::BitmapFont> edited_font;
- if (path == nullptr) {
- path = "/tmp/saved.font";
- edited_font = static_ptr_cast<Gfx::BitmapFont>(Gfx::FontDatabase::default_font().clone());
- } else {
- edited_font = static_ptr_cast<Gfx::BitmapFont>(Gfx::Font::load_from_file(path)->clone());
- if (!edited_font) {
- String message = String::formatted("Couldn't load font: {}\n", path);
- GUI::MessageBox::show(nullptr, message, "Font Editor", GUI::MessageBox::Type::Error);
- return 1;
- }
- }
-
- auto app_icon = GUI::Icon::default_icon("app-font-editor");
-
- auto window = GUI::Window::construct();
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto set_edited_font = [&](const String& path, RefPtr<Gfx::BitmapFont>&& font, Gfx::IntPoint point) {
- // Convert 256 char font to 384 char font.
- if (font->type() == Gfx::FontTypes::Default)
- font->set_type(Gfx::FontTypes::LatinExtendedA);
-
- window->set_title(String::formatted("{} - Font Editor", path));
- auto& font_editor_widget = window->set_main_widget<FontEditorWidget>(path, move(font));
- window->set_rect({ point, { font_editor_widget.preferred_width(), font_editor_widget.preferred_height() } });
- };
- set_edited_font(path, move(edited_font), window->position());
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Font Editor");
- app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(window);
- if (!open_path.has_value())
- return;
-
- RefPtr<Gfx::BitmapFont> new_font = static_ptr_cast<Gfx::BitmapFont>(Gfx::Font::load_from_file(open_path.value())->clone());
- if (!new_font) {
- String message = String::formatted("Couldn't load font: {}\n", open_path.value());
- GUI::MessageBox::show(window, message, "Font Editor", GUI::MessageBox::Type::Error);
- return;
- }
-
- set_edited_font(open_path.value(), move(new_font), window->position());
- }));
- app_menu.add_action(GUI::CommonActions::make_save_action([&](auto&) {
- FontEditorWidget* editor = static_cast<FontEditorWidget*>(window->main_widget());
- editor->save_as(editor->path());
- }));
- app_menu.add_action(GUI::CommonActions::make_save_as_action([&](auto&) {
- FontEditorWidget* editor = static_cast<FontEditorWidget*>(window->main_widget());
- LexicalPath lexical_path(editor->path());
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, lexical_path.title(), lexical_path.extension());
- if (!save_path.has_value())
- return;
-
- if (editor->save_as(save_path.value()))
- window->set_title(String::formatted("{} - Font Editor", save_path.value()));
- }));
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
- app->quit();
- return;
- }));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_help_action([](auto&) {
- Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man1/FontEditor.md"), "/bin/Help");
- }));
-
- help_menu.add_action(GUI::CommonActions::make_about_action("Font Editor", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/Help/CMakeLists.txt b/Applications/Help/CMakeLists.txt
deleted file mode 100644
index 46a832c044..0000000000
--- a/Applications/Help/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-set(SOURCES
- History.cpp
- main.cpp
- ManualModel.cpp
- ManualPageNode.cpp
- ManualSectionNode.cpp
-)
-
-serenity_app(Help ICON app-help)
-target_link_libraries(Help LibWeb LibMarkdown LibGUI LibDesktop)
diff --git a/Applications/Help/History.cpp b/Applications/Help/History.cpp
deleted file mode 100644
index bb4c822dcb..0000000000
--- a/Applications/Help/History.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "History.h"
-
-void History::push(const StringView& history_item)
-{
- m_items.shrink(m_current_history_item + 1);
- m_items.append(history_item);
- m_current_history_item++;
-}
-
-String History::current()
-{
- if (m_current_history_item == -1)
- return {};
- return m_items[m_current_history_item];
-}
-
-void History::go_back()
-{
- ASSERT(can_go_back());
- m_current_history_item--;
-}
-
-void History::go_forward()
-{
- ASSERT(can_go_forward());
- m_current_history_item++;
-}
-
-void History::clear()
-{
- m_items = {};
- m_current_history_item = -1;
-}
diff --git a/Applications/Help/History.h b/Applications/Help/History.h
deleted file mode 100644
index c4058fabfc..0000000000
--- a/Applications/Help/History.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Vector.h>
-
-class History final {
-public:
- void push(const StringView& history_item);
- String current();
-
- void go_back();
- void go_forward();
-
- bool can_go_back() { return m_current_history_item > 0; }
- bool can_go_forward() { return m_current_history_item + 1 < static_cast<int>(m_items.size()); }
-
- void clear();
-
-private:
- Vector<String> m_items;
- int m_current_history_item { -1 };
-};
diff --git a/Applications/Help/ManualModel.cpp b/Applications/Help/ManualModel.cpp
deleted file mode 100644
index 484b1b22c1..0000000000
--- a/Applications/Help/ManualModel.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ManualModel.h"
-#include "ManualNode.h"
-#include "ManualPageNode.h"
-#include "ManualSectionNode.h"
-#include <AK/ByteBuffer.h>
-#include <LibCore/File.h>
-#include <LibGUI/FilteringProxyModel.h>
-
-static ManualSectionNode s_sections[] = {
- { "1", "User programs" },
- { "2", "System calls" },
- { "3", "Libraries" },
- { "4", "Special files" },
- { "5", "File formats" },
- { "6", "Games" },
- { "7", "Miscellanea" },
- { "8", "Sysadmin tools" }
-};
-
-ManualModel::ManualModel()
-{
- m_section_open_icon.set_bitmap_for_size(16, Gfx::Bitmap::load_from_file("/res/icons/16x16/book-open.png"));
- m_section_icon.set_bitmap_for_size(16, Gfx::Bitmap::load_from_file("/res/icons/16x16/book.png"));
- m_page_icon.set_bitmap_for_size(16, Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-unknown.png"));
-}
-
-Optional<GUI::ModelIndex> ManualModel::index_from_path(const StringView& path) const
-{
- for (int section = 0; section < row_count(); ++section) {
- auto parent_index = index(section, 0);
- for (int row = 0; row < row_count(parent_index); ++row) {
- auto child_index = index(row, 0, parent_index);
- auto* node = static_cast<const ManualNode*>(child_index.internal_data());
- if (!node->is_page())
- continue;
- auto* page = static_cast<const ManualPageNode*>(node);
- if (page->path() != path)
- continue;
- return child_index;
- }
- }
- return {};
-}
-
-String ManualModel::page_path(const GUI::ModelIndex& index) const
-{
- if (!index.is_valid())
- return {};
- auto* node = static_cast<const ManualNode*>(index.internal_data());
- if (!node->is_page())
- return {};
- auto* page = static_cast<const ManualPageNode*>(node);
- return page->path();
-}
-
-Result<StringView, OSError> ManualModel::page_view(const String& path) const
-{
- if (path.is_empty())
- return StringView {};
-
- {
- // Check if we've got it cached already.
- auto mapped_file = m_mapped_files.get(path);
- if (mapped_file.has_value())
- return StringView { mapped_file.value()->bytes() };
- }
-
- auto file_or_error = MappedFile::map(path);
- if (file_or_error.is_error())
- return file_or_error.error();
-
- StringView view { file_or_error.value()->bytes() };
- m_mapped_files.set(path, file_or_error.release_value());
- return view;
-}
-
-String ManualModel::page_and_section(const GUI::ModelIndex& index) const
-{
- if (!index.is_valid())
- return {};
- auto* node = static_cast<const ManualNode*>(index.internal_data());
- if (!node->is_page())
- return {};
- auto* page = static_cast<const ManualPageNode*>(node);
- auto* section = static_cast<const ManualSectionNode*>(page->parent());
- return String::formatted("{}({})", page->name(), section->section_name());
-}
-
-GUI::ModelIndex ManualModel::index(int row, int column, const GUI::ModelIndex& parent_index) const
-{
- if (!parent_index.is_valid())
- return create_index(row, column, &s_sections[row]);
- auto* parent = static_cast<const ManualNode*>(parent_index.internal_data());
- auto* child = &parent->children()[row];
- return create_index(row, column, child);
-}
-
-GUI::ModelIndex ManualModel::parent_index(const GUI::ModelIndex& index) const
-{
- if (!index.is_valid())
- return {};
- auto* child = static_cast<const ManualNode*>(index.internal_data());
- auto* parent = child->parent();
- if (parent == nullptr)
- return {};
-
- if (parent->parent() == nullptr) {
- for (size_t row = 0; row < sizeof(s_sections) / sizeof(s_sections[0]); row++)
- if (&s_sections[row] == parent)
- return create_index(row, 0, parent);
- ASSERT_NOT_REACHED();
- }
- for (size_t row = 0; row < parent->parent()->children().size(); row++) {
- ManualNode* child_at_row = &parent->parent()->children()[row];
- if (child_at_row == parent)
- return create_index(row, 0, parent);
- }
- ASSERT_NOT_REACHED();
-}
-
-int ManualModel::row_count(const GUI::ModelIndex& index) const
-{
- if (!index.is_valid())
- return sizeof(s_sections) / sizeof(s_sections[0]);
- auto* node = static_cast<const ManualNode*>(index.internal_data());
- return node->children().size();
-}
-
-int ManualModel::column_count(const GUI::ModelIndex&) const
-{
- return 1;
-}
-
-GUI::Variant ManualModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- auto* node = static_cast<const ManualNode*>(index.internal_data());
- switch (role) {
- case GUI::ModelRole::Search:
- if (!node->is_page())
- return {};
- return String(page_view(page_path(index)).value());
- case GUI::ModelRole::Display:
- return node->name();
- case GUI::ModelRole::Icon:
- if (node->is_page())
- return m_page_icon;
- if (node->is_open())
- return m_section_open_icon;
- return m_section_icon;
- default:
- return {};
- }
-}
-
-void ManualModel::update_section_node_on_toggle(const GUI::ModelIndex& index, const bool open)
-{
- auto* node = static_cast<ManualSectionNode*>(index.internal_data());
- node->set_open(open);
-}
-
-TriState ManualModel::data_matches(const GUI::ModelIndex& index, GUI::Variant term) const
-{
- auto view_result = page_view(page_path(index));
- if (view_result.is_error() || view_result.value().is_empty())
- return TriState::False;
-
- return view_result.value().contains(term.as_string()) ? TriState::True : TriState::False;
-}
-
-void ManualModel::update()
-{
- did_update();
-}
diff --git a/Applications/Help/ManualModel.h b/Applications/Help/ManualModel.h
deleted file mode 100644
index 02efecaff0..0000000000
--- a/Applications/Help/ManualModel.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/NonnullRefPtr.h>
-#include <AK/Optional.h>
-#include <AK/Result.h>
-#include <AK/String.h>
-#include <LibGUI/Model.h>
-
-class ManualModel final : public GUI::Model {
-public:
- static NonnullRefPtr<ManualModel> create()
- {
- return adopt(*new ManualModel);
- }
-
- virtual ~ManualModel() override {};
-
- Optional<GUI::ModelIndex> index_from_path(const StringView&) const;
-
- String page_path(const GUI::ModelIndex&) const;
- String page_and_section(const GUI::ModelIndex&) const;
- Result<StringView, OSError> page_view(const String& path) const;
-
- void update_section_node_on_toggle(const GUI::ModelIndex&, const bool);
- virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
- virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual TriState data_matches(const GUI::ModelIndex&, GUI::Variant) const override;
- virtual void update() override;
- virtual GUI::ModelIndex parent_index(const GUI::ModelIndex&) const override;
- virtual GUI::ModelIndex index(int row, int column = 0, const GUI::ModelIndex& parent = GUI::ModelIndex()) const override;
-
-private:
- ManualModel();
-
- GUI::Icon m_section_open_icon;
- GUI::Icon m_section_icon;
- GUI::Icon m_page_icon;
- mutable HashMap<String, NonnullRefPtr<MappedFile>> m_mapped_files;
-};
diff --git a/Applications/Help/ManualNode.h b/Applications/Help/ManualNode.h
deleted file mode 100644
index b5901f9787..0000000000
--- a/Applications/Help/ManualNode.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/String.h>
-
-class ManualNode {
-public:
- virtual ~ManualNode() { }
-
- virtual NonnullOwnPtrVector<ManualNode>& children() const = 0;
- virtual const ManualNode* parent() const = 0;
- virtual String name() const = 0;
- virtual bool is_page() const { return false; }
- virtual bool is_open() const { return false; }
-};
diff --git a/Applications/Help/ManualPageNode.cpp b/Applications/Help/ManualPageNode.cpp
deleted file mode 100644
index 4b30c4dca4..0000000000
--- a/Applications/Help/ManualPageNode.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ManualPageNode.h"
-#include "ManualSectionNode.h"
-
-const ManualNode* ManualPageNode::parent() const
-{
- return &m_section;
-}
-
-NonnullOwnPtrVector<ManualNode>& ManualPageNode::children() const
-{
- static NonnullOwnPtrVector<ManualNode> empty_vector;
- return empty_vector;
-}
-
-String ManualPageNode::path() const
-{
- return String::formatted("{}/{}.md", m_section.path(), m_page);
-}
diff --git a/Applications/Help/ManualPageNode.h b/Applications/Help/ManualPageNode.h
deleted file mode 100644
index 6de744e0e4..0000000000
--- a/Applications/Help/ManualPageNode.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "ManualNode.h"
-
-class ManualSectionNode;
-
-class ManualPageNode : public ManualNode {
-public:
- virtual ~ManualPageNode() override { }
-
- ManualPageNode(const ManualSectionNode& section, const StringView& page)
- : m_section(section)
- , m_page(page)
- {
- }
-
- virtual NonnullOwnPtrVector<ManualNode>& children() const override;
- virtual const ManualNode* parent() const override;
- virtual String name() const override { return m_page; };
- virtual bool is_page() const override { return true; }
-
- String path() const;
-
-private:
- const ManualSectionNode& m_section;
- String m_page;
-};
diff --git a/Applications/Help/ManualSectionNode.cpp b/Applications/Help/ManualSectionNode.cpp
deleted file mode 100644
index ce34eb3286..0000000000
--- a/Applications/Help/ManualSectionNode.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ManualSectionNode.h"
-#include "ManualPageNode.h"
-#include <AK/LexicalPath.h>
-#include <AK/QuickSort.h>
-#include <AK/String.h>
-#include <LibCore/DirIterator.h>
-
-String ManualSectionNode::path() const
-{
- return String::formatted("/usr/share/man/man{}", m_section);
-}
-
-void ManualSectionNode::reify_if_needed() const
-{
- if (m_reified)
- return;
- m_reified = true;
-
- Core::DirIterator dir_iter { path(), Core::DirIterator::Flags::SkipDots };
-
- Vector<String> page_names;
- while (dir_iter.has_next()) {
- LexicalPath lexical_path(dir_iter.next_path());
- if (lexical_path.extension() != "md")
- continue;
- page_names.append(lexical_path.title());
- }
-
- quick_sort(page_names);
-
- for (auto& page_name : page_names)
- m_children.append(make<ManualPageNode>(*this, move(page_name)));
-}
-
-void ManualSectionNode::set_open(bool open)
-{
- if (m_open == open)
- return;
- m_open = open;
-}
diff --git a/Applications/Help/ManualSectionNode.h b/Applications/Help/ManualSectionNode.h
deleted file mode 100644
index 9b70ea9812..0000000000
--- a/Applications/Help/ManualSectionNode.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "ManualNode.h"
-
-class ManualSectionNode : public ManualNode {
-public:
- virtual ~ManualSectionNode() override { }
-
- ManualSectionNode(String section, String name)
- : m_section(section)
- , m_full_name(String::formatted("{}. {}", section, name))
- {
- }
-
- virtual NonnullOwnPtrVector<ManualNode>& children() const override
- {
- reify_if_needed();
- return m_children;
- }
-
- virtual const ManualNode* parent() const override { return nullptr; }
- virtual String name() const override { return m_full_name; }
- virtual bool is_open() const override { return m_open; }
- void set_open(bool open);
-
- const String& section_name() const { return m_section; }
- String path() const;
-
-private:
- void reify_if_needed() const;
-
- String m_section;
- String m_full_name;
- mutable NonnullOwnPtrVector<ManualNode> m_children;
- mutable bool m_reified { false };
- bool m_open { false };
-};
diff --git a/Applications/Help/main.cpp b/Applications/Help/main.cpp
deleted file mode 100644
index d5a6405fbf..0000000000
--- a/Applications/Help/main.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "History.h"
-#include "ManualModel.h"
-#include <AK/URL.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/File.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/FilteringProxyModel.h>
-#include <LibGUI/ListView.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/TreeView.h>
-#include <LibGUI/Window.h>
-#include <LibMarkdown/Document.h>
-#include <LibWeb/OutOfProcessWebView.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <string.h>
-
-int main(int argc, char* argv[])
-{
- if (pledge("stdio shared_buffer accept rpath unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept rpath unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/usr/share/man", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/launch", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/webcontent", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- const char* start_page = nullptr;
-
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(start_page, "Page to open at launch", "page", Core::ArgsParser::Required::No);
-
- args_parser.parse(argc, argv);
-
- auto app_icon = GUI::Icon::default_icon("app-help");
-
- auto window = GUI::Window::construct();
- window->set_icon(app_icon.bitmap_for_size(16));
- window->set_title("Help");
- window->resize(570, 500);
-
- auto& widget = window->set_main_widget<GUI::Widget>();
- widget.set_layout<GUI::VerticalBoxLayout>();
- widget.set_fill_with_background_color(true);
- widget.layout()->set_spacing(2);
-
- auto& toolbar_container = widget.add<GUI::ToolBarContainer>();
- auto& toolbar = toolbar_container.add<GUI::ToolBar>();
-
- auto& splitter = widget.add<GUI::HorizontalSplitter>();
-
- auto model = ManualModel::create();
-
- auto& left_tab_bar = splitter.add<GUI::TabWidget>();
- auto& tree_view_container = left_tab_bar.add_tab<GUI::Widget>("Browse");
- tree_view_container.set_layout<GUI::VerticalBoxLayout>();
- tree_view_container.layout()->set_margins({ 4, 4, 4, 4 });
- auto& tree_view = tree_view_container.add<GUI::TreeView>();
- auto& search_view = left_tab_bar.add_tab<GUI::Widget>("Search");
- search_view.set_layout<GUI::VerticalBoxLayout>();
- search_view.layout()->set_margins({ 4, 4, 4, 4 });
- auto& search_box = search_view.add<GUI::TextBox>();
- auto& search_list_view = search_view.add<GUI::ListView>();
- search_box.set_fixed_height(20);
- search_box.set_placeholder("Search...");
- search_box.on_change = [&] {
- if (auto model = search_list_view.model()) {
- auto& search_model = *static_cast<GUI::FilteringProxyModel*>(model);
- search_model.set_filter_term(search_box.text());
- search_model.update();
- }
- };
- search_list_view.set_model(GUI::FilteringProxyModel::construct(model));
- search_list_view.model()->update();
-
- tree_view.set_model(model);
- left_tab_bar.set_fixed_width(200);
-
- auto& page_view = splitter.add<Web::OutOfProcessWebView>();
-
- History history;
-
- RefPtr<GUI::Action> go_back_action;
- RefPtr<GUI::Action> go_forward_action;
-
- auto update_actions = [&]() {
- go_back_action->set_enabled(history.can_go_back());
- go_forward_action->set_enabled(history.can_go_forward());
- };
-
- auto open_page = [&](const String& path) {
- if (path.is_null()) {
- window->set_title("Help");
- page_view.load_empty_document();
- return;
- }
-
- auto source_result = model->page_view(path);
- if (source_result.is_error()) {
- GUI::MessageBox::show(window, source_result.error().string(), "Failed to open man page", GUI::MessageBox::Type::Error);
- return;
- }
-
- auto source = source_result.value();
- String html;
- {
- auto md_document = Markdown::Document::parse(source);
- ASSERT(md_document);
- html = md_document->render_to_html();
- }
-
- auto url = URL::create_with_file_protocol(path);
- page_view.load_html(html, url);
-
- auto tree_view_index = model->index_from_path(path);
- if (tree_view_index.has_value())
- tree_view.expand_tree(tree_view_index.value().parent());
-
- String page_and_section = model->page_and_section(tree_view_index.value());
- window->set_title(String::formatted("{} - Help", page_and_section));
- };
-
- tree_view.on_selection_change = [&] {
- String path = model->page_path(tree_view.selection().first());
- history.push(path);
- update_actions();
- open_page(path);
- };
-
- tree_view.on_toggle = [&](const GUI::ModelIndex& index, const bool open) {
- model->update_section_node_on_toggle(index, open);
- };
-
- auto open_external = [&](auto& url) {
- if (!Desktop::Launcher::open(url)) {
- GUI::MessageBox::show(window,
- String::formatted("The link to '{}' could not be opened.", url),
- "Failed to open link",
- GUI::MessageBox::Type::Error);
- }
- };
- search_list_view.on_selection = [&](auto index) {
- if (!index.is_valid())
- return;
-
- if (auto model = search_list_view.model()) {
- auto& search_model = *static_cast<GUI::FilteringProxyModel*>(model);
- index = search_model.map(index);
- } else {
- page_view.load_empty_document();
- return;
- }
- String path = model->page_path(index);
- if (path.is_null()) {
- page_view.load_empty_document();
- return;
- }
- tree_view.selection().clear();
- tree_view.selection().add(index);
- history.push(path);
- update_actions();
- open_page(path);
- };
-
- page_view.on_link_click = [&](auto& url, auto&, unsigned) {
- if (url.protocol() != "file") {
- open_external(url);
- return;
- }
- auto path = Core::File::real_path_for(url.path());
- if (!path.starts_with("/usr/share/man/")) {
- open_external(url);
- return;
- }
- auto tree_view_index = model->index_from_path(path);
- if (tree_view_index.has_value()) {
- dbgln("Found path _{}_ in model at index {}", path, tree_view_index.value());
- tree_view.selection().set(tree_view_index.value());
- return;
- }
- history.push(path);
- update_actions();
- open_page(path);
- };
-
- go_back_action = GUI::CommonActions::make_go_back_action([&](auto&) {
- history.go_back();
- update_actions();
- open_page(history.current());
- });
-
- go_forward_action = GUI::CommonActions::make_go_forward_action([&](auto&) {
- history.go_forward();
- update_actions();
- open_page(history.current());
- });
-
- go_back_action->set_enabled(false);
- go_forward_action->set_enabled(false);
-
- auto go_home_action = GUI::CommonActions::make_go_home_action([&](auto&) {
- String path = "/usr/share/man/man7/Help-index.md";
- history.push(path);
- update_actions();
- open_page(path);
- });
-
- toolbar.add_action(*go_back_action);
- toolbar.add_action(*go_forward_action);
- toolbar.add_action(*go_home_action);
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Help");
- app_menu.add_action(GUI::CommonActions::make_about_action("Help", app_icon, window));
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- }));
-
- auto& go_menu = menubar->add_menu("Go");
- go_menu.add_action(*go_back_action);
- go_menu.add_action(*go_forward_action);
- go_menu.add_action(*go_home_action);
-
- app->set_menubar(move(menubar));
-
- if (start_page) {
- URL url = URL::create_with_url_or_path(start_page);
- if (url.is_valid() && url.path().ends_with(".md")) {
- history.push(url.path());
- update_actions();
- open_page(url.path());
- } else {
- left_tab_bar.set_active_widget(&search_view);
- search_box.set_text(start_page);
- if (auto model = search_list_view.model()) {
- auto& search_model = *static_cast<GUI::FilteringProxyModel*>(model);
- search_model.set_filter_term(search_box.text());
- }
- }
- } else {
- go_home_action->activate();
- }
-
- window->set_focused_widget(&left_tab_bar);
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/HexEditor/CMakeLists.txt b/Applications/HexEditor/CMakeLists.txt
deleted file mode 100644
index ebe134863f..0000000000
--- a/Applications/HexEditor/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(SOURCES
- HexEditor.cpp
- HexEditorWidget.cpp
- main.cpp
-)
-
-serenity_app(HexEditor ICON app-hexeditor)
-target_link_libraries(HexEditor LibGUI)
diff --git a/Applications/HexEditor/HexEditor.cpp b/Applications/HexEditor/HexEditor.cpp
deleted file mode 100644
index f4999661f8..0000000000
--- a/Applications/HexEditor/HexEditor.cpp
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "HexEditor.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/ScrollBar.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/Palette.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-
-HexEditor::HexEditor()
-{
- set_focus_policy(GUI::FocusPolicy::StrongFocus);
- set_scrollbars_enabled(true);
- set_font(Gfx::FontDatabase::default_fixed_width_font());
- set_background_role(ColorRole::Base);
- set_foreground_role(ColorRole::BaseText);
- vertical_scrollbar().set_step(line_height());
-}
-
-HexEditor::~HexEditor()
-{
-}
-
-void HexEditor::set_readonly(bool readonly)
-{
- if (m_readonly == readonly)
- return;
- m_readonly = readonly;
-}
-
-void HexEditor::set_buffer(const ByteBuffer& buffer)
-{
- m_buffer = buffer;
- set_content_length(buffer.size());
- m_tracked_changes.clear();
- m_position = 0;
- m_byte_position = 0;
- update();
- update_status();
-}
-
-void HexEditor::fill_selection(u8 fill_byte)
-{
- if (!has_selection())
- return;
-
- for (int i = m_selection_start; i <= m_selection_end; i++) {
- m_tracked_changes.set(i, m_buffer.data()[i]);
- m_buffer.data()[i] = fill_byte;
- }
-
- update();
- did_change();
-}
-
-void HexEditor::set_position(int position)
-{
- if (position > static_cast<int>(m_buffer.size()))
- return;
-
- m_position = position;
- m_byte_position = 0;
- scroll_position_into_view(position);
- update_status();
-}
-
-bool HexEditor::write_to_file(const StringView& path)
-{
- if (m_buffer.is_empty())
- return true;
-
- int fd = open_with_path_length(path.characters_without_null_termination(), path.length(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- perror("open");
- return false;
- }
-
- int rc = ftruncate(fd, m_buffer.size());
- if (rc < 0) {
- perror("ftruncate");
- return false;
- }
-
- ssize_t nwritten = write(fd, m_buffer.data(), m_buffer.size());
- if (nwritten < 0) {
- perror("write");
- close(fd);
- return false;
- }
-
- if (static_cast<size_t>(nwritten) == m_buffer.size()) {
- m_tracked_changes.clear();
- update();
- }
-
- close(fd);
- return true;
-}
-
-bool HexEditor::copy_selected_hex_to_clipboard()
-{
- if (!has_selection())
- return false;
-
- StringBuilder output_string_builder;
- for (int i = m_selection_start; i <= m_selection_end; i++)
- output_string_builder.appendff("{:02X} ", m_buffer.data()[i]);
-
- GUI::Clipboard::the().set_plain_text(output_string_builder.to_string());
- return true;
-}
-
-bool HexEditor::copy_selected_text_to_clipboard()
-{
- if (!has_selection())
- return false;
-
- StringBuilder output_string_builder;
- for (int i = m_selection_start; i <= m_selection_end; i++)
- output_string_builder.append(isprint(m_buffer.data()[i]) ? m_buffer[i] : '.');
-
- GUI::Clipboard::the().set_plain_text(output_string_builder.to_string());
- return true;
-}
-
-bool HexEditor::copy_selected_hex_to_clipboard_as_c_code()
-{
- if (!has_selection())
- return false;
-
- StringBuilder output_string_builder;
- output_string_builder.appendff("unsigned char raw_data[{}] = {{\n", (m_selection_end - m_selection_start) + 1);
- output_string_builder.append(" ");
- for (int i = m_selection_start, j = 1; i <= m_selection_end; i++, j++) {
- output_string_builder.appendff("{:#02X}", m_buffer.data()[i]);
- if (i != m_selection_end)
- output_string_builder.append(", ");
- if ((j % 12) == 0) {
- output_string_builder.append("\n");
- output_string_builder.append(" ");
- }
- }
- output_string_builder.append("\n};\n");
-
- GUI::Clipboard::the().set_plain_text(output_string_builder.to_string());
- return true;
-}
-
-void HexEditor::set_bytes_per_row(int bytes_per_row)
-{
- m_bytes_per_row = bytes_per_row;
- set_content_size({ offset_margin_width() + (m_bytes_per_row * (character_width() * 3)) + 10 + (m_bytes_per_row * character_width()) + 20, total_rows() * line_height() + 10 });
- update();
-}
-
-void HexEditor::set_content_length(int length)
-{
- if (length == m_content_length)
- return;
- m_content_length = length;
- set_content_size({ offset_margin_width() + (m_bytes_per_row * (character_width() * 3)) + 10 + (m_bytes_per_row * character_width()) + 20, total_rows() * line_height() + 10 });
-}
-
-void HexEditor::mousedown_event(GUI::MouseEvent& event)
-{
- if (event.button() != GUI::MouseButton::Left) {
- return;
- }
-
- auto absolute_x = horizontal_scrollbar().value() + event.x();
- auto absolute_y = vertical_scrollbar().value() + event.y();
-
- auto hex_start_x = frame_thickness() + 90;
- auto hex_start_y = frame_thickness() + 5;
- auto hex_end_x = hex_start_x + (bytes_per_row() * (character_width() * 3));
- auto hex_end_y = hex_start_y + 5 + (total_rows() * line_height());
-
- auto text_start_x = frame_thickness() + 100 + (bytes_per_row() * (character_width() * 3));
- auto text_start_y = frame_thickness() + 5;
- auto text_end_x = text_start_x + (bytes_per_row() * character_width());
- auto text_end_y = text_start_y + 5 + (total_rows() * line_height());
-
- if (absolute_x >= hex_start_x && absolute_x <= hex_end_x && absolute_y >= hex_start_y && absolute_y <= hex_end_y) {
- auto byte_x = (absolute_x - hex_start_x) / (character_width() * 3);
- auto byte_y = (absolute_y - hex_start_y) / line_height();
- auto offset = (byte_y * m_bytes_per_row) + byte_x;
-
- if (offset < 0 || offset >= static_cast<int>(m_buffer.size()))
- return;
-
-#ifdef HEX_DEBUG
- outln("HexEditor::mousedown_event(hex): offset={}", offset);
-#endif
-
- m_edit_mode = EditMode::Hex;
- m_byte_position = 0;
- m_position = offset;
- m_in_drag_select = true;
- m_selection_start = offset;
- m_selection_end = offset;
- update();
- update_status();
- }
-
- if (absolute_x >= text_start_x && absolute_x <= text_end_x && absolute_y >= text_start_y && absolute_y <= text_end_y) {
- auto byte_x = (absolute_x - text_start_x) / character_width();
- auto byte_y = (absolute_y - text_start_y) / line_height();
- auto offset = (byte_y * m_bytes_per_row) + byte_x;
-
- if (offset < 0 || offset >= static_cast<int>(m_buffer.size()))
- return;
-
-#ifdef HEX_DEBUG
- outln("HexEditor::mousedown_event(text): offset={}", offset);
-#endif
-
- m_position = offset;
- m_byte_position = 0;
- m_in_drag_select = true;
- m_selection_start = offset;
- m_selection_end = offset;
- m_edit_mode = EditMode::Text;
- update();
- update_status();
- }
-}
-
-void HexEditor::mousemove_event(GUI::MouseEvent& event)
-{
- auto absolute_x = horizontal_scrollbar().value() + event.x();
- auto absolute_y = vertical_scrollbar().value() + event.y();
-
- auto hex_start_x = frame_thickness() + 90;
- auto hex_start_y = frame_thickness() + 5;
- auto hex_end_x = hex_start_x + (bytes_per_row() * (character_width() * 3));
- auto hex_end_y = hex_start_y + 5 + (total_rows() * line_height());
-
- auto text_start_x = frame_thickness() + 100 + (bytes_per_row() * (character_width() * 3));
- auto text_start_y = frame_thickness() + 5;
- auto text_end_x = text_start_x + (bytes_per_row() * character_width());
- auto text_end_y = text_start_y + 5 + (total_rows() * line_height());
-
- if ((absolute_x >= hex_start_x && absolute_x <= hex_end_x
- && absolute_y >= hex_start_y && absolute_y <= hex_end_y)
- || (absolute_x >= text_start_x && absolute_x <= text_end_x
- && absolute_y >= text_start_y && absolute_y <= text_end_y)) {
- set_override_cursor(Gfx::StandardCursor::IBeam);
- } else {
- set_override_cursor(Gfx::StandardCursor::None);
- }
-
- if (m_in_drag_select) {
- if (absolute_x >= hex_start_x && absolute_x <= hex_end_x && absolute_y >= hex_start_y && absolute_y <= hex_end_y) {
- auto byte_x = (absolute_x - hex_start_x) / (character_width() * 3);
- auto byte_y = (absolute_y - hex_start_y) / line_height();
- auto offset = (byte_y * m_bytes_per_row) + byte_x;
-
- if (offset < 0 || offset > static_cast<int>(m_buffer.size()))
- return;
-
- m_selection_end = offset;
- scroll_position_into_view(offset);
- }
-
- if (absolute_x >= text_start_x && absolute_x <= text_end_x && absolute_y >= text_start_y && absolute_y <= text_end_y) {
- auto byte_x = (absolute_x - text_start_x) / character_width();
- auto byte_y = (absolute_y - text_start_y) / line_height();
- auto offset = (byte_y * m_bytes_per_row) + byte_x;
- if (offset < 0 || offset > static_cast<int>(m_buffer.size()))
- return;
-
- m_selection_end = offset;
- scroll_position_into_view(offset);
- }
- update_status();
- update();
- return;
- }
-}
-
-void HexEditor::mouseup_event(GUI::MouseEvent& event)
-{
- if (event.button() == GUI::MouseButton::Left) {
- if (m_in_drag_select) {
- if (m_selection_end < m_selection_start) {
- // lets flip these around
- auto start = m_selection_end;
- m_selection_end = m_selection_start;
- m_selection_start = start;
- }
- m_in_drag_select = false;
- }
- update();
- update_status();
- }
-}
-
-void HexEditor::scroll_position_into_view(int position)
-{
- int y = position / bytes_per_row();
- int x = position % bytes_per_row();
- Gfx::IntRect rect {
- frame_thickness() + offset_margin_width() + (x * (character_width() * 3)) + 10,
- frame_thickness() + 5 + (y * line_height()),
- (character_width() * 3),
- line_height() - m_line_spacing
- };
- scroll_into_view(rect, true, true);
-}
-
-void HexEditor::keydown_event(GUI::KeyEvent& event)
-{
-#ifdef HEX_DEBUG
- outln("HexEditor::keydown_event key={}", static_cast<u8>(event.key()));
-#endif
-
- if (event.key() == KeyCode::Key_Up) {
- if (m_position - bytes_per_row() >= 0) {
- m_position -= bytes_per_row();
- m_byte_position = 0;
- scroll_position_into_view(m_position);
- update();
- update_status();
- }
- return;
- }
-
- if (event.key() == KeyCode::Key_Down) {
- if (m_position + bytes_per_row() < static_cast<int>(m_buffer.size())) {
- m_position += bytes_per_row();
- m_byte_position = 0;
- scroll_position_into_view(m_position);
- update();
- update_status();
- }
- return;
- }
-
- if (event.key() == KeyCode::Key_Left) {
- if (m_position - 1 >= 0) {
- m_position--;
- m_byte_position = 0;
- scroll_position_into_view(m_position);
- update();
- update_status();
- }
- return;
- }
-
- if (event.key() == KeyCode::Key_Right) {
- if (m_position + 1 < static_cast<int>(m_buffer.size())) {
- m_position++;
- m_byte_position = 0;
- scroll_position_into_view(m_position);
- update();
- update_status();
- }
- return;
- }
-
- if (event.key() == KeyCode::Key_Backspace) {
- if (m_position > 0) {
- m_position--;
- m_byte_position = 0;
- scroll_position_into_view(m_position);
- update();
- update_status();
- }
- return;
- }
-
- if (!is_readonly() && !event.ctrl() && !event.alt() && !event.text().is_empty()) {
- if (m_edit_mode == EditMode::Hex) {
- hex_mode_keydown_event(event);
- } else {
- text_mode_keydown_event(event);
- }
- }
-}
-
-void HexEditor::hex_mode_keydown_event(GUI::KeyEvent& event)
-{
- if ((event.key() >= KeyCode::Key_0 && event.key() <= KeyCode::Key_9) || (event.key() >= KeyCode::Key_A && event.key() <= KeyCode::Key_F)) {
- if (m_buffer.is_empty())
- return;
- ASSERT(m_position >= 0);
- ASSERT(m_position < static_cast<int>(m_buffer.size()));
-
- // yes, this is terrible... but it works.
- auto value = (event.key() >= KeyCode::Key_0 && event.key() <= KeyCode::Key_9)
- ? event.key() - KeyCode::Key_0
- : (event.key() - KeyCode::Key_A) + 0xA;
-
- if (m_byte_position == 0) {
- m_tracked_changes.set(m_position, m_buffer.data()[m_position]);
- m_buffer.data()[m_position] = value << 4 | (m_buffer.data()[m_position] & 0xF); // shift new value left 4 bits, OR with existing last 4 bits
- m_byte_position++;
- } else {
- m_buffer.data()[m_position] = (m_buffer.data()[m_position] & 0xF0) | value; // save the first 4 bits, OR the new value in the last 4
- if (m_position + 1 < static_cast<int>(m_buffer.size()))
- m_position++;
- m_byte_position = 0;
- }
-
- update();
- update_status();
- did_change();
- }
-}
-
-void HexEditor::text_mode_keydown_event(GUI::KeyEvent& event)
-{
- if (m_buffer.is_empty())
- return;
- ASSERT(m_position >= 0);
- ASSERT(m_position < static_cast<int>(m_buffer.size()));
-
- if (event.code_point() == 0) // This is a control key
- return;
-
- m_tracked_changes.set(m_position, m_buffer.data()[m_position]);
- m_buffer.data()[m_position] = event.code_point();
- if (m_position + 1 < static_cast<int>(m_buffer.size()))
- m_position++;
- m_byte_position = 0;
-
- update();
- update_status();
- did_change();
-}
-
-void HexEditor::update_status()
-{
- if (on_status_change)
- on_status_change(m_position, m_edit_mode, m_selection_start, m_selection_end);
-}
-
-void HexEditor::did_change()
-{
- if (on_change)
- on_change();
-}
-
-void HexEditor::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(widget_inner_rect());
- painter.add_clip_rect(event.rect());
- painter.fill_rect(event.rect(), palette().color(background_role()));
-
- if (m_buffer.is_empty())
- return;
-
- painter.translate(frame_thickness(), frame_thickness());
- painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
-
- Gfx::IntRect offset_clip_rect {
- 0,
- vertical_scrollbar().value(),
- 85,
- height() - height_occupied_by_horizontal_scrollbar() //(total_rows() * line_height()) + 5
- };
- painter.fill_rect(offset_clip_rect, palette().ruler());
- painter.draw_line(offset_clip_rect.top_right(), offset_clip_rect.bottom_right(), palette().ruler_border());
-
- auto margin_and_hex_width = offset_margin_width() + (m_bytes_per_row * (character_width() * 3)) + 15;
- painter.draw_line({ margin_and_hex_width, 0 },
- { margin_and_hex_width, vertical_scrollbar().value() + (height() - height_occupied_by_horizontal_scrollbar()) },
- palette().ruler_border());
-
- auto view_height = (height() - height_occupied_by_horizontal_scrollbar());
- auto min_row = max(0, vertical_scrollbar().value() / line_height()); // if below 0 then use 0
- auto max_row = min(total_rows(), min_row + ceil_div(view_height, line_height())); // if above calculated rows, use calculated rows
-
- // paint offsets
- for (int i = min_row; i < max_row; i++) {
- Gfx::IntRect side_offset_rect {
- frame_thickness() + 5,
- frame_thickness() + 5 + (i * line_height()),
- width() - width_occupied_by_vertical_scrollbar(),
- height() - height_occupied_by_horizontal_scrollbar()
- };
-
- bool is_current_line = (m_position / bytes_per_row()) == i;
- auto line = String::formatted("{:#08X}", i * bytes_per_row());
- painter.draw_text(
- side_offset_rect,
- line,
- is_current_line ? Gfx::FontDatabase::default_bold_font() : font(),
- Gfx::TextAlignment::TopLeft,
- is_current_line ? palette().ruler_active_text() : palette().ruler_inactive_text());
- }
-
- for (int i = min_row; i < max_row; i++) {
- for (int j = 0; j < bytes_per_row(); j++) {
- auto byte_position = (i * bytes_per_row()) + j;
- if (byte_position >= static_cast<int>(m_buffer.size()))
- return;
-
- Color text_color = palette().color(foreground_role());
- if (m_tracked_changes.contains(byte_position)) {
- text_color = Color::Red;
- }
-
- auto highlight_flag = false;
- if (m_selection_start > -1 && m_selection_end > -1) {
- if (byte_position >= m_selection_start && byte_position <= m_selection_end) {
- highlight_flag = true;
- }
- if (byte_position >= m_selection_end && byte_position <= m_selection_start) {
- highlight_flag = true;
- }
- }
-
- Gfx::IntRect hex_display_rect {
- frame_thickness() + offset_margin_width() + (j * (character_width() * 3)) + 10,
- frame_thickness() + 5 + (i * line_height()),
- (character_width() * 3),
- line_height() - m_line_spacing
- };
- if (highlight_flag) {
- painter.fill_rect(hex_display_rect, palette().selection());
- text_color = text_color == Color::Red ? Color::from_rgb(0xFFC0CB) : palette().selection_text();
- } else if (byte_position == m_position) {
- painter.fill_rect(hex_display_rect, palette().inactive_selection());
- text_color = palette().inactive_selection_text();
- }
-
- auto line = String::formatted("{:02X}", m_buffer[byte_position]);
- painter.draw_text(hex_display_rect, line, Gfx::TextAlignment::TopLeft, text_color);
-
- Gfx::IntRect text_display_rect {
- frame_thickness() + offset_margin_width() + (bytes_per_row() * (character_width() * 3)) + (j * character_width()) + 20,
- frame_thickness() + 5 + (i * line_height()),
- character_width(),
- line_height() - m_line_spacing
- };
- // selection highlighting.
- if (highlight_flag) {
- painter.fill_rect(text_display_rect, palette().selection());
- } else if (byte_position == m_position) {
- painter.fill_rect(text_display_rect, palette().inactive_selection());
- }
-
- painter.draw_text(text_display_rect, String::formatted("{:c}", isprint(m_buffer[byte_position]) ? m_buffer[byte_position] : '.'), Gfx::TextAlignment::TopLeft, text_color);
- }
- }
-}
diff --git a/Applications/HexEditor/HexEditor.h b/Applications/HexEditor/HexEditor.h
deleted file mode 100644
index e47eedeec3..0000000000
--- a/Applications/HexEditor/HexEditor.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/ByteBuffer.h>
-#include <AK/Function.h>
-#include <AK/HashMap.h>
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/NonnullRefPtrVector.h>
-#include <AK/StdLibExtras.h>
-#include <LibGUI/ScrollableWidget.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/TextAlignment.h>
-
-class HexEditor : public GUI::ScrollableWidget {
- C_OBJECT(HexEditor)
-public:
- enum EditMode {
- Hex,
- Text
- };
-
- virtual ~HexEditor() override;
-
- bool is_readonly() const { return m_readonly; }
- void set_readonly(bool);
-
- void set_buffer(const ByteBuffer&);
- void fill_selection(u8 fill_byte);
- bool write_to_file(const StringView& path);
-
- bool has_selection() const { return !(m_selection_start == -1 || m_selection_end == -1 || (m_selection_end - m_selection_start) < 0 || m_buffer.is_empty()); }
- bool copy_selected_text_to_clipboard();
- bool copy_selected_hex_to_clipboard();
- bool copy_selected_hex_to_clipboard_as_c_code();
-
- int bytes_per_row() const { return m_bytes_per_row; }
- void set_bytes_per_row(int);
-
- void set_position(int position);
-
- Function<void(int, EditMode, int, int)> on_status_change; // position, edit mode, selection start, selection end
- Function<void()> on_change;
-
-protected:
- HexEditor();
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void keydown_event(GUI::KeyEvent&) override;
-
-private:
- bool m_readonly { false };
- int m_line_spacing { 4 };
- int m_content_length { 0 };
- int m_bytes_per_row { 16 };
- ByteBuffer m_buffer;
- bool m_in_drag_select { false };
- int m_selection_start { 0 };
- int m_selection_end { 0 };
- HashMap<int, u8> m_tracked_changes;
- int m_position { 0 };
- int m_byte_position { 0 }; // 0 or 1
- EditMode m_edit_mode { Hex };
-
- void scroll_position_into_view(int position);
-
- int total_rows() const { return ceil_div(m_content_length, m_bytes_per_row); }
- int line_height() const { return font().glyph_height() + m_line_spacing; }
- int character_width() const { return font().glyph_width('W'); }
- int offset_margin_width() const { return 80; }
-
- void hex_mode_keydown_event(GUI::KeyEvent&);
- void text_mode_keydown_event(GUI::KeyEvent&);
-
- void set_content_length(int); // I might make this public if I add fetching data on demand.
- void update_status();
- void did_change();
-};
diff --git a/Applications/HexEditor/HexEditorWidget.cpp b/Applications/HexEditor/HexEditorWidget.cpp
deleted file mode 100644
index e6f6711884..0000000000
--- a/Applications/HexEditor/HexEditorWidget.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "HexEditorWidget.h"
-#include <AK/Optional.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/File.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/StatusBar.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/ToolBar.h>
-#include <stdio.h>
-#include <string.h>
-
-HexEditorWidget::HexEditorWidget()
-{
- set_fill_with_background_color(true);
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_spacing(2);
-
- m_editor = add<HexEditor>();
-
- m_editor->on_status_change = [this](int position, HexEditor::EditMode edit_mode, int selection_start, int selection_end) {
- m_statusbar->set_text(0, String::formatted("Offset: {:#08X}", position));
- m_statusbar->set_text(1, String::formatted("Edit Mode: {}", edit_mode == HexEditor::EditMode::Hex ? "Hex" : "Text"));
- m_statusbar->set_text(2, String::formatted("Selection Start: {}", selection_start));
- m_statusbar->set_text(3, String::formatted("Selection End: {}", selection_end));
- m_statusbar->set_text(4, String::formatted("Selected Bytes: {}", abs(selection_end - selection_start) + 1));
- };
-
- m_editor->on_change = [this] {
- bool was_dirty = m_document_dirty;
- m_document_dirty = true;
- if (!was_dirty)
- update_title();
- };
-
- m_statusbar = add<GUI::StatusBar>(5);
-
- m_new_action = GUI::Action::create("New", { Mod_Ctrl, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new.png"), [this](const GUI::Action&) {
- if (m_document_dirty) {
- if (GUI::MessageBox::show(window(), "Save changes to current file first?", "Warning", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OKCancel) != GUI::Dialog::ExecResult::ExecOK)
- return;
- m_save_action->activate();
- }
-
- String value;
- if (GUI::InputBox::show(value, window(), "Enter new file size:", "New file size") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto file_size = value.to_int();
- if (file_size.has_value() && file_size.value() > 0) {
- m_document_dirty = false;
- m_editor->set_buffer(ByteBuffer::create_zeroed(file_size.value()));
- set_path(LexicalPath());
- update_title();
- } else {
- GUI::MessageBox::show(window(), "Invalid file size entered.", "Error", GUI::MessageBox::Type::Error);
- }
- }
- });
-
- m_open_action = GUI::CommonActions::make_open_action([this](auto&) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(window());
-
- if (!open_path.has_value())
- return;
-
- open_file(open_path.value());
- });
-
- m_save_action = GUI::CommonActions::make_save_action([&](auto&) {
- if (!m_path.is_empty()) {
- if (!m_editor->write_to_file(m_path)) {
- GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
- } else {
- m_document_dirty = false;
- update_title();
- }
- return;
- }
-
- m_save_as_action->activate();
- });
-
- m_save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window(), m_name.is_null() ? "Untitled" : m_name, m_extension.is_null() ? "bin" : m_extension);
- if (!save_path.has_value())
- return;
-
- if (!m_editor->write_to_file(save_path.value())) {
- GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_document_dirty = false;
- set_path(LexicalPath(save_path.value()));
- dbgln("Wrote document to {}", save_path.value());
- });
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Hex Editor");
- app_menu.add_action(*m_new_action);
- app_menu.add_action(*m_open_action);
- app_menu.add_action(*m_save_action);
- app_menu.add_action(*m_save_as_action);
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([this](auto&) {
- if (!request_close())
- return;
- GUI::Application::the()->quit();
- }));
-
- m_goto_decimal_offset_action = GUI::Action::create("Go To Offset (Decimal)...", { Mod_Ctrl | Mod_Shift, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"), [this](const GUI::Action&) {
- String value;
- if (GUI::InputBox::show(value, window(), "Enter Decimal offset:", "Go To") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto new_offset = value.to_int();
- if (new_offset.has_value())
- m_editor->set_position(new_offset.value());
- }
- });
-
- m_goto_hex_offset_action = GUI::Action::create("Go To Offset (Hex)...", { Mod_Ctrl, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"), [this](const GUI::Action&) {
- String value;
- if (GUI::InputBox::show(value, window(), "Enter Hex offset:", "Go To") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto new_offset = strtol(value.characters(), nullptr, 16);
- m_editor->set_position(new_offset);
- }
- });
-
- auto& edit_menu = menubar->add_menu("Edit");
- edit_menu.add_action(GUI::Action::create("Fill selection...", { Mod_Ctrl, Key_B }, [&](const GUI::Action&) {
- String value;
- if (GUI::InputBox::show(value, window(), "Fill byte (hex):", "Fill Selection") == GUI::InputBox::ExecOK && !value.is_empty()) {
- auto fill_byte = strtol(value.characters(), nullptr, 16);
- m_editor->fill_selection(fill_byte);
- }
- }));
- edit_menu.add_separator();
- edit_menu.add_action(*m_goto_decimal_offset_action);
- edit_menu.add_action(*m_goto_hex_offset_action);
- edit_menu.add_separator();
- edit_menu.add_action(GUI::Action::create("Copy Hex", { Mod_Ctrl, Key_C }, [&](const GUI::Action&) {
- m_editor->copy_selected_hex_to_clipboard();
- }));
- edit_menu.add_action(GUI::Action::create("Copy Text", { Mod_Ctrl | Mod_Shift, Key_C }, [&](const GUI::Action&) {
- m_editor->copy_selected_text_to_clipboard();
- }));
- edit_menu.add_separator();
- edit_menu.add_action(GUI::Action::create("Copy As C Code", { Mod_Alt | Mod_Shift, Key_C }, [&](const GUI::Action&) {
- m_editor->copy_selected_hex_to_clipboard_as_c_code();
- }));
-
- auto& view_menu = menubar->add_menu("View");
- auto& bytes_per_row_menu = view_menu.add_submenu("Bytes per row");
- for (int i = 8; i <= 32; i += 8) {
- bytes_per_row_menu.add_action(GUI::Action::create(String::number(i), [this, i](auto&) {
- m_editor->set_bytes_per_row(i);
- m_editor->update();
- }));
- }
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Hex Editor", GUI::Icon::default_icon("Hex Editor"), window()));
-
- GUI::Application::the()->set_menubar(move(menubar));
-
- m_editor->set_focus(true);
-}
-
-HexEditorWidget::~HexEditorWidget()
-{
-}
-
-void HexEditorWidget::set_path(const LexicalPath& lexical_path)
-{
- m_path = lexical_path.string();
- m_name = lexical_path.title();
- m_extension = lexical_path.extension();
- update_title();
-}
-
-void HexEditorWidget::update_title()
-{
- StringBuilder builder;
- builder.append(m_path);
- if (m_document_dirty)
- builder.append(" (*)");
- builder.append(" - Hex Editor");
- window()->set_title(builder.to_string());
-}
-
-void HexEditorWidget::open_file(const String& path)
-{
- auto file = Core::File::construct(path);
- if (!file->open(Core::IODevice::ReadOnly)) {
- GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: {}", path, strerror(errno)), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_document_dirty = false;
- m_editor->set_buffer(file->read_all()); // FIXME: On really huge files, this is never going to work. Should really create a framework to fetch data from the file on-demand.
- set_path(LexicalPath(path));
-}
-
-bool HexEditorWidget::request_close()
-{
- if (!m_document_dirty)
- return true;
- auto result = GUI::MessageBox::show(window(), "The file has been modified. Quit without saving?", "Quit without saving?", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::OKCancel);
- return result == GUI::MessageBox::ExecOK;
-}
diff --git a/Applications/HexEditor/HexEditorWidget.h b/Applications/HexEditor/HexEditorWidget.h
deleted file mode 100644
index 55152518ab..0000000000
--- a/Applications/HexEditor/HexEditorWidget.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "HexEditor.h"
-#include <AK/Function.h>
-#include <AK/LexicalPath.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-
-class HexEditor;
-
-class HexEditorWidget final : public GUI::Widget {
- C_OBJECT(HexEditorWidget)
-public:
- virtual ~HexEditorWidget() override;
- void open_file(const String& path);
- bool request_close();
-
-private:
- HexEditorWidget();
- void set_path(const LexicalPath& file);
- void update_title();
-
- RefPtr<HexEditor> m_editor;
- String m_path;
- String m_name;
- String m_extension;
- RefPtr<GUI::Action> m_new_action;
- RefPtr<GUI::Action> m_open_action;
- RefPtr<GUI::Action> m_save_action;
- RefPtr<GUI::Action> m_save_as_action;
- RefPtr<GUI::Action> m_goto_decimal_offset_action;
- RefPtr<GUI::Action> m_goto_hex_offset_action;
-
- RefPtr<GUI::StatusBar> m_statusbar;
-
- bool m_document_dirty { false };
-};
diff --git a/Applications/HexEditor/main.cpp b/Applications/HexEditor/main.cpp
deleted file mode 100644
index 65e358726e..0000000000
--- a/Applications/HexEditor/main.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "HexEditorWidget.h"
-#include <LibGUI/Icon.h>
-#include <LibGfx/Bitmap.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept rpath unix cpath wpath fattr thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept rpath cpath wpath thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-hexeditor");
-
- auto window = GUI::Window::construct();
- window->set_title("Hex Editor");
- window->resize(640, 400);
-
- auto& hex_editor_widget = window->set_main_widget<HexEditorWidget>();
-
- window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
- if (hex_editor_widget.request_close())
- return GUI::Window::CloseRequestDecision::Close;
- return GUI::Window::CloseRequestDecision::StayOpen;
- };
-
- window->show();
- window->set_icon(app_icon.bitmap_for_size(16));
-
- if (argc >= 2)
- hex_editor_widget.open_file(argv[1]);
-
- return app->exec();
-}
diff --git a/Applications/IRCClient/CMakeLists.txt b/Applications/IRCClient/CMakeLists.txt
deleted file mode 100644
index 3926bbd5dc..0000000000
--- a/Applications/IRCClient/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-set(SOURCES
- IRCAppWindow.cpp
- IRCChannel.cpp
- IRCChannelMemberListModel.cpp
- IRCClient.cpp
- IRCLogBuffer.cpp
- IRCQuery.cpp
- IRCWindow.cpp
- IRCWindowListModel.cpp
- main.cpp
-)
-
-serenity_app(IRCClient ICON app-irc-client)
-target_link_libraries(IRCClient LibWeb LibGUI)
diff --git a/Applications/IRCClient/IRCAppWindow.cpp b/Applications/IRCClient/IRCAppWindow.cpp
deleted file mode 100644
index 8d4f931025..0000000000
--- a/Applications/IRCClient/IRCAppWindow.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCAppWindow.h"
-#include "IRCChannel.h"
-#include "IRCWindow.h"
-#include "IRCWindowListModel.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/StackWidget.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-
-static IRCAppWindow* s_the;
-
-IRCAppWindow& IRCAppWindow::the()
-{
- return *s_the;
-}
-
-IRCAppWindow::IRCAppWindow(String server, int port)
- : m_client(IRCClient::construct(server, port))
-{
- ASSERT(!s_the);
- s_the = this;
-
- set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-irc-client.png"));
-
- update_title();
- resize(600, 400);
- setup_actions();
- setup_menus();
- setup_widgets();
-
- setup_client();
-}
-
-IRCAppWindow::~IRCAppWindow()
-{
-}
-
-void IRCAppWindow::update_title()
-{
- set_title(String::formatted("{}@{}:{} - IRC Client", m_client->nickname(), m_client->hostname(), m_client->port()));
-}
-
-void IRCAppWindow::setup_client()
-{
- m_client->aid_create_window = [this](void* owner, IRCWindow::Type type, const String& name) {
- return create_window(owner, type, name);
- };
- m_client->aid_get_active_window = [this] {
- return static_cast<IRCWindow*>(m_container->active_widget());
- };
- m_client->aid_update_window_list = [this] {
- m_window_list->model()->update();
- };
- m_client->on_nickname_changed = [this](const String&) {
- update_title();
- };
- m_client->on_part_from_channel = [this](auto&) {
- update_gui_actions();
- };
-
- if (m_client->hostname().is_empty()) {
- String value;
- if (GUI::InputBox::show(value, this, "Enter server:", "Connect to server") == GUI::InputBox::ExecCancel)
- ::exit(0);
-
- m_client->set_server(value, 6667);
- }
- update_title();
- bool success = m_client->connect();
- ASSERT(success);
-}
-
-void IRCAppWindow::setup_actions()
-{
- m_join_action = GUI::Action::create("Join channel", { Mod_Ctrl, Key_J }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-join.png"), [&](auto&) {
- String value;
- if (GUI::InputBox::show(value, this, "Enter channel name:", "Join channel") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_join_action(value);
- });
-
- m_list_channels_action = GUI::Action::create("List channels", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-list.png"), [&](auto&) {
- m_client->handle_list_channels_action();
- });
-
- m_part_action = GUI::Action::create("Part from channel", { Mod_Ctrl, Key_P }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-part.png"), [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- m_client->handle_part_action(window->channel().name());
- });
-
- m_whois_action = GUI::Action::create("Whois user", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-whois.png"), [&](auto&) {
- String value;
- if (GUI::InputBox::show(value, this, "Enter nickname:", "IRC WHOIS lookup") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_whois_action(value);
- });
-
- m_open_query_action = GUI::Action::create("Open query", { Mod_Ctrl, Key_O }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-open-query.png"), [&](auto&) {
- String value;
- if (GUI::InputBox::show(value, this, "Enter nickname:", "Open IRC query with...") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_open_query_action(value);
- });
-
- m_close_query_action = GUI::Action::create("Close query", { Mod_Ctrl, Key_D }, Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-close-query.png"), [](auto&) {
- outln("FIXME: Implement close-query action");
- });
-
- m_change_nick_action = GUI::Action::create("Change nickname", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-nick.png"), [this](auto&) {
- String value;
- if (GUI::InputBox::show(value, this, "Enter nickname:", "Change nickname") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_change_nick_action(value);
- });
-
- m_change_topic_action = GUI::Action::create("Change topic", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-topic.png"), [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter topic:", "Change topic") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_change_topic_action(window->channel().name(), value);
- });
-
- m_invite_user_action = GUI::Action::create("Invite user", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-invite.png"), [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "Invite user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_invite_user_action(window->channel().name(), value);
- });
-
- m_banlist_action = GUI::Action::create("Ban list", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- m_client->handle_banlist_action(window->channel().name());
- });
-
- m_voice_user_action = GUI::Action::create("Voice user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "Voice user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_voice_user_action(window->channel().name(), value);
- });
-
- m_devoice_user_action = GUI::Action::create("DeVoice user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "DeVoice user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_devoice_user_action(window->channel().name(), value);
- });
-
- m_hop_user_action = GUI::Action::create("Hop user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "Hop user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_hop_user_action(window->channel().name(), value);
- });
-
- m_dehop_user_action = GUI::Action::create("DeHop user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "DeHop user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_dehop_user_action(window->channel().name(), value);
- });
-
- m_op_user_action = GUI::Action::create("Op user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "Op user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_op_user_action(window->channel().name(), value);
- });
-
- m_deop_user_action = GUI::Action::create("DeOp user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String value;
- if (GUI::InputBox::show(value, this, "Enter nick:", "DeOp user") == GUI::InputBox::ExecOK && !value.is_empty())
- m_client->handle_deop_user_action(window->channel().name(), value);
- });
-
- m_kick_user_action = GUI::Action::create("Kick user", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- String nick_value;
- if (GUI::InputBox::show(nick_value, this, "Enter nick:", "Kick user") != GUI::InputBox::ExecOK || nick_value.is_empty())
- return;
- String reason_value;
- if (GUI::InputBox::show(reason_value, this, "Enter reason:", "Reason") == GUI::InputBox::ExecOK)
- m_client->handle_kick_user_action(window->channel().name(), nick_value, reason_value.characters());
- });
-
- m_cycle_channel_action = GUI::Action::create("Cycle channel", [this](auto&) {
- auto* window = m_client->current_window();
- if (!window || window->type() != IRCWindow::Type::Channel) {
- return;
- }
- m_client->handle_cycle_channel_action(window->channel().name());
- });
-}
-
-void IRCAppWindow::setup_menus()
-{
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("IRC Client");
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- dbgln("Terminal: Quit menu activated!");
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& server_menu = menubar->add_menu("Server");
- server_menu.add_action(*m_change_nick_action);
- server_menu.add_separator();
- server_menu.add_action(*m_join_action);
- server_menu.add_action(*m_list_channels_action);
- server_menu.add_separator();
- server_menu.add_action(*m_whois_action);
- server_menu.add_action(*m_open_query_action);
- server_menu.add_action(*m_close_query_action);
-
- auto& channel_menu = menubar->add_menu("Channel");
- channel_menu.add_action(*m_change_topic_action);
- channel_menu.add_action(*m_invite_user_action);
- channel_menu.add_action(*m_banlist_action);
-
- auto& channel_control_menu = channel_menu.add_submenu("Control");
- channel_control_menu.add_action(*m_voice_user_action);
- channel_control_menu.add_action(*m_devoice_user_action);
- channel_control_menu.add_action(*m_hop_user_action);
- channel_control_menu.add_action(*m_dehop_user_action);
- channel_control_menu.add_action(*m_op_user_action);
- channel_control_menu.add_action(*m_deop_user_action);
- channel_control_menu.add_separator();
- channel_control_menu.add_action(*m_kick_user_action);
-
- channel_menu.add_separator();
- channel_menu.add_action(*m_cycle_channel_action);
- channel_menu.add_action(*m_part_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("IRC Client", GUI::Icon::default_icon("app-irc-client"), this));
-
- GUI::Application::the()->set_menubar(move(menubar));
-}
-
-void IRCAppWindow::setup_widgets()
-{
- auto& widget = set_main_widget<GUI::Widget>();
- widget.set_fill_with_background_color(true);
- widget.set_layout<GUI::VerticalBoxLayout>();
- widget.layout()->set_spacing(0);
-
- auto& toolbar_container = widget.add<GUI::ToolBarContainer>();
- auto& toolbar = toolbar_container.add<GUI::ToolBar>();
- toolbar.set_has_frame(false);
- toolbar.add_action(*m_change_nick_action);
- toolbar.add_separator();
- toolbar.add_action(*m_join_action);
- toolbar.add_action(*m_part_action);
- toolbar.add_separator();
- toolbar.add_action(*m_whois_action);
- toolbar.add_action(*m_open_query_action);
- toolbar.add_action(*m_close_query_action);
-
- auto& outer_container = widget.add<GUI::Widget>();
- outer_container.set_layout<GUI::VerticalBoxLayout>();
- outer_container.layout()->set_margins({ 2, 0, 2, 2 });
-
- auto& horizontal_container = outer_container.add<GUI::HorizontalSplitter>();
-
- m_window_list = horizontal_container.add<GUI::TableView>();
- m_window_list->set_column_headers_visible(false);
- m_window_list->set_alternating_row_colors(false);
- m_window_list->set_model(m_client->client_window_list_model());
- m_window_list->set_activates_on_selection(true);
- m_window_list->set_fixed_width(100);
- m_window_list->on_activation = [this](auto& index) {
- set_active_window(m_client->window_at(index.row()));
- };
-
- m_container = horizontal_container.add<GUI::StackWidget>();
- m_container->on_active_widget_change = [this](auto*) {
- update_gui_actions();
- };
-
- create_window(&m_client, IRCWindow::Server, "Server");
-}
-
-void IRCAppWindow::set_active_window(IRCWindow& window)
-{
- m_container->set_active_widget(&window);
- window.clear_unread_count();
- auto index = m_window_list->model()->index(m_client->window_index(window));
- m_window_list->selection().set(index);
-}
-
-void IRCAppWindow::update_gui_actions()
-{
- auto* window = static_cast<IRCWindow*>(m_container->active_widget());
- bool is_open_channel = window && window->type() == IRCWindow::Type::Channel && window->channel().is_open();
- m_change_topic_action->set_enabled(is_open_channel);
- m_invite_user_action->set_enabled(is_open_channel);
- m_banlist_action->set_enabled(is_open_channel);
- m_voice_user_action->set_enabled(is_open_channel);
- m_devoice_user_action->set_enabled(is_open_channel);
- m_hop_user_action->set_enabled(is_open_channel);
- m_dehop_user_action->set_enabled(is_open_channel);
- m_op_user_action->set_enabled(is_open_channel);
- m_deop_user_action->set_enabled(is_open_channel);
- m_kick_user_action->set_enabled(is_open_channel);
- m_cycle_channel_action->set_enabled(is_open_channel);
- m_part_action->set_enabled(is_open_channel);
-}
-
-NonnullRefPtr<IRCWindow> IRCAppWindow::create_window(void* owner, IRCWindow::Type type, const String& name)
-{
- return m_container->add<IRCWindow>(m_client, owner, type, name);
-}
diff --git a/Applications/IRCClient/IRCAppWindow.h b/Applications/IRCClient/IRCAppWindow.h
deleted file mode 100644
index 10f0f5a4ee..0000000000
--- a/Applications/IRCClient/IRCAppWindow.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "IRCClient.h"
-#include "IRCWindow.h"
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-
-class IRCAppWindow : public GUI::Window {
- C_OBJECT(IRCAppWindow);
-
-public:
- virtual ~IRCAppWindow() override;
-
- static IRCAppWindow& the();
-
- void set_active_window(IRCWindow&);
-
-private:
- IRCAppWindow(String server, int port);
-
- void setup_client();
- void setup_actions();
- void setup_menus();
- void setup_widgets();
- void update_title();
- void update_gui_actions();
-
- NonnullRefPtr<IRCWindow> create_window(void* owner, IRCWindow::Type, const String& name);
- NonnullRefPtr<IRCClient> m_client;
- RefPtr<GUI::StackWidget> m_container;
- RefPtr<GUI::TableView> m_window_list;
- RefPtr<GUI::Action> m_join_action;
- RefPtr<GUI::Action> m_list_channels_action;
- RefPtr<GUI::Action> m_part_action;
- RefPtr<GUI::Action> m_cycle_channel_action;
- RefPtr<GUI::Action> m_whois_action;
- RefPtr<GUI::Action> m_open_query_action;
- RefPtr<GUI::Action> m_close_query_action;
- RefPtr<GUI::Action> m_change_nick_action;
- RefPtr<GUI::Action> m_change_topic_action;
- RefPtr<GUI::Action> m_invite_user_action;
- RefPtr<GUI::Action> m_banlist_action;
- RefPtr<GUI::Action> m_voice_user_action;
- RefPtr<GUI::Action> m_devoice_user_action;
- RefPtr<GUI::Action> m_hop_user_action;
- RefPtr<GUI::Action> m_dehop_user_action;
- RefPtr<GUI::Action> m_op_user_action;
- RefPtr<GUI::Action> m_deop_user_action;
- RefPtr<GUI::Action> m_kick_user_action;
-};
diff --git a/Applications/IRCClient/IRCChannel.cpp b/Applications/IRCClient/IRCChannel.cpp
deleted file mode 100644
index 81d9173e31..0000000000
--- a/Applications/IRCClient/IRCChannel.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCChannel.h"
-#include "IRCChannelMemberListModel.h"
-#include "IRCClient.h"
-#include <stdio.h>
-
-IRCChannel::IRCChannel(IRCClient& client, const String& name)
- : m_client(client)
- , m_name(name)
- , m_log(IRCLogBuffer::create())
- , m_member_model(IRCChannelMemberListModel::create(*this))
-{
- m_window = m_client.aid_create_window(this, IRCWindow::Channel, m_name);
- m_window->set_log_buffer(*m_log);
-}
-
-IRCChannel::~IRCChannel()
-{
-}
-
-NonnullRefPtr<IRCChannel> IRCChannel::create(IRCClient& client, const String& name)
-{
- return adopt(*new IRCChannel(client, name));
-}
-
-void IRCChannel::add_member(const String& name, char prefix)
-{
- for (auto& member : m_members) {
- if (member.name == name) {
- member.prefix = prefix;
- return;
- }
- }
- m_members.append({ name, prefix });
- m_member_model->update();
-}
-
-void IRCChannel::remove_member(const String& name)
-{
- m_members.remove_first_matching([&](auto& member) { return name == member.name; });
-}
-
-void IRCChannel::add_message(char prefix, const String& name, const String& text, Color color)
-{
- log().add_message(prefix, name, text, color);
- window().did_add_message(name, text);
-}
-
-void IRCChannel::add_message(const String& text, Color color)
-{
- log().add_message(text, color);
- window().did_add_message();
-}
-
-void IRCChannel::say(const String& text)
-{
- m_client.send_privmsg(m_name, text);
- add_message(' ', m_client.nickname(), text);
-}
-
-void IRCChannel::handle_join(const String& nick, const String& hostmask)
-{
- if (nick == m_client.nickname()) {
- m_open = true;
- return;
- }
- add_member(nick, (char)0);
- m_member_model->update();
- if (m_client.show_join_part_messages())
- add_message(String::formatted("*** {} [{}] has joined {}", nick, hostmask, m_name), Color::MidGreen);
-}
-
-void IRCChannel::handle_part(const String& nick, const String& hostmask)
-{
- if (nick == m_client.nickname()) {
- m_open = false;
- m_members.clear();
- m_client.did_part_from_channel({}, *this);
- } else {
- remove_member(nick);
- }
- m_member_model->update();
- if (m_client.show_join_part_messages())
- add_message(String::formatted("*** {} [{}] has parted from {}", nick, hostmask, m_name), Color::MidGreen);
-}
-
-void IRCChannel::handle_quit(const String& nick, const String& hostmask, const String& message)
-{
- if (nick == m_client.nickname()) {
- m_open = false;
- m_members.clear();
- m_client.did_part_from_channel({}, *this);
- } else {
- remove_member(nick);
- }
- m_member_model->update();
- add_message(String::formatted("*** {} [{}] has quit ({})", nick, hostmask, message), Color::MidGreen);
-}
-
-void IRCChannel::handle_topic(const String& nick, const String& topic)
-{
- if (nick.is_null())
- add_message(String::formatted("*** Topic is \"{}\"", topic), Color::MidBlue);
- else
- add_message(String::formatted("*** {} set topic to \"{}\"", nick, topic), Color::MidBlue);
-}
-
-void IRCChannel::notify_nick_changed(const String& old_nick, const String& new_nick)
-{
- for (auto& member : m_members) {
- if (member.name == old_nick) {
- member.name = new_nick;
- m_member_model->update();
- if (m_client.show_nick_change_messages())
- add_message(String::formatted("~ {} changed nickname to {}", old_nick, new_nick), Color::MidMagenta);
- return;
- }
- }
-}
diff --git a/Applications/IRCClient/IRCChannel.h b/Applications/IRCClient/IRCChannel.h
deleted file mode 100644
index 1d0eb8657b..0000000000
--- a/Applications/IRCClient/IRCChannel.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "IRCLogBuffer.h"
-#include <AK/RefCounted.h>
-#include <AK/RefPtr.h>
-#include <AK/String.h>
-#include <AK/Vector.h>
-
-class IRCClient;
-class IRCChannelMemberListModel;
-class IRCWindow;
-
-class IRCChannel : public RefCounted<IRCChannel> {
-public:
- static NonnullRefPtr<IRCChannel> create(IRCClient&, const String&);
- ~IRCChannel();
-
- bool is_open() const { return m_open; }
- void set_open(bool b) { m_open = b; }
-
- String name() const { return m_name; }
-
- void add_member(const String& name, char prefix);
- void remove_member(const String& name);
-
- void add_message(char prefix, const String& name, const String& text, Color = Color::Black);
- void add_message(const String& text, Color = Color::Black);
-
- void say(const String&);
-
- const IRCLogBuffer& log() const { return *m_log; }
- IRCLogBuffer& log() { return *m_log; }
-
- IRCChannelMemberListModel* member_model() { return m_member_model.ptr(); }
- const IRCChannelMemberListModel* member_model() const { return m_member_model.ptr(); }
-
- int member_count() const { return m_members.size(); }
- String member_at(int i) { return m_members[i].name; }
-
- void handle_join(const String& nick, const String& hostmask);
- void handle_part(const String& nick, const String& hostmask);
- void handle_quit(const String& nick, const String& hostmask, const String& message);
- void handle_topic(const String& nick, const String& topic);
-
- IRCWindow& window() { return *m_window; }
- const IRCWindow& window() const { return *m_window; }
-
- String topic() const { return m_topic; }
-
- void notify_nick_changed(const String& old_nick, const String& new_nick);
-
-private:
- IRCChannel(IRCClient&, const String&);
-
- IRCClient& m_client;
- String m_name;
- String m_topic;
- struct Member {
- String name;
- char prefix { 0 };
- };
- Vector<Member> m_members;
- bool m_open { false };
-
- NonnullRefPtr<IRCLogBuffer> m_log;
- NonnullRefPtr<IRCChannelMemberListModel> m_member_model;
- IRCWindow* m_window { nullptr };
-};
diff --git a/Applications/IRCClient/IRCChannelMemberListModel.cpp b/Applications/IRCClient/IRCChannelMemberListModel.cpp
deleted file mode 100644
index 22cdcd710f..0000000000
--- a/Applications/IRCClient/IRCChannelMemberListModel.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCChannelMemberListModel.h"
-#include "IRCChannel.h"
-#include <stdio.h>
-#include <time.h>
-
-IRCChannelMemberListModel::IRCChannelMemberListModel(IRCChannel& channel)
- : m_channel(channel)
-{
-}
-
-IRCChannelMemberListModel::~IRCChannelMemberListModel()
-{
-}
-
-int IRCChannelMemberListModel::row_count(const GUI::ModelIndex&) const
-{
- return m_channel.member_count();
-}
-
-int IRCChannelMemberListModel::column_count(const GUI::ModelIndex&) const
-{
- return 1;
-}
-
-String IRCChannelMemberListModel::column_name(int column) const
-{
- switch (column) {
- case Column::Name:
- return "Name";
- }
- ASSERT_NOT_REACHED();
-}
-
-GUI::Variant IRCChannelMemberListModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- if (role == GUI::ModelRole::TextAlignment)
- return Gfx::TextAlignment::CenterLeft;
- if (role == GUI::ModelRole::Display) {
- switch (index.column()) {
- case Column::Name:
- return m_channel.member_at(index.row());
- }
- }
- return {};
-}
-
-void IRCChannelMemberListModel::update()
-{
- did_update();
-}
-
-String IRCChannelMemberListModel::nick_at(const GUI::ModelIndex& index) const
-{
- return data(index, GUI::ModelRole::Display).to_string();
-}
diff --git a/Applications/IRCClient/IRCChannelMemberListModel.h b/Applications/IRCClient/IRCChannelMemberListModel.h
deleted file mode 100644
index 99e4128fc6..0000000000
--- a/Applications/IRCClient/IRCChannelMemberListModel.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <LibGUI/Model.h>
-
-class IRCChannel;
-
-class IRCChannelMemberListModel final : public GUI::Model {
-public:
- enum Column {
- Name
- };
- static NonnullRefPtr<IRCChannelMemberListModel> create(IRCChannel& channel) { return adopt(*new IRCChannelMemberListModel(channel)); }
- virtual ~IRCChannelMemberListModel() override;
-
- virtual int row_count(const GUI::ModelIndex&) const override;
- virtual int column_count(const GUI::ModelIndex&) const override;
- virtual String column_name(int column) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual void update() override;
- virtual String nick_at(const GUI::ModelIndex& index) const;
-
-private:
- explicit IRCChannelMemberListModel(IRCChannel&);
-
- IRCChannel& m_channel;
-};
diff --git a/Applications/IRCClient/IRCClient.cpp b/Applications/IRCClient/IRCClient.cpp
deleted file mode 100644
index c0da630b8f..0000000000
--- a/Applications/IRCClient/IRCClient.cpp
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCClient.h"
-#include "IRCAppWindow.h"
-#include "IRCChannel.h"
-#include "IRCLogBuffer.h"
-#include "IRCQuery.h"
-#include "IRCWindow.h"
-#include "IRCWindowListModel.h"
-#include <AK/QuickSort.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/DateTime.h>
-#include <LibCore/Notifier.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <strings.h>
-
-#ifndef IRC_DEBUG
-# define IRC_DEBUG
-#endif
-
-enum IRCNumeric {
- RPL_WELCOME = 1,
- RPL_WHOISUSER = 311,
- RPL_WHOISSERVER = 312,
- RPL_WHOISOPERATOR = 313,
- RPL_ENDOFWHO = 315,
- RPL_WHOISIDLE = 317,
- RPL_ENDOFWHOIS = 318,
- RPL_WHOISCHANNELS = 319,
- RPL_TOPIC = 332,
- RPL_TOPICWHOTIME = 333,
- RPL_NAMREPLY = 353,
- RPL_ENDOFNAMES = 366,
- RPL_BANLIST = 367,
- RPL_ENDOFBANLIST = 368,
- RPL_ENDOFWHOWAS = 369,
- RPL_ENDOFMOTD = 376,
- ERR_NOSUCHNICK = 401,
- ERR_UNKNOWNCOMMAND = 421,
- ERR_NICKNAMEINUSE = 433,
-};
-
-IRCClient::IRCClient(String server, int port)
- : m_nickname("seren1ty")
- , m_client_window_list_model(IRCWindowListModel::create(*this))
- , m_log(IRCLogBuffer::create())
- , m_config(Core::ConfigFile::get_for_app("IRCClient"))
-{
- struct passwd* user_pw = getpwuid(getuid());
- m_socket = Core::TCPSocket::construct(this);
- m_nickname = m_config->read_entry("User", "Nickname", String::formatted("{}_seren1ty", user_pw->pw_name));
-
- if (server.is_empty()) {
- m_hostname = m_config->read_entry("Connection", "Server", "");
- m_port = m_config->read_num_entry("Connection", "Port", 6667);
- } else {
- m_hostname = server;
- m_port = port ? port : 6667;
- }
-
- m_show_join_part_messages = m_config->read_bool_entry("Messaging", "ShowJoinPartMessages", 1);
- m_show_nick_change_messages = m_config->read_bool_entry("Messaging", "ShowNickChangeMessages", 1);
-
- m_notify_on_message = m_config->read_bool_entry("Notifications", "NotifyOnMessage", 1);
- m_notify_on_mention = m_config->read_bool_entry("Notifications", "NotifyOnMention", 1);
-
- m_ctcp_version_reply = m_config->read_entry("CTCP", "VersionReply", "IRC Client [x86] / Serenity OS");
- m_ctcp_userinfo_reply = m_config->read_entry("CTCP", "UserInfoReply", user_pw->pw_name);
- m_ctcp_finger_reply = m_config->read_entry("CTCP", "FingerReply", user_pw->pw_name);
-}
-
-IRCClient::~IRCClient()
-{
-}
-
-void IRCClient::set_server(const String& hostname, int port)
-{
- m_hostname = hostname;
- m_port = port;
- m_config->write_entry("Connection", "Server", hostname);
- m_config->write_num_entry("Connection", "Port", port);
- m_config->sync();
-}
-
-void IRCClient::on_socket_connected()
-{
- m_notifier = Core::Notifier::construct(m_socket->fd(), Core::Notifier::Read);
- m_notifier->on_ready_to_read = [this] { receive_from_server(); };
-
- send_user();
- send_nick();
-}
-
-bool IRCClient::connect()
-{
- if (m_socket->is_connected())
- ASSERT_NOT_REACHED();
-
- m_socket->on_connected = [this] { on_socket_connected(); };
-
- return m_socket->connect(m_hostname, m_port);
-}
-
-void IRCClient::receive_from_server()
-{
- while (m_socket->can_read_line()) {
- auto line = m_socket->read_line();
- if (line.is_null()) {
- if (!m_socket->is_connected()) {
- outln("IRCClient: Connection closed!");
- exit(1);
- }
- ASSERT_NOT_REACHED();
- }
- process_line(line);
- }
-}
-
-void IRCClient::process_line(const String& line)
-{
- Message msg;
- Vector<char, 32> prefix;
- Vector<char, 32> command;
- Vector<char, 256> current_parameter;
- enum {
- Start,
- InPrefix,
- InCommand,
- InStartOfParameter,
- InParameter,
- InTrailingParameter,
- } state
- = Start;
-
- for (size_t i = 0; i < line.length(); ++i) {
- char ch = line[i];
- if (ch == '\r')
- continue;
- if (ch == '\n')
- break;
- switch (state) {
- case Start:
- if (ch == ':') {
- state = InPrefix;
- continue;
- }
- state = InCommand;
- [[fallthrough]];
- case InCommand:
- if (ch == ' ') {
- state = InStartOfParameter;
- continue;
- }
- command.append(ch);
- continue;
- case InPrefix:
- if (ch == ' ') {
- state = InCommand;
- continue;
- }
- prefix.append(ch);
- continue;
- case InStartOfParameter:
- if (ch == ':') {
- state = InTrailingParameter;
- continue;
- }
- state = InParameter;
- [[fallthrough]];
- case InParameter:
- if (ch == ' ') {
- if (!current_parameter.is_empty())
- msg.arguments.append(String(current_parameter.data(), current_parameter.size()));
- current_parameter.clear_with_capacity();
- state = InStartOfParameter;
- continue;
- }
- current_parameter.append(ch);
- continue;
- case InTrailingParameter:
- current_parameter.append(ch);
- continue;
- }
- }
- if (!current_parameter.is_empty())
- msg.arguments.append(String::copy(current_parameter));
- msg.prefix = String::copy(prefix);
- msg.command = String::copy(command);
- handle(msg);
-}
-
-void IRCClient::send(const String& text)
-{
- if (!m_socket->send(text.bytes())) {
- perror("send");
- exit(1);
- }
-}
-
-void IRCClient::send_user()
-{
- send(String::formatted("USER {} 0 * :{}\r\n", m_nickname, m_nickname));
-}
-
-void IRCClient::send_nick()
-{
- send(String::formatted("NICK {}\r\n", m_nickname));
-}
-
-void IRCClient::send_pong(const String& server)
-{
- send(String::formatted("PONG {}\r\n", server));
- sleep(1);
-}
-
-void IRCClient::join_channel(const String& channel_name)
-{
- send(String::formatted("JOIN {}\r\n", channel_name));
-}
-
-void IRCClient::part_channel(const String& channel_name)
-{
- send(String::formatted("PART {}\r\n", channel_name));
-}
-
-void IRCClient::send_whois(const String& nick)
-{
- send(String::formatted("WHOIS {}\r\n", nick));
-}
-
-void IRCClient::handle(const Message& msg)
-{
-#ifdef IRC_DEBUG
- outln("IRCClient::execute: prefix='{}', command='{}', arguments={}",
- msg.prefix,
- msg.command,
- msg.arguments.size());
-
- size_t index = 0;
- for (auto& arg : msg.arguments)
- outln(" [{}]: {}", index++, arg);
-#endif
-
- auto numeric = msg.command.to_uint();
-
- if (numeric.has_value()) {
- switch (numeric.value()) {
- case RPL_WELCOME:
- return handle_rpl_welcome(msg);
- case RPL_WHOISCHANNELS:
- return handle_rpl_whoischannels(msg);
- case RPL_ENDOFWHO:
- return handle_rpl_endofwho(msg);
- case RPL_ENDOFWHOIS:
- return handle_rpl_endofwhois(msg);
- case RPL_ENDOFWHOWAS:
- return handle_rpl_endofwhowas(msg);
- case RPL_ENDOFMOTD:
- return handle_rpl_endofmotd(msg);
- case RPL_WHOISOPERATOR:
- return handle_rpl_whoisoperator(msg);
- case RPL_WHOISSERVER:
- return handle_rpl_whoisserver(msg);
- case RPL_WHOISUSER:
- return handle_rpl_whoisuser(msg);
- case RPL_WHOISIDLE:
- return handle_rpl_whoisidle(msg);
- case RPL_TOPICWHOTIME:
- return handle_rpl_topicwhotime(msg);
- case RPL_TOPIC:
- return handle_rpl_topic(msg);
- case RPL_NAMREPLY:
- return handle_rpl_namreply(msg);
- case RPL_ENDOFNAMES:
- return handle_rpl_endofnames(msg);
- case RPL_BANLIST:
- return handle_rpl_banlist(msg);
- case RPL_ENDOFBANLIST:
- return handle_rpl_endofbanlist(msg);
- case ERR_NOSUCHNICK:
- return handle_err_nosuchnick(msg);
- case ERR_UNKNOWNCOMMAND:
- return handle_err_unknowncommand(msg);
- case ERR_NICKNAMEINUSE:
- return handle_err_nicknameinuse(msg);
- }
- }
-
- if (msg.command == "PING")
- return handle_ping(msg);
-
- if (msg.command == "JOIN")
- return handle_join(msg);
-
- if (msg.command == "PART")
- return handle_part(msg);
-
- if (msg.command == "QUIT")
- return handle_quit(msg);
-
- if (msg.command == "TOPIC")
- return handle_topic(msg);
-
- if (msg.command == "PRIVMSG")
- return handle_privmsg_or_notice(msg, PrivmsgOrNotice::Privmsg);
-
- if (msg.command == "NOTICE")
- return handle_privmsg_or_notice(msg, PrivmsgOrNotice::Notice);
-
- if (msg.command == "NICK")
- return handle_nick(msg);
-
- if (msg.arguments.size() >= 2)
- add_server_message(String::formatted("[{}] {}", msg.command, msg.arguments[1]));
-}
-
-void IRCClient::add_server_message(const String& text, Color color)
-{
- m_log->add_message(0, "", text, color);
- m_server_subwindow->did_add_message();
-}
-
-void IRCClient::send_topic(const String& channel_name, const String& text)
-{
- send(String::formatted("TOPIC {} :{}\r\n", channel_name, text));
-}
-
-void IRCClient::send_invite(const String& channel_name, const String& nick)
-{
- send(String::formatted("INVITE {} {}\r\n", nick, channel_name));
-}
-
-void IRCClient::send_banlist(const String& channel_name)
-{
- send(String::formatted("MODE {} +b\r\n", channel_name));
-}
-
-void IRCClient::send_voice_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} +v {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_devoice_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} -v {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_hop_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} +h {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_dehop_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} -h {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_op_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} +o {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_deop_user(const String& channel_name, const String& nick)
-{
- send(String::formatted("MODE {} -o {}\r\n", channel_name, nick));
-}
-
-void IRCClient::send_kick(const String& channel_name, const String& nick, const String& comment)
-{
- send(String::formatted("KICK {} {} :{}\r\n", channel_name, nick, comment));
-}
-
-void IRCClient::send_list()
-{
- send("LIST\r\n");
-}
-
-void IRCClient::send_privmsg(const String& target, const String& text)
-{
- send(String::formatted("PRIVMSG {} :{}\r\n", target, text));
-}
-
-void IRCClient::send_notice(const String& target, const String& text)
-{
- send(String::formatted("NOTICE {} :{}\r\n", target, text));
-}
-
-void IRCClient::handle_user_input_in_channel(const String& channel_name, const String& input)
-{
- if (input.is_empty())
- return;
- if (input[0] == '/')
- return handle_user_command(input);
- ensure_channel(channel_name).say(input);
-}
-
-void IRCClient::handle_user_input_in_query(const String& query_name, const String& input)
-{
- if (input.is_empty())
- return;
- if (input[0] == '/')
- return handle_user_command(input);
- ensure_query(query_name).say(input);
-}
-
-void IRCClient::handle_user_input_in_server(const String& input)
-{
- if (input.is_empty())
- return;
- if (input[0] == '/')
- return handle_user_command(input);
-}
-
-String IRCClient::nick_without_prefix(const String& nick)
-{
- assert(!nick.is_empty());
- if (IRCClient::is_nick_prefix(nick[0]))
- return nick.substring(1, nick.length() - 1);
- return nick;
-}
-
-bool IRCClient::is_nick_prefix(char ch)
-{
- switch (ch) {
- case '@':
- case '+':
- case '~':
- case '&':
- case '%':
- return true;
- }
- return false;
-}
-
-bool IRCClient::is_channel_prefix(char ch)
-{
- switch (ch) {
- case '&':
- case '#':
- case '+':
- case '!':
- return true;
- }
- return false;
-}
-
-static bool has_ctcp_payload(const StringView& string)
-{
- return string.length() >= 2 && string[0] == 0x01 && string[string.length() - 1] == 0x01;
-}
-
-void IRCClient::handle_privmsg_or_notice(const Message& msg, PrivmsgOrNotice type)
-{
- if (msg.arguments.size() < 2)
- return;
- if (msg.prefix.is_empty())
- return;
- auto parts = msg.prefix.split('!');
- auto sender_nick = parts[0];
- auto target = msg.arguments[0];
-
- bool is_ctcp = has_ctcp_payload(msg.arguments[1]);
-
-#ifdef IRC_DEBUG
- outln("handle_privmsg_or_notice: type='{}'{}, sender_nick='{}', target='{}'",
- type == PrivmsgOrNotice::Privmsg ? "privmsg" : "notice",
- is_ctcp ? " (ctcp)" : "",
- sender_nick,
- target);
-#endif
-
- if (sender_nick.is_empty())
- return;
-
- char sender_prefix = 0;
- if (is_nick_prefix(sender_nick[0])) {
- sender_prefix = sender_nick[0];
- sender_nick = sender_nick.substring(1, sender_nick.length() - 1);
- }
-
- String message_text = msg.arguments[1];
- auto message_color = Color::Black;
-
- bool insert_as_raw_message = false;
-
- if (is_ctcp) {
- auto ctcp_payload = msg.arguments[1].substring_view(1, msg.arguments[1].length() - 2);
- if (type == PrivmsgOrNotice::Privmsg)
- handle_ctcp_request(sender_nick, ctcp_payload);
- else
- handle_ctcp_response(sender_nick, ctcp_payload);
-
- if (ctcp_payload.starts_with("ACTION")) {
- insert_as_raw_message = true;
- message_text = String::formatted("* {}{}", sender_nick, ctcp_payload.substring_view(6, ctcp_payload.length() - 6));
- message_color = Color::Magenta;
- } else {
- message_text = String::formatted("(CTCP) {}", ctcp_payload);
- message_color = Color::Blue;
- }
- }
-
- {
- auto it = m_channels.find(target);
- if (it != m_channels.end()) {
- if (insert_as_raw_message)
- (*it).value->add_message(message_text, message_color);
- else
- (*it).value->add_message(sender_prefix, sender_nick, message_text, message_color);
- return;
- }
- }
-
- // For NOTICE or CTCP messages, only put them in query if one already exists.
- // Otherwise, put them in the server window. This seems to match other clients.
- IRCQuery* query = nullptr;
- if (is_ctcp || type == PrivmsgOrNotice::Notice) {
- query = query_with_name(sender_nick);
- } else {
- query = &ensure_query(sender_nick);
- }
- if (query) {
- if (insert_as_raw_message)
- query->add_message(message_text, message_color);
- else
- query->add_message(sender_prefix, sender_nick, message_text, message_color);
- } else {
- add_server_message(String::formatted("<{}> {}", sender_nick, message_text), message_color);
- }
-}
-
-IRCQuery* IRCClient::query_with_name(const String& name)
-{
- return const_cast<IRCQuery*>(m_queries.get(name).value_or(nullptr));
-}
-
-IRCQuery& IRCClient::ensure_query(const String& name)
-{
- auto it = m_queries.find(name);
- if (it != m_queries.end())
- return *(*it).value;
- auto query = IRCQuery::create(*this, name);
- auto& query_reference = *query;
- m_queries.set(name, query);
- return query_reference;
-}
-
-IRCChannel& IRCClient::ensure_channel(const String& name)
-{
- auto it = m_channels.find(name);
- if (it != m_channels.end())
- return *(*it).value;
- auto channel = IRCChannel::create(*this, name);
- auto& channel_reference = *channel;
- m_channels.set(name, channel);
- return channel_reference;
-}
-
-void IRCClient::handle_ping(const Message& msg)
-{
- if (msg.arguments.size() < 1)
- return;
- m_log->add_message(0, "", "Ping? Pong!");
- send_pong(msg.arguments[0]);
-}
-
-void IRCClient::handle_join(const Message& msg)
-{
- if (msg.arguments.size() != 1)
- return;
- auto prefix_parts = msg.prefix.split('!');
- if (prefix_parts.size() < 1)
- return;
- auto nick = prefix_parts[0];
- auto& channel_name = msg.arguments[0];
- ensure_channel(channel_name).handle_join(nick, msg.prefix);
-}
-
-void IRCClient::handle_part(const Message& msg)
-{
- if (msg.arguments.size() < 1)
- return;
- auto prefix_parts = msg.prefix.split('!');
- if (prefix_parts.size() < 1)
- return;
- auto nick = prefix_parts[0];
- auto& channel_name = msg.arguments[0];
- ensure_channel(channel_name).handle_part(nick, msg.prefix);
-}
-
-void IRCClient::handle_quit(const Message& msg)
-{
- if (msg.arguments.size() < 1)
- return;
- auto prefix_parts = msg.prefix.split('!');
- if (prefix_parts.size() < 1)
- return;
- auto nick = prefix_parts[0];
- auto& message = msg.arguments[0];
- for (auto& it : m_channels) {
- it.value->handle_quit(nick, msg.prefix, message);
- }
-}
-
-void IRCClient::handle_nick(const Message& msg)
-{
- auto prefix_parts = msg.prefix.split('!');
- if (prefix_parts.size() < 1)
- return;
- auto old_nick = prefix_parts[0];
- if (msg.arguments.size() != 1)
- return;
- auto& new_nick = msg.arguments[0];
- if (old_nick == m_nickname)
- m_nickname = new_nick;
- if (m_show_nick_change_messages)
- add_server_message(String::formatted("~ {} changed nickname to {}", old_nick, new_nick));
- if (on_nickname_changed)
- on_nickname_changed(new_nick);
- for (auto& it : m_channels) {
- it.value->notify_nick_changed(old_nick, new_nick);
- }
-}
-
-void IRCClient::handle_topic(const Message& msg)
-{
- if (msg.arguments.size() != 2)
- return;
- auto prefix_parts = msg.prefix.split('!');
- if (prefix_parts.size() < 1)
- return;
- auto nick = prefix_parts[0];
- auto& channel_name = msg.arguments[0];
- ensure_channel(channel_name).handle_topic(nick, msg.arguments[1]);
-}
-
-void IRCClient::handle_rpl_welcome(const Message& msg)
-{
- if (msg.arguments.size() < 2)
- return;
- auto& welcome_message = msg.arguments[1];
- add_server_message(welcome_message);
-
- auto channel_str = m_config->read_entry("Connection", "AutoJoinChannels", "");
- if (channel_str.is_empty())
- return;
- dbgln("IRCClient: Channels to autojoin: {}", channel_str);
- auto channels = channel_str.split(',');
- for (auto& channel : channels) {
- join_channel(channel);
- dbgln("IRCClient: Auto joining channel: {}", channel);
- }
-}
-
-void IRCClient::handle_rpl_topic(const Message& msg)
-{
- if (msg.arguments.size() < 3)
- return;
- auto& channel_name = msg.arguments[1];
- auto& topic = msg.arguments[2];
- ensure_channel(channel_name).handle_topic({}, topic);
-}
-
-void IRCClient::handle_rpl_namreply(const Message& msg)
-{
- if (msg.arguments.size() < 4)
- return;
- auto& channel_name = msg.arguments[2];
- auto& channel = ensure_channel(channel_name);
- auto members = msg.arguments[3].split(' ');
-
- quick_sort(members, [](auto& a, auto& b) {
- return strcasecmp(a.characters(), b.characters()) < 0;
- });
-
- for (auto& member : members) {
- if (member.is_empty())
- continue;
- char prefix = 0;
- if (is_nick_prefix(member[0]))
- prefix = member[0];
- channel.add_member(member, prefix);
- }
-}
-
-void IRCClient::handle_rpl_endofnames(const Message&)
-{
- add_server_message("// End of NAMES");
-}
-
-void IRCClient::handle_rpl_banlist(const Message& msg)
-{
- if (msg.arguments.size() < 5)
- return;
- auto& channel = msg.arguments[1];
- auto& mask = msg.arguments[2];
- auto& user = msg.arguments[3];
- auto& datestamp = msg.arguments[4];
- add_server_message(String::formatted("* {}: {} on {} by {}", channel, mask, datestamp, user));
-}
-
-void IRCClient::handle_rpl_endofbanlist(const Message&)
-{
- add_server_message("// End of BANLIST");
-}
-
-void IRCClient::handle_rpl_endofwho(const Message&)
-{
- add_server_message("// End of WHO");
-}
-
-void IRCClient::handle_rpl_endofwhois(const Message&)
-{
- add_server_message("// End of WHOIS");
-}
-
-void IRCClient::handle_rpl_endofwhowas(const Message&)
-{
- add_server_message("// End of WHOWAS");
-}
-
-void IRCClient::handle_rpl_endofmotd(const Message&)
-{
- add_server_message("// End of MOTD");
-}
-
-void IRCClient::handle_rpl_whoisoperator(const Message& msg)
-{
- if (msg.arguments.size() < 2)
- return;
- auto& nick = msg.arguments[1];
- add_server_message(String::formatted("* {} is an IRC operator", nick));
-}
-
-void IRCClient::handle_rpl_whoisserver(const Message& msg)
-{
- if (msg.arguments.size() < 3)
- return;
- auto& nick = msg.arguments[1];
- auto& server = msg.arguments[2];
- add_server_message(String::formatted("* {} is using server {}", nick, server));
-}
-
-void IRCClient::handle_rpl_whoisuser(const Message& msg)
-{
- if (msg.arguments.size() < 6)
- return;
- auto& nick = msg.arguments[1];
- auto& username = msg.arguments[2];
- auto& host = msg.arguments[3];
- [[maybe_unused]] auto& asterisk = msg.arguments[4];
- auto& realname = msg.arguments[5];
- add_server_message(String::formatted("* {} is {}@{}, real name: {}", nick, username, host, realname));
-}
-
-void IRCClient::handle_rpl_whoisidle(const Message& msg)
-{
- if (msg.arguments.size() < 3)
- return;
- auto& nick = msg.arguments[1];
- auto& secs = msg.arguments[2];
- add_server_message(String::formatted("* {} is {} seconds idle", nick, secs));
-}
-
-void IRCClient::handle_rpl_whoischannels(const Message& msg)
-{
- if (msg.arguments.size() < 3)
- return;
- auto& nick = msg.arguments[1];
- auto& channel_list = msg.arguments[2];
- add_server_message(String::formatted("* {} is in channels {}", nick, channel_list));
-}
-
-void IRCClient::handle_rpl_topicwhotime(const Message& msg)
-{
- if (msg.arguments.size() < 4)
- return;
- auto& channel_name = msg.arguments[1];
- auto& nick = msg.arguments[2];
- auto setat = msg.arguments[3];
- auto setat_time = setat.to_uint();
- if (setat_time.has_value())
- setat = Core::DateTime::from_timestamp(setat_time.value()).to_string();
- ensure_channel(channel_name).add_message(String::formatted("*** (set by {} at {})", nick, setat), Color::Blue);
-}
-
-void IRCClient::handle_err_nosuchnick(const Message& msg)
-{
- if (msg.arguments.size() < 3)
- return;
- auto& nick = msg.arguments[1];
- auto& message = msg.arguments[2];
- add_server_message(String::formatted("* {} :{}", nick, message));
-}
-
-void IRCClient::handle_err_unknowncommand(const Message& msg)
-{
- if (msg.arguments.size() < 2)
- return;
- auto& cmd = msg.arguments[1];
- add_server_message(String::formatted("* Unknown command: {}", cmd));
-}
-
-void IRCClient::handle_err_nicknameinuse(const Message& msg)
-{
- if (msg.arguments.size() < 2)
- return;
- auto& nick = msg.arguments[1];
- add_server_message(String::formatted("* {} :Nickname in use", nick));
-}
-
-void IRCClient::register_subwindow(IRCWindow& subwindow)
-{
- if (subwindow.type() == IRCWindow::Server) {
- m_server_subwindow = &subwindow;
- subwindow.set_log_buffer(*m_log);
- }
- m_windows.append(&subwindow);
- m_client_window_list_model->update();
-}
-
-void IRCClient::unregister_subwindow(IRCWindow& subwindow)
-{
- if (subwindow.type() == IRCWindow::Server) {
- m_server_subwindow = &subwindow;
- }
- for (size_t i = 0; i < m_windows.size(); ++i) {
- if (m_windows.at(i) == &subwindow) {
- m_windows.remove(i);
- break;
- }
- }
- m_client_window_list_model->update();
-}
-
-void IRCClient::handle_user_command(const String& input)
-{
- auto parts = input.split_view(' ');
- if (parts.is_empty())
- return;
- auto command = String(parts[0]).to_uppercase();
- if (command == "/RAW") {
- if (parts.size() <= 1)
- return;
- int command_length = command.length() + 1;
- StringView raw_message = input.view().substring_view(command_length, input.view().length() - command_length);
- send(String::formatted("{}\r\n", raw_message));
- return;
- }
- if (command == "/NICK") {
- if (parts.size() >= 2)
- change_nick(parts[1]);
- return;
- }
- if (command == "/JOIN") {
- if (parts.size() >= 2)
- join_channel(parts[1]);
- return;
- }
- if (command == "/PART") {
- if (parts.size() >= 2) {
- auto channel = parts[1];
- part_channel(channel);
- } else {
- auto* window = current_window();
- if (!window || window->type() != IRCWindow::Type::Channel)
- return;
- auto channel = window->channel().name();
- join_channel(channel);
- }
- return;
- }
- if (command == "/CYCLE") {
- if (parts.size() >= 2) {
- auto channel = parts[1];
- part_channel(channel);
- join_channel(channel);
- } else {
- auto* window = current_window();
- if (!window || window->type() != IRCWindow::Type::Channel)
- return;
- auto channel = window->channel().name();
- part_channel(channel);
- join_channel(channel);
- }
- return;
- }
- if (command == "/BANLIST") {
- if (parts.size() >= 2) {
- auto channel = parts[1];
- send_banlist(channel);
- } else {
- auto* window = current_window();
- if (!window || window->type() != IRCWindow::Type::Channel)
- return;
- auto channel = window->channel().name();
- send_banlist(channel);
- }
- return;
- }
- if (command == "/ME") {
- if (parts.size() < 2)
- return;
-
- auto* window = current_window();
- if (!window)
- return;
-
- auto emote = input.view().substring_view_starting_after_substring(parts[0]);
- auto action_string = String::formatted("ACTION{}", emote);
- String peer;
- if (window->type() == IRCWindow::Type::Channel) {
- peer = window->channel().name();
- window->channel().add_message(String::formatted("* {}{}", m_nickname, emote), Gfx::Color::Magenta);
- } else if (window->type() == IRCWindow::Type::Query) {
- peer = window->query().name();
- window->query().add_message(String::formatted("* {}{}", m_nickname, emote), Gfx::Color::Magenta);
- } else {
- return;
- }
-
- send_ctcp_request(peer, action_string);
- return;
- }
- if (command == "/TOPIC") {
- if (parts.size() < 2)
- return;
- if (parts[1].is_empty())
- return;
-
- if (is_channel_prefix(parts[1][0])) {
- if (parts.size() < 3)
- return;
- auto channel = parts[1];
- auto topic = input.view().substring_view_starting_after_substring(channel);
- send_topic(channel, topic);
- } else {
- auto* window = current_window();
- if (!window || window->type() != IRCWindow::Type::Channel)
- return;
- auto channel = window->channel().name();
- auto topic = input.view().substring_view_starting_after_substring(parts[0]);
- send_topic(channel, topic);
- }
- return;
- }
- if (command == "/KICK") {
- if (parts.size() < 2)
- return;
- if (parts[1].is_empty())
- return;
-
- if (is_channel_prefix(parts[1][0])) {
- if (parts.size() < 3)
- return;
- auto channel = parts[1];
- auto nick = parts[2];
- auto reason = input.view().substring_view_starting_after_substring(nick);
- send_kick(channel, nick, reason);
- } else {
- auto* window = current_window();
- if (!window || window->type() != IRCWindow::Type::Channel)
- return;
- auto channel = window->channel().name();
- auto nick = parts[1];
- auto reason = input.view().substring_view_starting_after_substring(nick);
- send_kick(channel, nick, reason);
- }
- return;
- }
- if (command == "/LIST") {
- send_list();
- return;
- }
- if (command == "/QUERY") {
- if (parts.size() >= 2) {
- auto& query = ensure_query(parts[1]);
- IRCAppWindow::the().set_active_window(query.window());
- }
- return;
- }
- if (command == "/MSG") {
- if (parts.size() < 3)
- return;
- auto nick = parts[1];
- auto& query = ensure_query(nick);
- IRCAppWindow::the().set_active_window(query.window());
- query.say(input.view().substring_view_starting_after_substring(nick));
- return;
- }
- if (command == "/WHOIS") {
- if (parts.size() >= 2)
- send_whois(parts[1]);
- return;
- }
-}
-
-void IRCClient::change_nick(const String& nick)
-{
- send(String::formatted("NICK {}\r\n", nick));
-}
-
-void IRCClient::handle_list_channels_action()
-{
- send_list();
-}
-
-void IRCClient::handle_whois_action(const String& nick)
-{
- send_whois(nick);
-}
-
-void IRCClient::handle_ctcp_user_action(const String& nick, const String& message)
-{
- send_ctcp_request(nick, message);
-}
-
-void IRCClient::handle_open_query_action(const String& nick)
-{
- ensure_query(nick);
-}
-
-void IRCClient::handle_change_nick_action(const String& nick)
-{
- change_nick(nick);
-}
-
-void IRCClient::handle_change_topic_action(const String& channel, const String& topic)
-{
- send_topic(channel, topic);
-}
-
-void IRCClient::handle_invite_user_action(const String& channel, const String& nick)
-{
- send_invite(channel, nick);
-}
-
-void IRCClient::handle_banlist_action(const String& channel)
-{
- send_banlist(channel);
-}
-
-void IRCClient::handle_voice_user_action(const String& channel, const String& nick)
-{
- send_voice_user(channel, nick);
-}
-
-void IRCClient::handle_devoice_user_action(const String& channel, const String& nick)
-{
- send_devoice_user(channel, nick);
-}
-
-void IRCClient::handle_hop_user_action(const String& channel, const String& nick)
-{
- send_hop_user(channel, nick);
-}
-
-void IRCClient::handle_dehop_user_action(const String& channel, const String& nick)
-{
- send_dehop_user(channel, nick);
-}
-
-void IRCClient::handle_op_user_action(const String& channel, const String& nick)
-{
- send_op_user(channel, nick);
-}
-
-void IRCClient::handle_deop_user_action(const String& channel, const String& nick)
-{
- send_deop_user(channel, nick);
-}
-
-void IRCClient::handle_kick_user_action(const String& channel, const String& nick, const String& message)
-{
- send_kick(channel, nick, message);
-}
-
-void IRCClient::handle_close_query_action(const String& nick)
-{
- m_queries.remove(nick);
- m_client_window_list_model->update();
-}
-
-void IRCClient::handle_join_action(const String& channel)
-{
- join_channel(channel);
-}
-
-void IRCClient::handle_part_action(const String& channel)
-{
- part_channel(channel);
-}
-
-void IRCClient::handle_cycle_channel_action(const String& channel)
-{
- part_channel(channel);
- join_channel(channel);
-}
-
-void IRCClient::did_part_from_channel(Badge<IRCChannel>, IRCChannel& channel)
-{
- if (on_part_from_channel)
- on_part_from_channel(channel);
-}
-
-void IRCClient::send_ctcp_response(const StringView& peer, const StringView& payload)
-{
- StringBuilder builder;
- builder.append(0x01);
- builder.append(payload);
- builder.append(0x01);
- auto message = builder.to_string();
- send_notice(peer, message);
-}
-
-void IRCClient::send_ctcp_request(const StringView& peer, const StringView& payload)
-{
- StringBuilder builder;
- builder.append(0x01);
- builder.append(payload);
- builder.append(0x01);
- auto message = builder.to_string();
- send_privmsg(peer, message);
-}
-
-void IRCClient::handle_ctcp_request(const StringView& peer, const StringView& payload)
-{
- dbgln("handle_ctcp_request: {}", payload);
-
- if (payload == "VERSION") {
- auto version = ctcp_version_reply();
- if (version.is_empty())
- return;
- send_ctcp_response(peer, String::formatted("VERSION {}", version));
- return;
- }
-
- if (payload == "USERINFO") {
- auto userinfo = ctcp_userinfo_reply();
- if (userinfo.is_empty())
- return;
- send_ctcp_response(peer, String::formatted("USERINFO {}", userinfo));
- return;
- }
-
- if (payload == "FINGER") {
- auto finger = ctcp_finger_reply();
- if (finger.is_empty())
- return;
- send_ctcp_response(peer, String::formatted("FINGER {}", finger));
- return;
- }
-
- if (payload.starts_with("PING")) {
- send_ctcp_response(peer, payload);
- return;
- }
-}
-
-void IRCClient::handle_ctcp_response(const StringView& peer, const StringView& payload)
-{
- dbgln("handle_ctcp_response({}): {}", peer, payload);
-}
diff --git a/Applications/IRCClient/IRCClient.h b/Applications/IRCClient/IRCClient.h
deleted file mode 100644
index 06f7e59289..0000000000
--- a/Applications/IRCClient/IRCClient.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "IRCLogBuffer.h"
-#include "IRCWindow.h"
-#include <AK/CircularQueue.h>
-#include <AK/Function.h>
-#include <AK/HashMap.h>
-#include <AK/String.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/TCPSocket.h>
-
-class IRCChannel;
-class IRCQuery;
-class IRCWindowListModel;
-
-class IRCClient final : public Core::Object {
- C_OBJECT(IRCClient)
- friend class IRCChannel;
- friend class IRCQuery;
-
-public:
- virtual ~IRCClient() override;
-
- void set_server(const String& hostname, int port = 6667);
-
- bool connect();
-
- String hostname() const { return m_hostname; }
- int port() const { return m_port; }
-
- String nickname() const { return m_nickname; }
-
- String ctcp_version_reply() const { return m_ctcp_version_reply; }
- String ctcp_userinfo_reply() const { return m_ctcp_userinfo_reply; }
- String ctcp_finger_reply() const { return m_ctcp_finger_reply; }
-
- bool show_join_part_messages() const { return m_show_join_part_messages; }
- bool show_nick_change_messages() const { return m_show_nick_change_messages; }
-
- bool notify_on_message() const { return m_notify_on_message; }
- bool notify_on_mention() const { return m_notify_on_mention; }
-
- void join_channel(const String&);
- void part_channel(const String&);
- void change_nick(const String&);
-
- static bool is_nick_prefix(char);
- static bool is_channel_prefix(char);
- String nick_without_prefix(const String& nick);
-
- IRCWindow* current_window() { return aid_get_active_window(); }
- const IRCWindow* current_window() const { return aid_get_active_window(); }
-
- Function<void()> on_disconnect;
- Function<void()> on_server_message;
- Function<void(const String&)> on_nickname_changed;
- Function<void(IRCChannel&)> on_part_from_channel;
-
- Function<NonnullRefPtr<IRCWindow>(void*, IRCWindow::Type, const String&)> aid_create_window;
- Function<IRCWindow*()> aid_get_active_window;
- Function<void()> aid_update_window_list;
-
- void register_subwindow(IRCWindow&);
- void unregister_subwindow(IRCWindow&);
-
- IRCWindowListModel* client_window_list_model() { return m_client_window_list_model.ptr(); }
- const IRCWindowListModel* client_window_list_model() const { return m_client_window_list_model.ptr(); }
-
- int window_count() const { return m_windows.size(); }
- const IRCWindow& window_at(int index) const { return *m_windows.at(index); }
- IRCWindow& window_at(int index) { return *m_windows.at(index); }
-
- size_t window_index(const IRCWindow& window) const
- {
- for (size_t i = 0; i < m_windows.size(); ++i) {
- if (m_windows[i] == &window)
- return i;
- }
- ASSERT_NOT_REACHED();
- }
-
- void did_part_from_channel(Badge<IRCChannel>, IRCChannel&);
-
- void handle_user_input_in_channel(const String& channel_name, const String&);
- void handle_user_input_in_query(const String& query_name, const String&);
- void handle_user_input_in_server(const String&);
-
- void handle_list_channels_action();
- void handle_whois_action(const String& nick);
- void handle_ctcp_user_action(const String& nick, const String& message);
- void handle_open_query_action(const String&);
- void handle_close_query_action(const String&);
- void handle_join_action(const String& channel_name);
- void handle_part_action(const String& channel_name);
- void handle_cycle_channel_action(const String& channel_name);
- void handle_change_nick_action(const String& nick);
- void handle_change_topic_action(const String& channel_name, const String&);
- void handle_invite_user_action(const String& channel_name, const String& nick);
- void handle_banlist_action(const String& channel_name);
- void handle_voice_user_action(const String& channel_name, const String& nick);
- void handle_devoice_user_action(const String& channel_name, const String& nick);
- void handle_hop_user_action(const String& channel_name, const String& nick);
- void handle_dehop_user_action(const String& channel_name, const String& nick);
- void handle_op_user_action(const String& channel_name, const String& nick);
- void handle_deop_user_action(const String& channel_name, const String& nick);
- void handle_kick_user_action(const String& channel_name, const String& nick, const String&);
-
- IRCQuery* query_with_name(const String&);
- IRCQuery& ensure_query(const String& name);
- IRCChannel& ensure_channel(const String& name);
-
- void add_server_message(const String&, Color = Color::Black);
-
-private:
- IRCClient(String server, int port);
-
- struct Message {
- String prefix;
- String command;
- Vector<String> arguments;
- };
-
- enum class PrivmsgOrNotice {
- Privmsg,
- Notice,
- };
-
- void receive_from_server();
- void send(const String&);
- void send_user();
- void send_nick();
- void send_pong(const String& server);
- void send_privmsg(const String& target, const String&);
- void send_notice(const String& target, const String&);
- void send_topic(const String& channel_name, const String&);
- void send_invite(const String& channel_name, const String& nick);
- void send_banlist(const String& channel_name);
- void send_voice_user(const String& channel_name, const String& nick);
- void send_devoice_user(const String& channel_name, const String& nick);
- void send_hop_user(const String& channel_name, const String& nick);
- void send_dehop_user(const String& channel_name, const String& nick);
- void send_op_user(const String& channel_name, const String& nick);
- void send_deop_user(const String& channel_name, const String& nick);
- void send_kick(const String& channel_name, const String& nick, const String&);
- void send_list();
- void send_whois(const String&);
- void process_line(const String&);
- void handle_join(const Message&);
- void handle_part(const Message&);
- void handle_quit(const Message&);
- void handle_ping(const Message&);
- void handle_topic(const Message&);
- void handle_rpl_welcome(const Message&);
- void handle_rpl_topic(const Message&);
- void handle_rpl_whoisuser(const Message&);
- void handle_rpl_whoisserver(const Message&);
- void handle_rpl_whoisoperator(const Message&);
- void handle_rpl_whoisidle(const Message&);
- void handle_rpl_endofwho(const Message&);
- void handle_rpl_endofwhois(const Message&);
- void handle_rpl_endofwhowas(const Message&);
- void handle_rpl_endofmotd(const Message&);
- void handle_rpl_whoischannels(const Message&);
- void handle_rpl_topicwhotime(const Message&);
- void handle_rpl_endofnames(const Message&);
- void handle_rpl_endofbanlist(const Message&);
- void handle_rpl_namreply(const Message&);
- void handle_rpl_banlist(const Message&);
- void handle_err_nosuchnick(const Message&);
- void handle_err_unknowncommand(const Message&);
- void handle_err_nicknameinuse(const Message&);
- void handle_privmsg_or_notice(const Message&, PrivmsgOrNotice);
- void handle_nick(const Message&);
- void handle(const Message&);
- void handle_user_command(const String&);
- void handle_ctcp_request(const StringView& peer, const StringView& payload);
- void handle_ctcp_response(const StringView& peer, const StringView& payload);
- void send_ctcp_request(const StringView& peer, const StringView& payload);
- void send_ctcp_response(const StringView& peer, const StringView& payload);
-
- void on_socket_connected();
-
- String m_hostname;
- int m_port { 6667 };
-
- RefPtr<Core::TCPSocket> m_socket;
-
- String m_nickname;
- RefPtr<Core::Notifier> m_notifier;
- HashMap<String, RefPtr<IRCChannel>, CaseInsensitiveStringTraits> m_channels;
- HashMap<String, RefPtr<IRCQuery>, CaseInsensitiveStringTraits> m_queries;
-
- bool m_show_join_part_messages { 1 };
- bool m_show_nick_change_messages { 1 };
-
- bool m_notify_on_message { 1 };
- bool m_notify_on_mention { 1 };
-
- String m_ctcp_version_reply;
- String m_ctcp_userinfo_reply;
- String m_ctcp_finger_reply;
-
- Vector<IRCWindow*> m_windows;
-
- IRCWindow* m_server_subwindow { nullptr };
-
- NonnullRefPtr<IRCWindowListModel> m_client_window_list_model;
- NonnullRefPtr<IRCLogBuffer> m_log;
- NonnullRefPtr<Core::ConfigFile> m_config;
-};
diff --git a/Applications/IRCClient/IRCLogBuffer.cpp b/Applications/IRCClient/IRCLogBuffer.cpp
deleted file mode 100644
index b292e0a4ee..0000000000
--- a/Applications/IRCClient/IRCLogBuffer.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCLogBuffer.h"
-#include <AK/StringBuilder.h>
-#include <LibWeb/DOM/DocumentFragment.h>
-#include <LibWeb/DOM/DocumentType.h>
-#include <LibWeb/DOM/ElementFactory.h>
-#include <LibWeb/DOM/Text.h>
-#include <LibWeb/HTML/HTMLBodyElement.h>
-#include <time.h>
-
-NonnullRefPtr<IRCLogBuffer> IRCLogBuffer::create()
-{
- return adopt(*new IRCLogBuffer);
-}
-
-IRCLogBuffer::IRCLogBuffer()
-{
- m_document = Web::DOM::Document::create();
- m_document->append_child(adopt(*new Web::DOM::DocumentType(document())));
- auto html_element = m_document->create_element("html");
- m_document->append_child(html_element);
- auto head_element = m_document->create_element("head");
- html_element->append_child(head_element);
- auto style_element = m_document->create_element("style");
- style_element->append_child(adopt(*new Web::DOM::Text(document(), "div { font-family: Csilla; font-weight: lighter; }")));
- head_element->append_child(style_element);
- auto body_element = m_document->create_element("body");
- html_element->append_child(body_element);
- m_container_element = body_element;
-}
-
-IRCLogBuffer::~IRCLogBuffer()
-{
-}
-
-static String timestamp_string()
-{
- auto now = time(nullptr);
- auto* tm = localtime(&now);
- return String::formatted("{:02}:{:02}:{:02} ", tm->tm_hour, tm->tm_min, tm->tm_sec);
-}
-
-void IRCLogBuffer::add_message(char prefix, const String& name, const String& text, Color color)
-{
- auto nick_string = String::formatted("<{}{}> ", prefix ? prefix : ' ', name.characters());
- auto html = String::formatted(
- "<span>{}</span>"
- "<b>{}</b>"
- "<span>{}</span>",
- timestamp_string(),
- escape_html_entities(nick_string),
- escape_html_entities(text));
-
- auto wrapper = m_document->create_element(Web::HTML::TagNames::div);
- wrapper->set_attribute(Web::HTML::AttributeNames::style, String::formatted("color: {}", color.to_string()));
- wrapper->set_inner_html(html);
- m_container_element->append_child(wrapper);
- m_document->force_layout();
-}
-
-void IRCLogBuffer::add_message(const String& text, Color color)
-{
- auto html = String::formatted(
- "<span>{}</span>"
- "<span>{}</span>",
- timestamp_string(),
- escape_html_entities(text));
- auto wrapper = m_document->create_element(Web::HTML::TagNames::div);
- wrapper->set_attribute(Web::HTML::AttributeNames::style, String::formatted("color: {}", color.to_string()));
- wrapper->set_inner_html(html);
- m_container_element->append_child(wrapper);
- m_document->force_layout();
-}
diff --git a/Applications/IRCClient/IRCLogBuffer.h b/Applications/IRCClient/IRCLogBuffer.h
deleted file mode 100644
index db4636f0ee..0000000000
--- a/Applications/IRCClient/IRCLogBuffer.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/RefCounted.h>
-#include <AK/RefPtr.h>
-#include <AK/String.h>
-#include <LibGfx/Color.h>
-#include <LibWeb/DOM/Document.h>
-
-class IRCLogBuffer : public RefCounted<IRCLogBuffer> {
-public:
- static NonnullRefPtr<IRCLogBuffer> create();
- ~IRCLogBuffer();
-
- struct Message {
- time_t timestamp { 0 };
- char prefix { 0 };
- String sender;
- String text;
- Color color { Color::Black };
- };
-
- void add_message(char prefix, const String& name, const String& text, Color = Color::Black);
- void add_message(const String& text, Color = Color::Black);
-
- const Web::DOM::Document& document() const { return *m_document; }
- Web::DOM::Document& document() { return *m_document; }
-
-private:
- IRCLogBuffer();
- RefPtr<Web::DOM::Document> m_document;
- RefPtr<Web::DOM::Element> m_container_element;
-};
diff --git a/Applications/IRCClient/IRCQuery.cpp b/Applications/IRCClient/IRCQuery.cpp
deleted file mode 100644
index e2795f05d8..0000000000
--- a/Applications/IRCClient/IRCQuery.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCQuery.h"
-#include "IRCClient.h"
-#include <stdio.h>
-
-IRCQuery::IRCQuery(IRCClient& client, const String& name)
- : m_client(client)
- , m_name(name)
- , m_log(IRCLogBuffer::create())
-{
- m_window = m_client->aid_create_window(this, IRCWindow::Query, m_name);
- m_window->set_log_buffer(*m_log);
-}
-
-IRCQuery::~IRCQuery()
-{
-}
-
-NonnullRefPtr<IRCQuery> IRCQuery::create(IRCClient& client, const String& name)
-{
- return adopt(*new IRCQuery(client, name));
-}
-
-void IRCQuery::add_message(char prefix, const String& name, const String& text, Color color)
-{
- log().add_message(prefix, name, text, color);
- window().did_add_message(name, text);
-}
-
-void IRCQuery::add_message(const String& text, Color color)
-{
- log().add_message(text, color);
- window().did_add_message();
-}
-
-void IRCQuery::say(const String& text)
-{
- m_client->send_privmsg(m_name, text);
- add_message(' ', m_client->nickname(), text);
-}
diff --git a/Applications/IRCClient/IRCQuery.h b/Applications/IRCClient/IRCQuery.h
deleted file mode 100644
index 379d9d6492..0000000000
--- a/Applications/IRCClient/IRCQuery.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "IRCLogBuffer.h"
-#include <AK/CircularQueue.h>
-#include <AK/RefCounted.h>
-#include <AK/RefPtr.h>
-#include <AK/String.h>
-#include <AK/Vector.h>
-
-class IRCClient;
-class IRCWindow;
-
-class IRCQuery : public RefCounted<IRCQuery> {
-public:
- static NonnullRefPtr<IRCQuery> create(IRCClient&, const String& name);
- ~IRCQuery();
-
- String name() const { return m_name; }
- void add_message(char prefix, const String& name, const String& text, Color = Color::Black);
- void add_message(const String& text, Color = Color::Black);
-
- const IRCLogBuffer& log() const { return *m_log; }
- IRCLogBuffer& log() { return *m_log; }
-
- void say(const String&);
-
- IRCWindow& window() { return *m_window; }
- const IRCWindow& window() const { return *m_window; }
-
-private:
- IRCQuery(IRCClient&, const String& name);
-
- NonnullRefPtr<IRCClient> m_client;
- String m_name;
- RefPtr<IRCWindow> m_window;
-
- NonnullRefPtr<IRCLogBuffer> m_log;
-};
diff --git a/Applications/IRCClient/IRCWindow.cpp b/Applications/IRCClient/IRCWindow.cpp
deleted file mode 100644
index 7a84795b8f..0000000000
--- a/Applications/IRCClient/IRCWindow.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCWindow.h"
-#include "IRCChannel.h"
-#include "IRCChannelMemberListModel.h"
-#include "IRCClient.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Notification.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Window.h>
-#include <LibWeb/InProcessWebView.h>
-
-IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& name)
- : m_client(client)
- , m_owner(owner)
- , m_type(type)
- , m_name(name)
-{
- set_layout<GUI::VerticalBoxLayout>();
-
- // Make a container for the log buffer view + (optional) member list.
- auto& container = add<GUI::HorizontalSplitter>();
-
- m_page_view = container.add<Web::InProcessWebView>();
-
- if (m_type == Channel) {
- auto& member_view = container.add<GUI::TableView>();
- member_view.set_column_headers_visible(false);
- member_view.set_fixed_width(100);
- member_view.set_alternating_row_colors(false);
- member_view.set_model(channel().member_model());
- member_view.set_activates_on_selection(true);
- member_view.on_activation = [&](auto& index) {
- if (!index.is_valid())
- return;
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_open_query_action(m_client->nick_without_prefix(nick.characters()));
- };
- member_view.on_context_menu_request = [&](const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
- if (!index.is_valid())
- return;
-
- m_context_menu = GUI::Menu::construct();
-
- m_context_menu->add_action(GUI::Action::create("Open query", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-open-query.png"), [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_open_query_action(m_client->nick_without_prefix(nick.characters()));
- }));
-
- m_context_menu->add_action(GUI::Action::create("Whois", Gfx::Bitmap::load_from_file("/res/icons/16x16/irc-whois.png"), [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_whois_action(m_client->nick_without_prefix(nick.characters()));
- }));
-
- auto& context_control_menu = m_context_menu->add_submenu("Control");
-
- context_control_menu.add_action(GUI::Action::create("Voice", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_voice_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_action(GUI::Action::create("DeVoice", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_devoice_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_action(GUI::Action::create("Hop", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_hop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_action(GUI::Action::create("DeHop", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_dehop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_action(GUI::Action::create("Op", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_op_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_action(GUI::Action::create("DeOp", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_deop_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()));
- }));
-
- context_control_menu.add_separator();
-
- context_control_menu.add_action(GUI::Action::create("Kick", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- if (IRCClient::is_nick_prefix(nick[0]))
- nick = nick.substring(1, nick.length() - 1);
- String value;
- if (GUI::InputBox::show(value, window(), "Enter reason:", "Reason") == GUI::InputBox::ExecOK)
- m_client->handle_kick_user_action(m_name.characters(), m_client->nick_without_prefix(nick.characters()), value);
- }));
-
- auto& context_ctcp_menu = m_context_menu->add_submenu("CTCP");
-
- context_ctcp_menu.add_action(GUI::Action::create("User info", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "USERINFO");
- }));
-
- context_ctcp_menu.add_action(GUI::Action::create("Finger", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "FINGER");
- }));
-
- context_ctcp_menu.add_action(GUI::Action::create("Time", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "TIME");
- }));
-
- context_ctcp_menu.add_action(GUI::Action::create("Version", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "VERSION");
- }));
-
- context_ctcp_menu.add_action(GUI::Action::create("Client info", [&](const GUI::Action&) {
- auto nick = channel().member_model()->nick_at(member_view.selection().first());
- if (nick.is_empty())
- return;
- m_client->handle_ctcp_user_action(m_client->nick_without_prefix(nick.characters()), "CLIENTINFO");
- }));
-
- m_context_menu->popup(event.screen_position());
- };
- }
-
- m_text_box = add<GUI::TextBox>();
- m_text_box->set_fixed_height(19);
- m_text_box->on_return_pressed = [this] {
- if (m_type == Channel)
- m_client->handle_user_input_in_channel(m_name, m_text_box->text());
- else if (m_type == Query)
- m_client->handle_user_input_in_query(m_name, m_text_box->text());
- else if (m_type == Server)
- m_client->handle_user_input_in_server(m_text_box->text());
- m_text_box->add_current_text_to_history();
- m_text_box->clear();
- };
- m_text_box->set_history_enabled(true);
- m_text_box->set_placeholder("Message");
-
- m_client->register_subwindow(*this);
-}
-
-IRCWindow::~IRCWindow()
-{
- m_client->unregister_subwindow(*this);
-}
-
-void IRCWindow::set_log_buffer(const IRCLogBuffer& log_buffer)
-{
- m_log_buffer = &log_buffer;
- m_page_view->set_document(const_cast<Web::DOM::Document*>(&log_buffer.document()));
-}
-
-bool IRCWindow::is_active() const
-{
- return m_client->current_window() == this;
-}
-
-void IRCWindow::post_notification_if_needed(const String& name, const String& message)
-{
- if (name.is_null() || message.is_null())
- return;
- if (is_active() && window()->is_active())
- return;
-
- auto notification = GUI::Notification::construct();
-
- if (type() == Type::Channel) {
- if (!m_client->notify_on_mention())
- return;
- if (!message.contains(m_client->nickname()))
- return;
-
- StringBuilder builder;
- builder.append(name);
- builder.append(" in ");
- builder.append(m_name);
- notification->set_title(builder.to_string());
- } else {
- if (!m_client->notify_on_message())
- return;
- notification->set_title(name);
- }
-
- notification->set_icon(Gfx::Bitmap::load_from_file("/res/icons/32x32/app-irc-client.png"));
- notification->set_text(message);
- notification->show();
-}
-
-void IRCWindow::did_add_message(const String& name, const String& message)
-{
- post_notification_if_needed(name, message);
-
- if (!is_active()) {
- ++m_unread_count;
- m_client->aid_update_window_list();
- return;
- }
- m_page_view->scroll_to_bottom();
-}
-
-void IRCWindow::clear_unread_count()
-{
- if (!m_unread_count)
- return;
- m_unread_count = 0;
- m_client->aid_update_window_list();
-}
-
-int IRCWindow::unread_count() const
-{
- return m_unread_count;
-}
diff --git a/Applications/IRCClient/IRCWindow.h b/Applications/IRCClient/IRCWindow.h
deleted file mode 100644
index a26e00d65e..0000000000
--- a/Applications/IRCClient/IRCWindow.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-#include <LibWeb/Forward.h>
-
-class IRCChannel;
-class IRCClient;
-class IRCQuery;
-class IRCLogBuffer;
-
-class IRCWindow : public GUI::Widget {
- C_OBJECT(IRCWindow)
-public:
- enum Type {
- Server,
- Channel,
- Query,
- };
-
- virtual ~IRCWindow() override;
-
- String name() const { return m_name; }
- void set_name(const String& name) { m_name = name; }
-
- Type type() const { return m_type; }
-
- void set_log_buffer(const IRCLogBuffer&);
-
- bool is_active() const;
-
- int unread_count() const;
- void clear_unread_count();
-
- void did_add_message(const String& name = {}, const String& message = {});
-
- IRCChannel& channel() { return *(IRCChannel*)m_owner; }
- const IRCChannel& channel() const { return *(const IRCChannel*)m_owner; }
-
- IRCQuery& query() { return *(IRCQuery*)m_owner; }
- const IRCQuery& query() const { return *(const IRCQuery*)m_owner; }
-
-private:
- IRCWindow(IRCClient&, void* owner, Type, const String& name);
-
- void post_notification_if_needed(const String& name, const String& message);
-
- NonnullRefPtr<IRCClient> m_client;
- void* m_owner { nullptr };
- Type m_type;
- String m_name;
- RefPtr<Web::InProcessWebView> m_page_view;
- RefPtr<GUI::TextBox> m_text_box;
- RefPtr<IRCLogBuffer> m_log_buffer;
- RefPtr<GUI::Menu> m_context_menu;
- int m_unread_count { 0 };
-};
diff --git a/Applications/IRCClient/IRCWindowListModel.cpp b/Applications/IRCClient/IRCWindowListModel.cpp
deleted file mode 100644
index 7ee68c429e..0000000000
--- a/Applications/IRCClient/IRCWindowListModel.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCWindowListModel.h"
-#include "IRCChannel.h"
-#include "IRCClient.h"
-
-IRCWindowListModel::IRCWindowListModel(IRCClient& client)
- : m_client(client)
-{
-}
-
-IRCWindowListModel::~IRCWindowListModel()
-{
-}
-
-int IRCWindowListModel::row_count(const GUI::ModelIndex&) const
-{
- return m_client->window_count();
-}
-
-int IRCWindowListModel::column_count(const GUI::ModelIndex&) const
-{
- return 1;
-}
-
-String IRCWindowListModel::column_name(int column) const
-{
- switch (column) {
- case Column::Name:
- return "Name";
- }
- ASSERT_NOT_REACHED();
-}
-
-GUI::Variant IRCWindowListModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- if (role == GUI::ModelRole::TextAlignment)
- return Gfx::TextAlignment::CenterLeft;
- if (role == GUI::ModelRole::Display) {
- switch (index.column()) {
- case Column::Name: {
- auto& window = m_client->window_at(index.row());
- if (window.unread_count())
- return String::formatted("{} ({})", window.name(), window.unread_count());
- return window.name();
- }
- }
- }
- if (role == GUI::ModelRole::ForegroundColor) {
- switch (index.column()) {
- case Column::Name: {
- auto& window = m_client->window_at(index.row());
- if (window.unread_count())
- return Color(Color::Red);
- if (!window.channel().is_open())
- return Color(Color::WarmGray);
- return Color(Color::Black);
- }
- }
- }
- return {};
-}
-
-void IRCWindowListModel::update()
-{
- did_update();
-}
diff --git a/Applications/IRCClient/IRCWindowListModel.h b/Applications/IRCClient/IRCWindowListModel.h
deleted file mode 100644
index 88e5463b82..0000000000
--- a/Applications/IRCClient/IRCWindowListModel.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <LibGUI/Model.h>
-
-class IRCClient;
-class IRCWindow;
-
-class IRCWindowListModel final : public GUI::Model {
-public:
- enum Column {
- Name,
- };
-
- static NonnullRefPtr<IRCWindowListModel> create(IRCClient& client) { return adopt(*new IRCWindowListModel(client)); }
- virtual ~IRCWindowListModel() override;
-
- virtual int row_count(const GUI::ModelIndex&) const override;
- virtual int column_count(const GUI::ModelIndex&) const override;
- virtual String column_name(int column) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual void update() override;
-
-private:
- explicit IRCWindowListModel(IRCClient&);
-
- NonnullRefPtr<IRCClient> m_client;
-};
diff --git a/Applications/IRCClient/main.cpp b/Applications/IRCClient/main.cpp
deleted file mode 100644
index a0adf92c0d..0000000000
--- a/Applications/IRCClient/main.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "IRCAppWindow.h"
-#include "IRCClient.h"
-#include <LibCore/StandardPaths.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/MessageBox.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio inet dns unix shared_buffer cpath rpath fattr wpath cpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (getuid() == 0) {
- warnln("Refusing to run as root");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio inet dns unix shared_buffer rpath wpath cpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/tmp/portal/lookup", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/notify", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/etc/passwd", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(Core::StandardPaths::home_directory().characters(), "rwc") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- URL url = "";
- if (app->args().size() >= 1) {
- url = URL::create_with_url_or_path(app->args()[0]);
-
- if (url.protocol().to_lowercase() == "ircs") {
- warnln("Secure IRC over SSL/TLS (ircs) is not supported");
- return 1;
- }
-
- if (url.protocol().to_lowercase() != "irc") {
- warnln("Unsupported protocol");
- return 1;
- }
-
- if (url.host().is_empty()) {
- warnln("Invalid URL");
- return 1;
- }
-
- if (!url.port() || url.port() == 80)
- url.set_port(6667);
- }
-
- auto app_window = IRCAppWindow::construct(url.host(), url.port());
- app_window->show();
- return app->exec();
-}
diff --git a/Applications/KeyboardMapper/CMakeLists.txt b/Applications/KeyboardMapper/CMakeLists.txt
deleted file mode 100644
index fe24376eb1..0000000000
--- a/Applications/KeyboardMapper/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(SOURCES
- KeyboardMapperWidget.cpp
- KeyButton.cpp
- main.cpp
-)
-
-serenity_bin(KeyboardMapper)
-target_link_libraries(KeyboardMapper LibGUI LibKeyboard)
diff --git a/Applications/KeyboardMapper/KeyButton.cpp b/Applications/KeyboardMapper/KeyButton.cpp
deleted file mode 100644
index 58a687faca..0000000000
--- a/Applications/KeyboardMapper/KeyButton.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "KeyButton.h"
-#include <LibGUI/Button.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Palette.h>
-
-KeyButton::~KeyButton()
-{
-}
-
-void KeyButton::paint_event(GUI::PaintEvent& event)
-{
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- auto cont_rect = rect();
- auto& font = this->font();
-
- Color color;
- if (m_pressed) {
- color = Color::Cyan;
- } else if (!is_enabled()) {
- color = Color::LightGray;
- } else {
- color = Color::White;
- }
-
- painter.fill_rect(cont_rect, Color::Black);
- painter.fill_rect({ cont_rect.x() + 1, cont_rect.y() + 1, cont_rect.width() - 2, cont_rect.height() - 2 }, Color::from_rgb(0x999999));
- painter.fill_rect({ cont_rect.x() + 6, cont_rect.y() + 3, cont_rect.width() - 12, cont_rect.height() - 12 }, Color::from_rgb(0x8C7272));
- painter.fill_rect({ cont_rect.x() + 7, cont_rect.y() + 4, cont_rect.width() - 14, cont_rect.height() - 14 }, color);
-
- if (!text().is_empty()) {
- Gfx::IntRect text_rect { 0, 0, font.width(text()), font.glyph_height() };
- text_rect.align_within({ cont_rect.x() + 7, cont_rect.y() + 4, cont_rect.width() - 14, cont_rect.height() - 14 }, Gfx::TextAlignment::Center);
-
- painter.draw_text(text_rect, text(), font, Gfx::TextAlignment::Center, palette().button_text(), Gfx::TextElision::Right);
- if (is_focused())
- painter.draw_rect(text_rect.inflated(6, 4), palette().focus_outline());
- }
-}
-
-void KeyButton::click(unsigned)
-{
- if (on_click)
- on_click();
-}
-
-void KeyButton::mousemove_event(GUI::MouseEvent& event)
-{
- if (!is_enabled())
- return;
-
- Gfx::IntRect c = { rect().x() + 7, rect().y() + 4, rect().width() - 14, rect().height() - 14 };
-
- if (c.contains(event.position())) {
- window()->set_cursor(Gfx::StandardCursor::Hand);
- return;
- }
- window()->set_cursor(Gfx::StandardCursor::Arrow);
-
- AbstractButton::mousemove_event(event);
-}
-
-void KeyButton::leave_event(Core::Event& event)
-{
- window()->set_cursor(Gfx::StandardCursor::Arrow);
- AbstractButton::leave_event(event);
-}
diff --git a/Applications/KeyboardMapper/KeyButton.h b/Applications/KeyboardMapper/KeyButton.h
deleted file mode 100644
index afb57033b3..0000000000
--- a/Applications/KeyboardMapper/KeyButton.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/AbstractButton.h>
-
-class KeyButton : public GUI::AbstractButton {
- C_OBJECT(KeyButton)
-
-public:
- virtual ~KeyButton() override;
-
- void set_pressed(bool value) { m_pressed = value; }
-
- Function<void()> on_click;
-
-protected:
- virtual void click(unsigned modifiers = 0) override;
- virtual void leave_event(Core::Event&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void paint_event(GUI::PaintEvent&) override;
-
-private:
- bool m_pressed { false };
-};
diff --git a/Applications/KeyboardMapper/KeyPositions.h b/Applications/KeyboardMapper/KeyPositions.h
deleted file mode 100644
index 3cd9dbaaf7..0000000000
--- a/Applications/KeyboardMapper/KeyPositions.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-
-struct KeyPosition {
- u32 scancode;
- int x;
- int y;
- int width;
- int height;
- bool enabled;
- int map_index;
- AK::String name;
-};
-
-#define KEY_COUNT 63
-
-struct KeyPosition keys[KEY_COUNT] = {
- // clang-format off
- [ 0] = { 0, 0, 0, 0, 0, false, 0, ""},
-
- [ 1] = { 0x29, 0, 0, 50, 50, true, 41, "`"},
- [ 2] = { 0x02, 51, 0, 50, 50, true, 2, "1"},
- [ 3] = { 0x03, 102, 0, 50, 50, true, 3, "2"},
- [ 4] = { 0x04, 153, 0, 50, 50, true, 4, "3"},
- [ 5] = { 0x05, 204, 0, 50, 50, true, 5, "4"},
- [ 6] = { 0x06, 255, 0, 50, 50, true, 6, "5"},
- [ 7] = { 0x07, 306, 0, 50, 50, true, 7, "6"},
- [ 8] = { 0x08, 357, 0, 50, 50, true, 8, "7"},
- [ 9] = { 0x09, 408, 0, 50, 50, true, 9, "8"},
- [10] = { 0x0A, 459, 0, 50, 50, true, 10, "9"},
- [11] = { 0x0B, 510, 0, 50, 50, true, 11, "0"},
- [12] = { 0x0C, 561, 0, 50, 50, true, 12, "-"},
- [13] = { 0x0D, 612, 0, 50, 50, true, 13, "="},
- [14] = { 0x0E, 663, 0, 100, 50, false, 0, "back space"},
-
- [15] = { 0x0F, 0, 52, 76, 50, false, 0, "tab"},
- [16] = { 0x10, 77, 52, 50, 50, true, 16, "q"},
- [17] = { 0x11, 128, 52, 50, 50, true, 17, "w"},
- [18] = { 0x12, 179, 52, 50, 50, true, 18, "e"},
- [19] = { 0x13, 230, 52, 50, 50, true, 19, "r"},
- [20] = { 0x14, 281, 52, 50, 50, true, 20, "t"},
- [21] = { 0x15, 332, 52, 50, 50, true, 21, "y"},
- [22] = { 0x16, 383, 52, 50, 50, true, 22, "u"},
- [23] = { 0x17, 434, 52, 50, 50, true, 23, "ı"},
- [24] = { 0x18, 485, 52, 50, 50, true, 24, "o"},
- [25] = { 0x19, 536, 52, 50, 50, true, 25, "p"},
- [26] = { 0x1A, 587, 52, 50, 50, true, 26, "["},
- [27] = { 0x1B, 638, 52, 50, 50, true, 27, "]"},
- [28] = { 0x1C, 689, 52, 74, 50, false, 0, "enter"},
-
- [29] = { 0x3A, 0, 104, 101, 50, false, 0, "caps lock"},
- [30] = { 0x1E, 103, 104, 50, 50, true, 30, "a"},
- [31] = { 0x1F, 154, 104, 50, 50, true, 31, "s"},
- [32] = { 0x20, 205, 104, 50, 50, true, 32, "d"},
- [33] = { 0x21, 256, 104, 50, 50, true, 33, "f"},
- [34] = { 0x22, 307, 104, 50, 50, true, 34, "g"},
- [35] = { 0x23, 358, 104, 50, 50, true, 35, "h"},
- [36] = { 0x24, 409, 104, 50, 50, true, 36, "j"},
- [37] = { 0x25, 460, 104, 50, 50, true, 37, "k"},
- [38] = { 0x26, 511, 104, 50, 50, true, 38, "l"},
- [39] = { 0x27, 562, 104, 50, 50, true, 39, ";"},
- [40] = { 0x28, 614, 104, 50, 50, true, 40, "\""},
- [41] = { 0x2B, 665, 104, 50, 50, true, 43, "\\"},
-
- [42] = { 0x2A, 0, 156, 76, 50, false, 0, "left shift"},
- [43] = { 0x56, 77, 156, 50, 50, true, 86, "\\"},
- [44] = { 0x2C, 128, 156, 50, 50, true, 44, "z"},
- [45] = { 0x2D, 179, 156, 50, 50, true, 45, "x"},
- [46] = { 0x2E, 230, 156, 50, 50, true, 46, "c"},
- [47] = { 0x2F, 281, 156, 50, 50, true, 47, "v"},
- [48] = { 0x30, 332, 156, 50, 50, true, 48, "b"},
- [49] = { 0x31, 383, 156, 50, 50, true, 49, "n"},
- [50] = { 0x32, 434, 156, 50, 50, true, 50, "m"},
- [51] = { 0x33, 485, 156, 50, 50, true, 51, ","},
- [52] = { 0x34, 536, 156, 50, 50, true, 52, "."},
- [53] = { 0x35, 587, 156, 50, 50, true, 53, "/"},
- [54] = { 0x36, 638, 156, 125, 50, false, 0, "right shift"},
-
- [55] = { 0x1D, 0, 208, 76, 50, false, 0, "left ctrl"},
- [56] = {0xE05B, 77, 208, 50, 50, false, 0, "left\nsuper"},
- [57] = { 0x38, 128, 208, 50, 50, false, 0, "alt"},
- [58] = { 0x39, 179, 208, 356, 50, false, 0, "space"},
- [59] = {0xE038, 536, 208, 50, 50, false, 0, "alt gr"},
- [60] = {0xE05C, 587, 208, 50, 50, false, 0, "right\nsuper"},
- [61] = {0xE05D, 638, 208, 50, 50, false, 0, "menu"},
- [62] = {0xE01D, 689, 208, 74, 50, false, 0, "right ctrl"}
- // clang-format on
-};
diff --git a/Applications/KeyboardMapper/KeyboardMapperWidget.cpp b/Applications/KeyboardMapper/KeyboardMapperWidget.cpp
deleted file mode 100644
index 24df141a01..0000000000
--- a/Applications/KeyboardMapper/KeyboardMapperWidget.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "KeyboardMapperWidget.h"
-#include "KeyPositions.h"
-#include <LibCore/File.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/InputBox.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/RadioButton.h>
-#include <LibKeyboard/CharacterMapFile.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-
-KeyboardMapperWidget::KeyboardMapperWidget()
-{
- create_frame();
-}
-
-KeyboardMapperWidget::~KeyboardMapperWidget()
-{
-}
-
-void KeyboardMapperWidget::create_frame()
-{
- set_fill_with_background_color(true);
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& main_widget = add<GUI::Widget>();
- main_widget.set_relative_rect(0, 0, 200, 200);
-
- m_keys.resize(KEY_COUNT);
-
- for (unsigned i = 0; i < KEY_COUNT; i++) {
- Gfx::IntRect rect = { keys[i].x, keys[i].y, keys[i].width, keys[i].height };
-
- auto& tmp_button = main_widget.add<KeyButton>();
- tmp_button.set_relative_rect(rect);
- tmp_button.set_text(keys[i].name);
- tmp_button.set_enabled(keys[i].enabled);
-
- tmp_button.on_click = [this, &tmp_button]() {
- String value;
- if (GUI::InputBox::show(value, window(), "New Character:", "Select Character") == GUI::InputBox::ExecOK) {
- int i = m_keys.find_first_index(&tmp_button).value_or(0);
- ASSERT(i > 0);
-
- auto index = keys[i].map_index;
- ASSERT(index > 0);
-
- tmp_button.set_text(value);
- u32* map;
-
- if (m_current_map_name == "map") {
- map = m_character_map.map;
- } else if (m_current_map_name == "shift_map") {
- map = m_character_map.shift_map;
- } else if (m_current_map_name == "alt_map") {
- map = m_character_map.alt_map;
- } else if (m_current_map_name == "altgr_map") {
- map = m_character_map.altgr_map;
- } else if (m_current_map_name == "shift_altgr_map") {
- map = m_character_map.shift_altgr_map;
- } else {
- ASSERT_NOT_REACHED();
- }
-
- if (value.length() == 0)
- map[index] = '\0'; // Empty string
- else
- map[index] = value[0];
-
- m_modified = true;
- update_window_title();
- }
- };
-
- m_keys.insert(i, &tmp_button);
- }
-
- // Action Buttons
- auto& bottom_widget = add<GUI::Widget>();
- bottom_widget.set_layout<GUI::HorizontalBoxLayout>();
- bottom_widget.set_fixed_height(40);
-
- // Map Selection
- m_map_group = bottom_widget.add<GUI::Widget>();
- m_map_group->set_layout<GUI::HorizontalBoxLayout>();
- m_map_group->set_fixed_width(250);
-
- auto& radio_map = m_map_group->add<GUI::RadioButton>("Default");
- radio_map.set_name("map");
- radio_map.on_checked = [&](bool) {
- set_current_map("map");
- };
- auto& radio_shift = m_map_group->add<GUI::RadioButton>("Shift");
- radio_shift.set_name("shift_map");
- radio_shift.on_checked = [this](bool) {
- set_current_map("shift_map");
- };
- auto& radio_altgr = m_map_group->add<GUI::RadioButton>("AltGr");
- radio_altgr.set_name("altgr_map");
- radio_altgr.on_checked = [this](bool) {
- set_current_map("altgr_map");
- };
- auto& radio_alt = m_map_group->add<GUI::RadioButton>("Alt");
- radio_alt.set_name("alt_map");
- radio_alt.on_checked = [this](bool) {
- set_current_map("alt_map");
- };
- auto& radio_shift_altgr = m_map_group->add<GUI::RadioButton>("Shift+AltGr");
- radio_shift_altgr.set_name("shift_altgr_map");
- radio_shift_altgr.on_checked = [this](bool) {
- set_current_map("shift_altgr_map");
- };
-
- bottom_widget.layout()->add_spacer();
-
- auto& ok_button = bottom_widget.add<GUI::Button>();
- ok_button.set_text("Save");
- ok_button.set_fixed_width(80);
- ok_button.on_click = [this](auto) {
- save();
- };
-}
-
-void KeyboardMapperWidget::load_from_file(String file_name)
-{
- auto result = Keyboard::CharacterMapFile::load_from_file(file_name);
- if (!result.has_value()) {
- ASSERT_NOT_REACHED();
- }
-
- m_file_name = file_name;
- m_character_map = result.value();
- set_current_map("map");
-
- for (Widget* widget : m_map_group->child_widgets()) {
- auto radio_button = (GUI::RadioButton*)widget;
- radio_button->set_checked(radio_button->name() == "map");
- }
-
- update_window_title();
-}
-
-void KeyboardMapperWidget::save()
-{
- save_to_file(m_file_name);
-}
-
-void KeyboardMapperWidget::save_to_file(const StringView& file_name)
-{
- JsonObject map_json;
-
- auto add_array = [&](String name, u32* values) {
- JsonArray items;
- for (int i = 0; i < 90; i++) {
- AK::StringBuilder sb;
- sb.append(values[i]);
-
- JsonValue val(sb.to_string());
- items.append(move(val));
- }
- map_json.set(name, move(items));
- };
-
- add_array("map", m_character_map.map);
- add_array("shift_map", m_character_map.shift_map);
- add_array("alt_map", m_character_map.alt_map);
- add_array("altgr_map", m_character_map.altgr_map);
- add_array("shift_altgr_map", m_character_map.shift_altgr_map);
-
- // Write to file.
- String file_content = map_json.to_string();
-
- auto file = Core::File::construct(file_name);
- file->open(Core::IODevice::WriteOnly);
- if (!file->is_open()) {
- StringBuilder sb;
- sb.append("Failed to open ");
- sb.append(file_name);
- sb.append(" for write. Error: ");
- sb.append(file->error_string());
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- bool result = file->write(file_content);
- if (!result) {
- int error_number = errno;
- StringBuilder sb;
- sb.append("Unable to save file. Error: ");
- sb.append(strerror(error_number));
-
- GUI::MessageBox::show(window(), sb.to_string(), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_modified = false;
- m_file_name = file_name;
- update_window_title();
-}
-
-void KeyboardMapperWidget::keydown_event(GUI::KeyEvent& event)
-{
- for (int i = 0; i < KEY_COUNT; i++) {
- auto& tmp_button = m_keys.at(i);
- tmp_button->set_pressed(keys[i].scancode == event.scancode());
- tmp_button->update();
- }
-}
-
-void KeyboardMapperWidget::keyup_event(GUI::KeyEvent& event)
-{
- for (int i = 0; i < KEY_COUNT; i++) {
- if (keys[i].scancode == event.scancode()) {
- auto& tmp_button = m_keys.at(i);
- tmp_button->set_pressed(false);
- tmp_button->update();
- break;
- }
- }
-}
-
-void KeyboardMapperWidget::set_current_map(const String current_map)
-{
- m_current_map_name = current_map;
- u32* map;
-
- if (m_current_map_name == "map") {
- map = m_character_map.map;
- } else if (m_current_map_name == "shift_map") {
- map = m_character_map.shift_map;
- } else if (m_current_map_name == "alt_map") {
- map = m_character_map.alt_map;
- } else if (m_current_map_name == "altgr_map") {
- map = m_character_map.altgr_map;
- } else if (m_current_map_name == "shift_altgr_map") {
- map = m_character_map.shift_altgr_map;
- } else {
- ASSERT_NOT_REACHED();
- }
-
- for (unsigned k = 0; k < KEY_COUNT; k++) {
- auto index = keys[k].map_index;
- if (index == 0)
- continue;
-
- AK::StringBuilder sb;
- sb.append_code_point(map[index]);
-
- m_keys.at(k)->set_text(sb.to_string());
- }
-
- this->update();
-}
-
-void KeyboardMapperWidget::update_window_title()
-{
- StringBuilder sb;
- sb.append(m_file_name);
- if (m_modified)
- sb.append(" (*)");
- sb.append(" - KeyboardMapper");
-
- window()->set_title(sb.to_string());
-}
diff --git a/Applications/KeyboardMapper/KeyboardMapperWidget.h b/Applications/KeyboardMapper/KeyboardMapperWidget.h
deleted file mode 100644
index e0df34ed78..0000000000
--- a/Applications/KeyboardMapper/KeyboardMapperWidget.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "KeyButton.h"
-#include <LibGUI/Button.h>
-#include <LibKeyboard/CharacterMapData.h>
-
-class KeyboardMapperWidget : public GUI::Widget {
- C_OBJECT(KeyboardMapperWidget)
-
-public:
- KeyboardMapperWidget();
- virtual ~KeyboardMapperWidget() override;
-
- void create_frame();
- void load_from_file(const String);
- void save();
- void save_to_file(const StringView&);
-
-protected:
- virtual void keydown_event(GUI::KeyEvent&) override;
- virtual void keyup_event(GUI::KeyEvent&) override;
-
- void set_current_map(const String);
- void update_window_title();
-
-private:
- Vector<KeyButton*> m_keys;
- RefPtr<GUI::Widget> m_map_group;
-
- String m_file_name;
- Keyboard::CharacterMapData m_character_map;
- String m_current_map_name;
- bool m_modified { false };
-};
diff --git a/Applications/KeyboardMapper/main.cpp b/Applications/KeyboardMapper/main.cpp
deleted file mode 100644
index 0edeef72fe..0000000000
--- a/Applications/KeyboardMapper/main.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "KeyboardMapperWidget.h"
-#include <LibCore/ArgsParser.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-
-int main(int argc, char** argv)
-{
- const char* path = nullptr;
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(path, "Keyboard character mapping file.", "file", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-keyboard-mapper");
-
- auto window = GUI::Window::construct();
- window->set_title("Keyboard Mapper");
- window->set_icon(app_icon.bitmap_for_size(16));
- window->set_main_widget<KeyboardMapperWidget>();
- window->resize(775, 315);
- window->set_resizable(false);
- window->show();
-
- auto keyboard_mapper_widget = (KeyboardMapperWidget*)window->main_widget();
- if (path != nullptr) {
- keyboard_mapper_widget->load_from_file(path);
- } else {
- keyboard_mapper_widget->load_from_file("/res/keymaps/en.json");
- }
-
- // Actions
- auto open_action = GUI::CommonActions::make_open_action(
- [&](auto&) {
- Optional<String> path = GUI::FilePicker::get_open_filepath(window, "Open");
- if (path.has_value()) {
- keyboard_mapper_widget->load_from_file(path.value());
- }
- });
-
- auto save_action = GUI::CommonActions::make_save_action(
- [&](auto&) {
- keyboard_mapper_widget->save();
- });
-
- auto save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
- String m_name = "Unnamed";
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, m_name, "json");
- if (!save_path.has_value())
- return;
-
- keyboard_mapper_widget->save_to_file(save_path.value());
- });
-
- auto quit_action = GUI::CommonActions::make_quit_action(
- [&](auto&) {
- app->quit();
- });
-
- // Menu
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Keyboard Mapper");
- app_menu.add_action(open_action);
- app_menu.add_action(save_action);
- app_menu.add_action(save_as_action);
- app_menu.add_separator();
- app_menu.add_action(quit_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Keyboard Mapper", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- return app->exec();
-}
diff --git a/Applications/KeyboardSettings/CMakeLists.txt b/Applications/KeyboardSettings/CMakeLists.txt
deleted file mode 100644
index 62212cda36..0000000000
--- a/Applications/KeyboardSettings/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(SOURCES
- main.cpp
-)
-
-serenity_app(KeyboardSettings ICON app-keyboard-settings)
-target_link_libraries(KeyboardSettings LibGUI LibKeyboard)
diff --git a/Applications/KeyboardSettings/CharacterMapFileListModel.h b/Applications/KeyboardSettings/CharacterMapFileListModel.h
deleted file mode 100644
index 4fcd1d8123..0000000000
--- a/Applications/KeyboardSettings/CharacterMapFileListModel.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Vector.h>
-#include <LibGUI/Model.h>
-
-class CharacterMapFileListModel final : public GUI::Model {
-public:
- static NonnullRefPtr<CharacterMapFileListModel> create(Vector<String>& file_names)
- {
- return adopt(*new CharacterMapFileListModel(file_names));
- }
-
- virtual ~CharacterMapFileListModel() override { }
-
- virtual int row_count(const GUI::ModelIndex&) const override
- {
- return m_file_names.size();
- }
-
- virtual int column_count(const GUI::ModelIndex&) const override
- {
- return 1;
- }
-
- virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role) const override
- {
- ASSERT(index.is_valid());
- ASSERT(index.column() == 0);
-
- if (role == GUI::ModelRole::Display)
- return m_file_names.at(index.row());
-
- return {};
- }
-
- virtual void update() override
- {
- did_update();
- }
-
-private:
- explicit CharacterMapFileListModel(Vector<String>& file_names)
- : m_file_names(file_names)
- {
- }
-
- Vector<String>& m_file_names;
-};
diff --git a/Applications/KeyboardSettings/main.cpp b/Applications/KeyboardSettings/main.cpp
deleted file mode 100644
index 8b515d815e..0000000000
--- a/Applications/KeyboardSettings/main.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CharacterMapFileListModel.h"
-#include <AK/JsonObject.h>
-#include <AK/QuickSort.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/ComboBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibKeyboard/CharacterMap.h>
-#include <spawn.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio rpath accept cpath wpath shared_buffer unix fattr proc exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- // If there is no command line parameter go for GUI.
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio rpath accept shared_buffer proc exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin/keymap", "x") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/proc/keymap", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr)) {
- perror("unveil");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-keyboard-settings");
-
- auto proc_keymap = Core::File::construct("/proc/keymap");
- if (!proc_keymap->open(Core::IODevice::OpenMode::ReadOnly))
- ASSERT_NOT_REACHED();
-
- auto json = JsonValue::from_string(proc_keymap->read_all());
- ASSERT(json.has_value());
- JsonObject keymap_object = json.value().as_object();
- ASSERT(keymap_object.has("keymap"));
- String current_keymap = keymap_object.get("keymap").to_string();
- dbgln("KeyboardSettings thinks the current keymap is: {}", current_keymap);
-
- Vector<String> character_map_files;
- Core::DirIterator iterator("/res/keymaps/", Core::DirIterator::Flags::SkipDots);
- if (iterator.has_error()) {
- GUI::MessageBox::show(nullptr, String::formatted("Error on reading mapping file list: {}", iterator.error_string()), "Keyboard settings", GUI::MessageBox::Type::Error);
- return -1;
- }
-
- while (iterator.has_next()) {
- auto name = iterator.next_path();
- name.replace(".json", "");
- character_map_files.append(name);
- }
- quick_sort(character_map_files);
-
- size_t initial_keymap_index = SIZE_MAX;
- for (size_t i = 0; i < character_map_files.size(); ++i) {
- if (character_map_files[i].equals_ignoring_case(current_keymap))
- initial_keymap_index = i;
- }
- ASSERT(initial_keymap_index < character_map_files.size());
-
- auto window = GUI::Window::construct();
- window->set_title("Keyboard Settings");
- window->resize(300, 70);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto& root_widget = window->set_main_widget<GUI::Widget>();
- root_widget.set_layout<GUI::VerticalBoxLayout>();
- root_widget.set_fill_with_background_color(true);
- root_widget.layout()->set_spacing(0);
- root_widget.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& character_map_file_selection_container = root_widget.add<GUI::Widget>();
- character_map_file_selection_container.set_layout<GUI::HorizontalBoxLayout>();
- character_map_file_selection_container.set_fixed_height(22);
-
- auto& character_map_file_label = character_map_file_selection_container.add<GUI::Label>();
- character_map_file_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- character_map_file_label.set_fixed_width(130);
- character_map_file_label.set_text("Character Mapping File:");
-
- auto& character_map_file_combo = character_map_file_selection_container.add<GUI::ComboBox>();
- character_map_file_combo.set_only_allow_values_from_model(true);
- character_map_file_combo.set_model(*CharacterMapFileListModel::create(character_map_files));
- character_map_file_combo.set_selected_index(initial_keymap_index);
-
- root_widget.layout()->add_spacer();
-
- auto apply_settings = [&](bool quit) {
- String character_map_file = character_map_file_combo.text();
- if (character_map_file.is_empty()) {
- GUI::MessageBox::show(window, "Please select character mapping file.", "Keyboard settings", GUI::MessageBox::Type::Error);
- return;
- }
- pid_t child_pid;
- const char* argv[] = { "/bin/keymap", character_map_file.characters(), nullptr };
- if ((errno = posix_spawn(&child_pid, "/bin/keymap", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- exit(1);
- }
- if (quit)
- app->quit();
- };
-
- auto& bottom_widget = root_widget.add<GUI::Widget>();
- bottom_widget.set_layout<GUI::HorizontalBoxLayout>();
- bottom_widget.layout()->add_spacer();
- bottom_widget.set_fixed_height(22);
-
- auto& apply_button = bottom_widget.add<GUI::Button>();
- apply_button.set_text("Apply");
- apply_button.set_fixed_width(60);
- apply_button.on_click = [&](auto) {
- apply_settings(false);
- };
-
- auto& ok_button = bottom_widget.add<GUI::Button>();
- ok_button.set_text("OK");
- ok_button.set_fixed_width(60);
- ok_button.on_click = [&](auto) {
- apply_settings(true);
- };
-
- auto& cancel_button = bottom_widget.add<GUI::Button>();
- cancel_button.set_text("Cancel");
- cancel_button.set_fixed_width(60);
- cancel_button.on_click = [&](auto) {
- app->quit();
- };
-
- auto quit_action = GUI::CommonActions::make_quit_action(
- [&](auto&) {
- app->quit();
- });
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Keyboard Settings");
- app_menu.add_action(quit_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Keyboard Settings", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/MouseSettings/CMakeLists.txt b/Applications/MouseSettings/CMakeLists.txt
deleted file mode 100644
index f52df8d76c..0000000000
--- a/Applications/MouseSettings/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(SOURCES
- main.cpp
-)
-
-serenity_app(MouseSettings ICON app-mouse)
-target_link_libraries(MouseSettings LibGUI)
diff --git a/Applications/MouseSettings/main.cpp b/Applications/MouseSettings/main.cpp
deleted file mode 100644
index 74b07d0b0a..0000000000
--- a/Applications/MouseSettings/main.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2020, Idan Horowitz <idan.horowitz@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Slider.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/SystemTheme.h>
-#include <WindowServer/Screen.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio cpath rpath shared_buffer unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio cpath rpath shared_buffer", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-mouse");
- auto window = GUI::Window::construct();
- window->set_title("Mouse Settings");
- window->resize(200, 130);
- window->set_resizable(false);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto& settings = window->set_main_widget<GUI::Widget>();
- settings.set_fill_with_background_color(true);
- settings.set_background_role(ColorRole::Button);
- settings.set_layout<GUI::VerticalBoxLayout>();
- settings.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& speed_container = settings.add<GUI::GroupBox>("Mouse speed");
- speed_container.set_layout<GUI::VerticalBoxLayout>();
- speed_container.layout()->set_margins({ 6, 16, 6, 6 });
- speed_container.set_fixed_height(50);
-
- auto& speed_slider = speed_container.add<GUI::HorizontalSlider>();
- const auto scalar = 1000.0;
- speed_slider.set_range(WindowServer::mouse_accel_min * scalar, WindowServer::mouse_accel_max * scalar); // These values are scaled down (by a factor of 1000) to get fractional values
- int current_value = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetMouseAcceleration>()->factor() * scalar;
- speed_slider.set_value(current_value);
-
- auto& scroll_container = settings.add<GUI::GroupBox>("Scroll length");
- scroll_container.set_layout<GUI::VerticalBoxLayout>();
- scroll_container.layout()->set_margins({ 6, 16, 6, 6 });
- scroll_container.set_fixed_height(46);
-
- auto& scroll_spinbox = scroll_container.add<GUI::SpinBox>();
- scroll_spinbox.set_min(WindowServer::scroll_step_size_min);
- scroll_spinbox.set_value(GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetScrollStepSize>()->step_size());
-
- auto update_window_server = [&]() {
- float factor = speed_slider.value() / scalar;
- GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetMouseAcceleration>(factor);
- GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetScrollStepSize>(scroll_spinbox.value());
- };
-
- auto& prompt_buttons = settings.add<GUI::Widget>();
- prompt_buttons.set_layout<GUI::HorizontalBoxLayout>();
- prompt_buttons.set_fixed_height(22);
-
- auto& ok_button = prompt_buttons.add<GUI::Button>();
- ok_button.set_text("OK");
- prompt_buttons.set_fixed_height(22);
- ok_button.on_click = [&](auto) {
- update_window_server();
- app->quit();
- };
- auto& apply_button = prompt_buttons.add<GUI::Button>();
- apply_button.set_text("Apply");
- prompt_buttons.set_fixed_height(22);
- apply_button.on_click = [&](auto) {
- update_window_server();
- };
- auto& reset_button = prompt_buttons.add<GUI::Button>();
- reset_button.set_text("Reset");
- prompt_buttons.set_fixed_height(22);
- reset_button.on_click = [&](auto) {
- speed_slider.set_value(scalar);
- scroll_spinbox.set_value(4);
- update_window_server();
- };
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Mouse Settings");
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
- app->quit();
- }));
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Mouse Settings", app_icon, window));
- app->set_menubar(move(menubar));
-
- window->show();
- return app->exec();
-}
diff --git a/Applications/Piano/CMakeLists.txt b/Applications/Piano/CMakeLists.txt
deleted file mode 100644
index 382e023c3b..0000000000
--- a/Applications/Piano/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-set(SOURCES
- Track.cpp
- TrackManager.cpp
- KeysWidget.cpp
- KnobsWidget.cpp
- main.cpp
- MainWidget.cpp
- RollWidget.cpp
- SamplerWidget.cpp
- WaveWidget.cpp
-)
-
-serenity_app(Piano ICON app-piano)
-target_link_libraries(Piano LibAudio LibGUI)
diff --git a/Applications/Piano/KeysWidget.cpp b/Applications/Piano/KeysWidget.cpp
deleted file mode 100644
index 65fcdc39b5..0000000000
--- a/Applications/Piano/KeysWidget.cpp
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "KeysWidget.h"
-#include "TrackManager.h"
-#include <LibGUI/Painter.h>
-
-KeysWidget::KeysWidget(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
- set_fill_with_background_color(true);
-}
-
-KeysWidget::~KeysWidget()
-{
-}
-
-int KeysWidget::mouse_note() const
-{
- if (m_mouse_down && m_mouse_note + m_track_manager.octave_base() < note_count)
- return m_mouse_note; // Can be -1.
- else
- return -1;
-}
-
-void KeysWidget::set_key(int key, Switch switch_key)
-{
- if (key == -1 || key + m_track_manager.octave_base() >= note_count)
- return;
-
- if (switch_key == On) {
- ++m_key_on[key];
- } else {
- if (m_key_on[key] >= 1)
- --m_key_on[key];
- }
- ASSERT(m_key_on[key] <= 2);
-
- m_track_manager.set_note_current_octave(key, switch_key);
-}
-
-bool KeysWidget::note_is_set(int note) const
-{
- if (note < m_track_manager.octave_base())
- return false;
-
- if (note >= m_track_manager.octave_base() + note_count)
- return false;
-
- return m_key_on[note - m_track_manager.octave_base()] != 0;
-}
-
-int KeysWidget::key_code_to_key(int key_code) const
-{
- switch (key_code) {
- case Key_A:
- return 0;
- case Key_W:
- return 1;
- case Key_S:
- return 2;
- case Key_E:
- return 3;
- case Key_D:
- return 4;
- case Key_F:
- return 5;
- case Key_T:
- return 6;
- case Key_G:
- return 7;
- case Key_Y:
- return 8;
- case Key_H:
- return 9;
- case Key_U:
- return 10;
- case Key_J:
- return 11;
- case Key_K:
- return 12;
- case Key_O:
- return 13;
- case Key_L:
- return 14;
- case Key_P:
- return 15;
- case Key_Semicolon:
- return 16;
- case Key_Apostrophe:
- return 17;
- case Key_RightBracket:
- return 18;
- case Key_Return:
- return 19;
- default:
- return -1;
- }
-}
-
-constexpr int white_key_width = 24;
-constexpr int black_key_width = 16;
-constexpr int black_key_x_offset = black_key_width / 2;
-constexpr int black_key_height = 60;
-
-constexpr char white_key_labels[] = {
- 'A',
- 'S',
- 'D',
- 'F',
- 'G',
- 'H',
- 'J',
- 'K',
- 'L',
- ';',
- '\'',
- 'r',
-};
-constexpr int white_key_labels_count = sizeof(white_key_labels) / sizeof(char);
-
-constexpr char black_key_labels[] = {
- 'W',
- 'E',
- 'T',
- 'Y',
- 'U',
- 'O',
- 'P',
- ']',
-};
-constexpr int black_key_labels_count = sizeof(black_key_labels) / sizeof(char);
-
-constexpr int black_key_offsets[] = {
- white_key_width,
- white_key_width * 2,
- white_key_width,
- white_key_width,
- white_key_width * 2,
-};
-
-constexpr int white_key_note_accumulator[] = {
- 2,
- 2,
- 1,
- 2,
- 2,
- 2,
- 1,
-};
-
-constexpr int black_key_note_accumulator[] = {
- 2,
- 3,
- 2,
- 2,
- 3,
-};
-
-void KeysWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Painter painter(*this);
- painter.translate(frame_thickness(), frame_thickness());
-
- int note = 0;
- int x = 0;
- int i = 0;
- for (;;) {
- Gfx::IntRect rect(x, 0, white_key_width, frame_inner_rect().height());
- painter.fill_rect(rect, m_key_on[note] ? note_pressed_color : Color::White);
- painter.draw_rect(rect, Color::Black);
- if (i < white_key_labels_count) {
- rect.set_height(rect.height() * 1.5);
- painter.draw_text(rect, StringView(&white_key_labels[i], 1), Gfx::TextAlignment::Center, Color::Black);
- }
-
- note += white_key_note_accumulator[i % white_keys_per_octave];
- x += white_key_width;
- ++i;
-
- if (note + m_track_manager.octave_base() >= note_count)
- break;
- if (x >= frame_inner_rect().width())
- break;
- }
-
- note = 1;
- x = white_key_width - black_key_x_offset;
- i = 0;
- for (;;) {
- Gfx::IntRect rect(x, 0, black_key_width, black_key_height);
- painter.fill_rect(rect, m_key_on[note] ? note_pressed_color : Color::Black);
- painter.draw_rect(rect, Color::Black);
- if (i < black_key_labels_count) {
- rect.set_height(rect.height() * 1.5);
- painter.draw_text(rect, StringView(&black_key_labels[i], 1), Gfx::TextAlignment::Center, Color::White);
- }
-
- note += black_key_note_accumulator[i % black_keys_per_octave];
- x += black_key_offsets[i % black_keys_per_octave];
- ++i;
-
- if (note + m_track_manager.octave_base() >= note_count)
- break;
- if (x >= frame_inner_rect().width())
- break;
- }
-
- GUI::Frame::paint_event(event);
-}
-
-constexpr int notes_per_white_key[] = {
- 1,
- 3,
- 5,
- 6,
- 8,
- 10,
- 12,
-};
-
-// Keep in mind that in any of these functions a note value can be out of
-// bounds. Bounds checking is done in set_key().
-
-static inline int note_from_white_keys(int white_keys)
-{
- int octaves = white_keys / white_keys_per_octave;
- int remainder = white_keys % white_keys_per_octave;
- int notes_from_octaves = octaves * notes_per_octave;
- int notes_from_remainder = notes_per_white_key[remainder];
- int note = (notes_from_octaves + notes_from_remainder) - 1;
- return note;
-}
-
-int KeysWidget::note_for_event_position(const Gfx::IntPoint& a_point) const
-{
- if (!frame_inner_rect().contains(a_point))
- return -1;
-
- auto point = a_point;
- point.move_by(-frame_thickness(), -frame_thickness());
-
- int white_keys = point.x() / white_key_width;
- int note = note_from_white_keys(white_keys);
-
- bool black_key_on_left = note != 0 && key_pattern[(note - 1) % notes_per_octave] == Black;
- if (black_key_on_left) {
- int black_key_x = (white_keys * white_key_width) - black_key_x_offset;
- Gfx::IntRect black_key(black_key_x, 0, black_key_width, black_key_height);
- if (black_key.contains(point))
- return note - 1;
- }
-
- bool black_key_on_right = key_pattern[(note + 1) % notes_per_octave] == Black;
- if (black_key_on_right) {
- int black_key_x = ((white_keys + 1) * white_key_width) - black_key_x_offset;
- Gfx::IntRect black_key(black_key_x, 0, black_key_width, black_key_height);
- if (black_key.contains(point))
- return note + 1;
- }
-
- return note;
-}
-
-void KeysWidget::mousedown_event(GUI::MouseEvent& event)
-{
- if (event.button() != GUI::MouseButton::Left)
- return;
-
- m_mouse_down = true;
-
- m_mouse_note = note_for_event_position(event.position());
-
- set_key(m_mouse_note, On);
- update();
-}
-
-void KeysWidget::mouseup_event(GUI::MouseEvent& event)
-{
- if (event.button() != GUI::MouseButton::Left)
- return;
-
- m_mouse_down = false;
-
- set_key(m_mouse_note, Off);
- update();
-}
-
-void KeysWidget::mousemove_event(GUI::MouseEvent& event)
-{
- if (!m_mouse_down)
- return;
-
- int new_mouse_note = note_for_event_position(event.position());
-
- if (m_mouse_note == new_mouse_note)
- return;
-
- set_key(m_mouse_note, Off);
- set_key(new_mouse_note, On);
- update();
-
- m_mouse_note = new_mouse_note;
-}
diff --git a/Applications/Piano/KeysWidget.h b/Applications/Piano/KeysWidget.h
deleted file mode 100644
index d0b5a833ce..0000000000
--- a/Applications/Piano/KeysWidget.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Music.h"
-#include <LibGUI/Frame.h>
-
-class TrackManager;
-
-class KeysWidget final : public GUI::Frame {
- C_OBJECT(KeysWidget)
-public:
- virtual ~KeysWidget() override;
-
- int key_code_to_key(int key_code) const;
- int mouse_note() const;
-
- void set_key(int key, Switch);
- bool note_is_set(int note) const;
-
-private:
- explicit KeysWidget(TrackManager&);
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
-
- int note_for_event_position(const Gfx::IntPoint&) const;
-
- TrackManager& m_track_manager;
-
- u8 m_key_on[note_count] { 0 };
-
- bool m_mouse_down { false };
- int m_mouse_note { -1 };
-};
diff --git a/Applications/Piano/KnobsWidget.cpp b/Applications/Piano/KnobsWidget.cpp
deleted file mode 100644
index 4b9e4360c2..0000000000
--- a/Applications/Piano/KnobsWidget.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "KnobsWidget.h"
-#include "MainWidget.h"
-#include "TrackManager.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Slider.h>
-
-constexpr int max_attack = 1000;
-constexpr int max_decay = 1000;
-constexpr int max_sustain = 1000;
-constexpr int max_release = 1000;
-constexpr int max_delay = 8;
-
-KnobsWidget::KnobsWidget(TrackManager& track_manager, MainWidget& main_widget)
- : m_track_manager(track_manager)
- , m_main_widget(main_widget)
-{
- set_layout<GUI::VerticalBoxLayout>();
- set_fill_with_background_color(true);
-
- m_labels_container = add<GUI::Widget>();
- m_labels_container->set_layout<GUI::HorizontalBoxLayout>();
- m_labels_container->set_fixed_height(20);
-
- m_octave_label = m_labels_container->add<GUI::Label>("Octave");
- m_wave_label = m_labels_container->add<GUI::Label>("Wave");
- m_attack_label = m_labels_container->add<GUI::Label>("Attack");
- m_decay_label = m_labels_container->add<GUI::Label>("Decay");
- m_sustain_label = m_labels_container->add<GUI::Label>("Sustain");
- m_release_label = m_labels_container->add<GUI::Label>("Release");
- m_delay_label = m_labels_container->add<GUI::Label>("Delay");
-
- m_values_container = add<GUI::Widget>();
- m_values_container->set_layout<GUI::HorizontalBoxLayout>();
- m_values_container->set_fixed_height(10);
-
- m_octave_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.octave()));
- m_wave_value = m_values_container->add<GUI::Label>(wave_strings[m_track_manager.current_track().wave()]);
- m_attack_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().attack()));
- m_decay_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().decay()));
- m_sustain_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().sustain()));
- m_release_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().release()));
- m_delay_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().delay()));
-
- m_knobs_container = add<GUI::Widget>();
- m_knobs_container->set_layout<GUI::HorizontalBoxLayout>();
-
- // FIXME: Implement vertical flipping in GUI::Slider, not here.
-
- m_octave_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_octave_knob->set_tooltip("Z: octave down, X: octave up");
- m_octave_knob->set_range(octave_min - 1, octave_max - 1);
- m_octave_knob->set_value((octave_max - 1) - (m_track_manager.octave() - 1));
- m_octave_knob->on_change = [this](int value) {
- int new_octave = octave_max - value;
- if (m_change_underlying)
- m_main_widget.set_octave_and_ensure_note_change(new_octave);
- ASSERT(new_octave == m_track_manager.octave());
- m_octave_value->set_text(String::number(new_octave));
- };
-
- m_wave_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_wave_knob->set_tooltip("C: cycle through waveforms");
- m_wave_knob->set_range(0, last_wave);
- m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
- m_wave_knob->on_change = [this](int value) {
- int new_wave = last_wave - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_wave(new_wave);
- ASSERT(new_wave == m_track_manager.current_track().wave());
- m_wave_value->set_text(wave_strings[new_wave]);
- };
-
- m_attack_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_attack_knob->set_range(0, max_attack);
- m_attack_knob->set_value(max_attack - m_track_manager.current_track().attack());
- m_attack_knob->set_step(100);
- m_attack_knob->on_change = [this](int value) {
- int new_attack = max_attack - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_attack(new_attack);
- ASSERT(new_attack == m_track_manager.current_track().attack());
- m_attack_value->set_text(String::number(new_attack));
- };
-
- m_decay_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_decay_knob->set_range(0, max_decay);
- m_decay_knob->set_value(max_decay - m_track_manager.current_track().decay());
- m_decay_knob->set_step(100);
- m_decay_knob->on_change = [this](int value) {
- int new_decay = max_decay - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_decay(new_decay);
- ASSERT(new_decay == m_track_manager.current_track().decay());
- m_decay_value->set_text(String::number(new_decay));
- };
-
- m_sustain_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_sustain_knob->set_range(0, max_sustain);
- m_sustain_knob->set_value(max_sustain - m_track_manager.current_track().sustain());
- m_sustain_knob->set_step(100);
- m_sustain_knob->on_change = [this](int value) {
- int new_sustain = max_sustain - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_sustain(new_sustain);
- ASSERT(new_sustain == m_track_manager.current_track().sustain());
- m_sustain_value->set_text(String::number(new_sustain));
- };
-
- m_release_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_release_knob->set_range(0, max_release);
- m_release_knob->set_value(max_release - m_track_manager.current_track().release());
- m_release_knob->set_step(100);
- m_release_knob->on_change = [this](int value) {
- int new_release = max_release - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_release(new_release);
- ASSERT(new_release == m_track_manager.current_track().release());
- m_release_value->set_text(String::number(new_release));
- };
-
- m_delay_knob = m_knobs_container->add<GUI::VerticalSlider>();
- m_delay_knob->set_range(0, max_delay);
- m_delay_knob->set_value(max_delay - m_track_manager.current_track().delay());
- m_delay_knob->on_change = [this](int value) {
- int new_delay = max_delay - value;
- if (m_change_underlying)
- m_track_manager.current_track().set_delay(new_delay);
- ASSERT(new_delay == m_track_manager.current_track().delay());
- m_delay_value->set_text(String::number(new_delay));
- };
-}
-
-KnobsWidget::~KnobsWidget()
-{
-}
-
-void KnobsWidget::update_knobs()
-{
- m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
-
- // FIXME: This is needed because when the slider is changed normally, we
- // need to change the underlying value, but if the keyboard was used, we
- // need to change the slider without changing the underlying value.
- m_change_underlying = false;
-
- m_octave_knob->set_value(octave_max - m_track_manager.octave());
- m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave());
- m_attack_knob->set_value(max_attack - m_track_manager.current_track().attack());
- m_decay_knob->set_value(max_decay - m_track_manager.current_track().decay());
- m_sustain_knob->set_value(max_sustain - m_track_manager.current_track().sustain());
- m_release_knob->set_value(max_release - m_track_manager.current_track().release());
- m_delay_knob->set_value(max_delay - m_track_manager.current_track().delay());
-
- m_change_underlying = true;
-}
diff --git a/Applications/Piano/KnobsWidget.h b/Applications/Piano/KnobsWidget.h
deleted file mode 100644
index d5abea5be0..0000000000
--- a/Applications/Piano/KnobsWidget.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-class TrackManager;
-class MainWidget;
-
-class KnobsWidget final : public GUI::Frame {
- C_OBJECT(KnobsWidget)
-public:
- virtual ~KnobsWidget() override;
-
- void update_knobs();
-
-private:
- KnobsWidget(TrackManager&, MainWidget&);
-
- TrackManager& m_track_manager;
- MainWidget& m_main_widget;
-
- RefPtr<GUI::Widget> m_labels_container;
- RefPtr<GUI::Label> m_octave_label;
- RefPtr<GUI::Label> m_wave_label;
- RefPtr<GUI::Label> m_attack_label;
- RefPtr<GUI::Label> m_decay_label;
- RefPtr<GUI::Label> m_sustain_label;
- RefPtr<GUI::Label> m_release_label;
- RefPtr<GUI::Label> m_delay_label;
-
- RefPtr<GUI::Widget> m_values_container;
- RefPtr<GUI::Label> m_octave_value;
- RefPtr<GUI::Label> m_wave_value;
- RefPtr<GUI::Label> m_attack_value;
- RefPtr<GUI::Label> m_decay_value;
- RefPtr<GUI::Label> m_sustain_value;
- RefPtr<GUI::Label> m_release_value;
- RefPtr<GUI::Label> m_delay_value;
-
- RefPtr<GUI::Widget> m_knobs_container;
- RefPtr<GUI::Slider> m_octave_knob;
- RefPtr<GUI::Slider> m_wave_knob;
- RefPtr<GUI::Slider> m_attack_knob;
- RefPtr<GUI::Slider> m_decay_knob;
- RefPtr<GUI::Slider> m_sustain_knob;
- RefPtr<GUI::Slider> m_release_knob;
- RefPtr<GUI::Slider> m_delay_knob;
-
- bool m_change_underlying { true };
-};
diff --git a/Applications/Piano/MainWidget.cpp b/Applications/Piano/MainWidget.cpp
deleted file mode 100644
index ef40a4fd1a..0000000000
--- a/Applications/Piano/MainWidget.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "MainWidget.h"
-#include "KeysWidget.h"
-#include "KnobsWidget.h"
-#include "RollWidget.h"
-#include "SamplerWidget.h"
-#include "TrackManager.h"
-#include "WaveWidget.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/TabWidget.h>
-
-MainWidget::MainWidget(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_spacing(2);
- layout()->set_margins({ 2, 2, 2, 2 });
- set_fill_with_background_color(true);
-
- m_wave_widget = add<WaveWidget>(track_manager);
- m_wave_widget->set_fixed_height(100);
-
- m_tab_widget = add<GUI::TabWidget>();
- m_roll_widget = m_tab_widget->add_tab<RollWidget>("Piano Roll", track_manager);
-
- m_roll_widget->set_fixed_height(300);
-
- m_tab_widget->add_tab<SamplerWidget>("Sampler", track_manager);
-
- m_keys_and_knobs_container = add<GUI::Widget>();
- m_keys_and_knobs_container->set_layout<GUI::HorizontalBoxLayout>();
- m_keys_and_knobs_container->layout()->set_spacing(2);
- m_keys_and_knobs_container->set_fixed_height(100);
- m_keys_and_knobs_container->set_fill_with_background_color(true);
-
- m_keys_widget = m_keys_and_knobs_container->add<KeysWidget>(track_manager);
-
- m_knobs_widget = m_keys_and_knobs_container->add<KnobsWidget>(track_manager, *this);
- m_knobs_widget->set_fixed_width(350);
-
- m_roll_widget->set_keys_widget(m_keys_widget);
-}
-
-MainWidget::~MainWidget()
-{
-}
-
-void MainWidget::add_actions(GUI::Menu& menu)
-{
- menu.add_action(GUI::Action::create("Add track", { Mod_Ctrl, Key_T }, [&](auto&) {
- m_track_manager.add_track();
- }));
-
- menu.add_action(GUI::Action::create("Next track", { Mod_Ctrl, Key_N }, [&](auto&) {
- turn_off_pressed_keys();
- m_track_manager.next_track();
- turn_on_pressed_keys();
-
- m_knobs_widget->update_knobs();
- }));
-}
-
-// FIXME: There are some unnecessary calls to update() throughout this program,
-// which are an easy target for optimization.
-
-void MainWidget::custom_event(Core::CustomEvent&)
-{
- m_wave_widget->update();
- m_roll_widget->update();
-}
-
-void MainWidget::keydown_event(GUI::KeyEvent& event)
-{
- // This is to stop held-down keys from creating multiple events.
- if (m_keys_pressed[event.key()])
- return;
- else
- m_keys_pressed[event.key()] = true;
-
- note_key_action(event.key(), On);
- special_key_action(event.key());
- m_keys_widget->update();
-}
-
-void MainWidget::keyup_event(GUI::KeyEvent& event)
-{
- m_keys_pressed[event.key()] = false;
-
- note_key_action(event.key(), Off);
- m_keys_widget->update();
-}
-
-void MainWidget::note_key_action(int key_code, Switch switch_note)
-{
- int key = m_keys_widget->key_code_to_key(key_code);
- m_keys_widget->set_key(key, switch_note);
-}
-
-void MainWidget::special_key_action(int key_code)
-{
- switch (key_code) {
- case Key_Z:
- set_octave_and_ensure_note_change(Down);
- break;
- case Key_X:
- set_octave_and_ensure_note_change(Up);
- break;
- case Key_C:
- m_track_manager.current_track().set_wave(Up);
- m_knobs_widget->update_knobs();
- break;
- }
-}
-
-void MainWidget::turn_off_pressed_keys()
-{
- m_keys_widget->set_key(m_keys_widget->mouse_note(), Off);
- for (int i = 0; i < key_code_count; ++i) {
- if (m_keys_pressed[i])
- note_key_action(i, Off);
- }
-}
-
-void MainWidget::turn_on_pressed_keys()
-{
- m_keys_widget->set_key(m_keys_widget->mouse_note(), On);
- for (int i = 0; i < key_code_count; ++i) {
- if (m_keys_pressed[i])
- note_key_action(i, On);
- }
-}
-
-void MainWidget::set_octave_and_ensure_note_change(int octave)
-{
- turn_off_pressed_keys();
- m_track_manager.set_octave(octave);
- turn_on_pressed_keys();
-
- m_knobs_widget->update_knobs();
- m_keys_widget->update();
-}
-
-void MainWidget::set_octave_and_ensure_note_change(Direction direction)
-{
- turn_off_pressed_keys();
- m_track_manager.set_octave(direction);
- turn_on_pressed_keys();
-
- m_knobs_widget->update_knobs();
- m_keys_widget->update();
-}
diff --git a/Applications/Piano/MainWidget.h b/Applications/Piano/MainWidget.h
deleted file mode 100644
index a2a6a35a0c..0000000000
--- a/Applications/Piano/MainWidget.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Music.h"
-#include <LibGUI/Widget.h>
-
-class TrackManager;
-class WaveWidget;
-class RollWidget;
-class SamplerWidget;
-class KeysWidget;
-class KnobsWidget;
-
-class MainWidget final : public GUI::Widget {
- C_OBJECT(MainWidget)
-public:
- virtual ~MainWidget() override;
-
- void add_actions(GUI::Menu&);
-
- void set_octave_and_ensure_note_change(Direction);
- void set_octave_and_ensure_note_change(int);
-
-private:
- explicit MainWidget(TrackManager&);
-
- virtual void keydown_event(GUI::KeyEvent&) override;
- virtual void keyup_event(GUI::KeyEvent&) override;
- virtual void custom_event(Core::CustomEvent&) override;
-
- void note_key_action(int key_code, Switch);
- void special_key_action(int key_code);
-
- void turn_off_pressed_keys();
- void turn_on_pressed_keys();
-
- TrackManager& m_track_manager;
-
- RefPtr<WaveWidget> m_wave_widget;
- RefPtr<RollWidget> m_roll_widget;
- RefPtr<SamplerWidget> m_sampler_widget;
- RefPtr<GUI::TabWidget> m_tab_widget;
- RefPtr<GUI::Widget> m_keys_and_knobs_container;
- RefPtr<KeysWidget> m_keys_widget;
- RefPtr<KnobsWidget> m_knobs_widget;
-
- bool m_keys_pressed[key_code_count] { false };
-};
diff --git a/Applications/Piano/Music.h b/Applications/Piano/Music.h
deleted file mode 100644
index 3a150944ec..0000000000
--- a/Applications/Piano/Music.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Types.h>
-#include <LibGfx/Color.h>
-
-namespace Music {
-
-// CD quality
-// - Stereo
-// - 16 bit
-// - 44,100 samples/sec
-// - 1,411.2 kbps
-
-struct Sample {
- i16 left;
- i16 right;
-};
-
-constexpr int sample_count = 1024;
-
-constexpr int buffer_size = sample_count * sizeof(Sample);
-
-constexpr double sample_rate = 44100;
-
-constexpr double volume = 1800;
-
-enum Switch {
- Off,
- On,
-};
-
-struct RollNote {
- u32 length() const { return (off_sample - on_sample) + 1; }
-
- u32 on_sample;
- u32 off_sample;
-};
-
-enum Direction {
- Down,
- Up,
-};
-
-enum Wave {
- Sine,
- Triangle,
- Square,
- Saw,
- Noise,
- RecordedSample,
-};
-
-constexpr const char* wave_strings[] = {
- "Sine",
- "Triangle",
- "Square",
- "Saw",
- "Noise",
- "Sample",
-};
-
-constexpr int first_wave = Sine;
-constexpr int last_wave = RecordedSample;
-
-enum Envelope {
- Done,
- Attack,
- Decay,
- Release,
-};
-
-enum KeyColor {
- White,
- Black,
-};
-
-constexpr KeyColor key_pattern[] = {
- White,
- Black,
- White,
- Black,
- White,
- White,
- Black,
- White,
- Black,
- White,
- Black,
- White,
-};
-
-const Color note_pressed_color(64, 64, 255);
-const Color column_playing_color(128, 128, 255);
-
-const Color left_wave_colors[] = {
- // Sine
- {
- 255,
- 192,
- 0,
- },
- // Triangle
- {
- 35,
- 171,
- 35,
- },
- // Square
- {
- 128,
- 160,
- 255,
- },
- // Saw
- {
- 240,
- 100,
- 128,
- },
- // Noise
- {
- 197,
- 214,
- 225,
- },
- // RecordedSample
- {
- 227,
- 39,
- 39,
- },
-};
-
-const Color right_wave_colors[] = {
- // Sine
- {
- 255,
- 223,
- 0,
- },
- // Triangle
- {
- 35,
- 171,
- 90,
- },
- // Square
- {
- 139,
- 128,
- 255,
- },
- // Saw
- {
- 240,
- 100,
- 220,
- },
- // Noise
- {
- 197,
- 223,
- 225,
- },
- // RecordedSample
- {
- 227,
- 105,
- 39,
- },
-};
-
-constexpr int notes_per_octave = 12;
-constexpr int white_keys_per_octave = 7;
-constexpr int black_keys_per_octave = 5;
-constexpr int octave_min = 1;
-constexpr int octave_max = 7;
-
-constexpr double beats_per_minute = 60;
-constexpr int beats_per_bar = 4;
-constexpr int notes_per_beat = 4;
-constexpr int roll_length = (sample_rate / (beats_per_minute / 60)) * beats_per_bar;
-
-constexpr const char* note_names[] = {
- "C",
- "C#",
- "D",
- "D#",
- "E",
- "F",
- "F#",
- "G",
- "G#",
- "A",
- "A#",
- "B",
-};
-
-// Equal temperament, A = 440Hz
-// We calculate note frequencies relative to A4:
-// 440.0 * pow(pow(2.0, 1.0 / 12.0), N)
-// Where N is the note distance from A.
-constexpr double note_frequencies[] = {
- // Octave 1
- 32.703195662574764,
- 34.647828872108946,
- 36.708095989675876,
- 38.890872965260044,
- 41.203444614108669,
- 43.653528929125407,
- 46.249302838954222,
- 48.99942949771858,
- 51.913087197493056,
- 54.999999999999915,
- 58.270470189761156,
- 61.735412657015416,
- // Octave 2
- 65.406391325149571,
- 69.295657744217934,
- 73.416191979351794,
- 77.781745930520117,
- 82.406889228217381,
- 87.307057858250872,
- 92.4986056779085,
- 97.998858995437217,
- 103.82617439498618,
- 109.99999999999989,
- 116.54094037952237,
- 123.4708253140309,
- // Octave 3
- 130.8127826502992,
- 138.59131548843592,
- 146.83238395870364,
- 155.56349186104035,
- 164.81377845643485,
- 174.61411571650183,
- 184.99721135581709,
- 195.99771799087452,
- 207.65234878997245,
- 219.99999999999989,
- 233.08188075904488,
- 246.94165062806198,
- // Octave 4
- 261.62556530059851,
- 277.18263097687202,
- 293.66476791740746,
- 311.12698372208081,
- 329.62755691286986,
- 349.22823143300383,
- 369.99442271163434,
- 391.99543598174927,
- 415.30469757994513,
- 440,
- 466.16376151808993,
- 493.88330125612413,
- // Octave 5
- 523.25113060119736,
- 554.36526195374427,
- 587.32953583481526,
- 622.25396744416196,
- 659.25511382574007,
- 698.456462866008,
- 739.98884542326903,
- 783.99087196349899,
- 830.60939515989071,
- 880.00000000000034,
- 932.32752303618031,
- 987.76660251224882,
- // Octave 6
- 1046.5022612023952,
- 1108.7305239074892,
- 1174.659071669631,
- 1244.5079348883246,
- 1318.5102276514808,
- 1396.9129257320169,
- 1479.977690846539,
- 1567.9817439269987,
- 1661.2187903197821,
- 1760.000000000002,
- 1864.6550460723618,
- 1975.5332050244986,
- // Octave 7
- 2093.0045224047913,
- 2217.4610478149793,
- 2349.3181433392633,
- 2489.0158697766506,
- 2637.020455302963,
- 2793.8258514640347,
- 2959.9553816930793,
- 3135.9634878539991,
- 3322.437580639566,
- 3520.0000000000055,
- 3729.3100921447249,
- 3951.0664100489994,
-};
-constexpr int note_count = sizeof(note_frequencies) / sizeof(double);
-
-constexpr double middle_c = note_frequencies[36];
-
-}
-
-using namespace Music;
diff --git a/Applications/Piano/RollWidget.cpp b/Applications/Piano/RollWidget.cpp
deleted file mode 100644
index 2677fed384..0000000000
--- a/Applications/Piano/RollWidget.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "RollWidget.h"
-#include "TrackManager.h"
-#include <LibGUI/Painter.h>
-#include <LibGUI/ScrollBar.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <math.h>
-
-constexpr int note_height = 20;
-constexpr int max_note_width = note_height * 2;
-constexpr int roll_height = note_count * note_height;
-constexpr int horizontal_scroll_sensitivity = 20;
-constexpr int max_zoom = 1 << 8;
-
-RollWidget::RollWidget(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
- set_should_hide_unnecessary_scrollbars(true);
- set_content_size({ 0, roll_height });
- vertical_scrollbar().set_value(roll_height / 2);
-}
-
-RollWidget::~RollWidget()
-{
-}
-
-void RollWidget::paint_event(GUI::PaintEvent& event)
-{
- m_roll_width = widget_inner_rect().width() * m_zoom_level;
- set_content_size({ m_roll_width, roll_height });
-
- // Divide the roll by the maximum note width. If we get fewer notes than
- // our time signature requires, round up. Otherwise, round down to the
- // nearest x*(2^y), where x is the base number of notes of our time
- // signature. In other words, find a number that is a double of our time
- // signature. For 4/4 that would be 16, 32, 64, 128 ...
- m_num_notes = m_roll_width / max_note_width;
- int time_signature_notes = beats_per_bar * notes_per_beat;
- if (m_num_notes < time_signature_notes)
- m_num_notes = time_signature_notes;
- else
- m_num_notes = time_signature_notes * pow(2, static_cast<int>(log2(m_num_notes / time_signature_notes)));
- m_note_width = static_cast<double>(m_roll_width) / m_num_notes;
-
- // This calculates the minimum number of rows needed. We account for a
- // partial row at the top and/or bottom.
- int y_offset = vertical_scrollbar().value();
- int note_offset = y_offset / note_height;
- int note_offset_remainder = y_offset % note_height;
- int paint_area = widget_inner_rect().height() + note_offset_remainder;
- if (paint_area % note_height != 0)
- paint_area += note_height;
- int notes_to_paint = paint_area / note_height;
- int key_pattern_index = (notes_per_octave - 1) - (note_offset % notes_per_octave);
-
- int x_offset = horizontal_scrollbar().value();
- int horizontal_note_offset_remainder = fmod(x_offset, m_note_width);
- int horizontal_paint_area = widget_inner_rect().width() + horizontal_note_offset_remainder;
- if (fmod(horizontal_paint_area, m_note_width) != 0)
- horizontal_paint_area += m_note_width;
- int horizontal_notes_to_paint = horizontal_paint_area / m_note_width;
-
- GUI::Painter painter(*this);
- painter.translate(frame_thickness(), frame_thickness());
- painter.add_clip_rect(event.rect());
- painter.translate(-horizontal_note_offset_remainder, -note_offset_remainder);
-
- for (int y = 0; y < notes_to_paint; ++y) {
- int y_pos = y * note_height;
-
- int note = (note_count - note_offset - 1) - y;
- for (int x = 0; x < horizontal_notes_to_paint; ++x) {
- // This is needed to avoid rounding errors. You can't just use
- // m_note_width as the width.
- int x_pos = x * m_note_width;
- int next_x_pos = (x + 1) * m_note_width;
- int distance_to_next_x = next_x_pos - x_pos;
- Gfx::IntRect rect(x_pos, y_pos, distance_to_next_x, note_height);
-
- if (key_pattern[key_pattern_index] == Black)
- painter.fill_rect(rect, Color::LightGray);
- else
- painter.fill_rect(rect, Color::White);
-
- if (keys_widget() && keys_widget()->note_is_set(note))
- painter.fill_rect(rect, note_pressed_color.with_alpha(128));
-
- painter.draw_line(rect.top_right(), rect.bottom_right(), Color::Black);
- painter.draw_line(rect.bottom_left(), rect.bottom_right(), Color::Black);
- }
-
- if (--key_pattern_index == -1)
- key_pattern_index = notes_per_octave - 1;
- }
-
- painter.translate(-x_offset, -y_offset);
- painter.translate(horizontal_note_offset_remainder, note_offset_remainder);
-
- for (int note = note_count - (note_offset + notes_to_paint); note <= (note_count - 1) - note_offset; ++note) {
- int y = ((note_count - 1) - note) * note_height;
- for (auto roll_note : m_track_manager.current_track().roll_notes(note)) {
- int x = m_roll_width * (static_cast<double>(roll_note.on_sample) / roll_length);
- int width = m_roll_width * (static_cast<double>(roll_note.length()) / roll_length);
- if (x + width < x_offset || x > x_offset + widget_inner_rect().width())
- continue;
- if (width < 2)
- width = 2;
-
- int height = note_height;
-
- Gfx::IntRect rect(x, y, width, height);
- painter.fill_rect(rect, note_pressed_color);
- painter.draw_rect(rect, Color::Black);
- }
- Gfx::IntRect note_name_rect(3, y, 1, note_height);
- const char* note_name = note_names[note % notes_per_octave];
-
- painter.draw_text(note_name_rect, note_name, Gfx::TextAlignment::CenterLeft);
- note_name_rect.move_by(Gfx::FontDatabase::default_font().width(note_name) + 2, 0);
- if (note % notes_per_octave == 0)
- painter.draw_text(note_name_rect, String::formatted("{}", note / notes_per_octave + 1), Gfx::TextAlignment::CenterLeft);
- }
-
- int x = m_roll_width * (static_cast<double>(m_track_manager.time()) / roll_length);
- if (x > x_offset && x <= x_offset + widget_inner_rect().width())
- painter.draw_line({ x, 0 }, { x, roll_height }, Gfx::Color::Black);
-
- GUI::Frame::paint_event(event);
-}
-
-void RollWidget::mousedown_event(GUI::MouseEvent& event)
-{
- if (!widget_inner_rect().contains(event.x(), event.y()))
- return;
-
- m_note_drag_start = event.position();
-
- int y = (m_note_drag_start.value().y() + vertical_scrollbar().value()) - frame_thickness();
- y /= note_height;
- m_drag_note = (note_count - 1) - y;
-
- mousemove_event(event);
-}
-
-void RollWidget::mousemove_event(GUI::MouseEvent& event)
-{
- if (!m_note_drag_start.has_value())
- return;
-
- if (m_note_drag_location.has_value()) {
- // Clear previous note
- m_track_manager.current_track().set_roll_note(m_drag_note, m_note_drag_location.value().on_sample, m_note_drag_location.value().off_sample);
- }
-
- auto get_note_x = [&](int x0) {
- // There's a case where we can't just use x / m_note_width. For example, if
- // your m_note_width is 3.1 you will have a rect starting at 3. When that
- // leftmost pixel of the rect is clicked you will do 3 / 3.1 which is 0
- // and not 1. We can avoid that case by shifting x by 1 if m_note_width is
- // fractional, being careful not to shift out of bounds.
- int x = (x0 + horizontal_scrollbar().value()) - frame_thickness();
- bool note_width_is_fractional = m_note_width - static_cast<int>(m_note_width) != 0;
- bool x_is_not_last = x != widget_inner_rect().width() - 1;
- if (note_width_is_fractional && x_is_not_last)
- ++x;
- x /= m_note_width;
- return x;
- };
-
- int x0 = get_note_x(m_note_drag_start.value().x());
- int x1 = get_note_x(event.x());
-
- u32 on_sample = roll_length * (static_cast<double>(min(x0, x1)) / m_num_notes);
- u32 off_sample = (roll_length * (static_cast<double>(max(x0, x1) + 1) / m_num_notes)) - 1;
- m_track_manager.current_track().set_roll_note(m_drag_note, on_sample, off_sample);
- m_note_drag_location = RollNote({ on_sample, off_sample });
-
- update();
-}
-
-void RollWidget::mouseup_event([[maybe_unused]] GUI::MouseEvent& event)
-{
- m_note_drag_start = {};
- m_note_drag_location = {};
-}
-
-// FIXME: Implement zoom and horizontal scroll events in LibGUI, not here.
-void RollWidget::mousewheel_event(GUI::MouseEvent& event)
-{
- if (event.modifiers() & KeyModifier::Mod_Shift) {
- horizontal_scrollbar().set_value(horizontal_scrollbar().value() + (event.wheel_delta() * horizontal_scroll_sensitivity));
- return;
- }
-
- if (!(event.modifiers() & KeyModifier::Mod_Ctrl)) {
- GUI::ScrollableWidget::mousewheel_event(event);
- return;
- }
-
- double multiplier = event.wheel_delta() >= 0 ? 0.5 : 2;
-
- if (m_zoom_level * multiplier > max_zoom)
- return;
-
- if (m_zoom_level * multiplier < 1) {
- if (m_zoom_level == 1)
- return;
- m_zoom_level = 1;
- } else {
- m_zoom_level *= multiplier;
- }
-
- int absolute_x_of_pixel_at_cursor = horizontal_scrollbar().value() + event.position().x();
- int absolute_x_of_pixel_at_cursor_after_resize = absolute_x_of_pixel_at_cursor * multiplier;
- int new_scrollbar = absolute_x_of_pixel_at_cursor_after_resize - event.position().x();
-
- m_roll_width = widget_inner_rect().width() * m_zoom_level;
- set_content_size({ m_roll_width, roll_height });
-
- horizontal_scrollbar().set_value(new_scrollbar);
-}
diff --git a/Applications/Piano/RollWidget.h b/Applications/Piano/RollWidget.h
deleted file mode 100644
index bbfcc8bb62..0000000000
--- a/Applications/Piano/RollWidget.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "KeysWidget.h"
-#include "Music.h"
-#include <LibGUI/ScrollableWidget.h>
-
-class TrackManager;
-
-class RollWidget final : public GUI::ScrollableWidget {
- C_OBJECT(RollWidget)
-public:
- virtual ~RollWidget() override;
-
- const KeysWidget* keys_widget() const { return m_keys_widget; }
- void set_keys_widget(const KeysWidget* widget) { m_keys_widget = widget; }
-
-private:
- explicit RollWidget(TrackManager&);
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent& event) override;
- virtual void mousemove_event(GUI::MouseEvent& event) override;
- virtual void mouseup_event(GUI::MouseEvent& event) override;
- virtual void mousewheel_event(GUI::MouseEvent&) override;
-
- TrackManager& m_track_manager;
- const KeysWidget* m_keys_widget;
-
- int m_roll_width { 0 };
- int m_num_notes { 0 };
- double m_note_width { 0.0 };
- int m_zoom_level { 1 };
-
- Optional<Gfx::IntPoint> m_note_drag_start;
- Optional<RollNote> m_note_drag_location;
- int m_drag_note;
-};
diff --git a/Applications/Piano/SamplerWidget.cpp b/Applications/Piano/SamplerWidget.cpp
deleted file mode 100644
index 72704f28c7..0000000000
--- a/Applications/Piano/SamplerWidget.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SamplerWidget.h"
-#include "TrackManager.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Painter.h>
-
-WaveEditor::WaveEditor(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
-}
-
-WaveEditor::~WaveEditor()
-{
-}
-
-int WaveEditor::sample_to_y(double percentage) const
-{
- double portion_of_half_height = percentage * ((frame_inner_rect().height() - 1) / 2.0);
- double y = (frame_inner_rect().height() / 2.0) + portion_of_half_height;
- return y;
-}
-
-void WaveEditor::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.fill_rect(frame_inner_rect(), Color::Black);
-
- auto recorded_sample = m_track_manager.current_track().recorded_sample();
- if (recorded_sample.is_empty())
- return;
-
- double width_scale = static_cast<double>(frame_inner_rect().width()) / recorded_sample.size();
-
- painter.translate(frame_thickness(), frame_thickness());
-
- int prev_x = 0;
- int left_prev_y = sample_to_y(recorded_sample[0].left);
- int right_prev_y = sample_to_y(recorded_sample[0].right);
- painter.set_pixel({ prev_x, left_prev_y }, left_wave_colors[RecordedSample]);
- painter.set_pixel({ prev_x, right_prev_y }, right_wave_colors[RecordedSample]);
-
- for (size_t x = 1; x < recorded_sample.size(); ++x) {
- int left_y = sample_to_y(recorded_sample[x].left);
- int right_y = sample_to_y(recorded_sample[x].right);
-
- Gfx::IntPoint left_point1(prev_x * width_scale, left_prev_y);
- Gfx::IntPoint left_point2(x * width_scale, left_y);
- painter.draw_line(left_point1, left_point2, left_wave_colors[RecordedSample]);
-
- Gfx::IntPoint right_point1(prev_x * width_scale, right_prev_y);
- Gfx::IntPoint right_point2(x * width_scale, right_y);
- painter.draw_line(right_point1, right_point2, right_wave_colors[RecordedSample]);
-
- prev_x = x;
- left_prev_y = left_y;
- right_prev_y = right_y;
- }
-}
-
-SamplerWidget::SamplerWidget(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 10, 10, 10, 10 });
- layout()->set_spacing(10);
- set_fill_with_background_color(true);
-
- m_open_button_and_recorded_sample_name_container = add<GUI::Widget>();
- m_open_button_and_recorded_sample_name_container->set_layout<GUI::HorizontalBoxLayout>();
- m_open_button_and_recorded_sample_name_container->layout()->set_spacing(10);
- m_open_button_and_recorded_sample_name_container->set_fixed_height(24);
-
- m_open_button = m_open_button_and_recorded_sample_name_container->add<GUI::Button>();
- m_open_button->set_fixed_size(24, 24);
- m_open_button->set_focus_policy(GUI::FocusPolicy::TabFocus);
- m_open_button->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/open.png"));
- m_open_button->on_click = [this](auto) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(window());
- if (!open_path.has_value())
- return;
- String error_string = m_track_manager.current_track().set_recorded_sample(open_path.value());
- if (!error_string.is_empty()) {
- GUI::MessageBox::show(window(), String::formatted("Failed to load WAV file: {}", error_string.characters()), "Error", GUI::MessageBox::Type::Error);
- return;
- }
- m_recorded_sample_name->set_text(open_path.value());
- m_wave_editor->update();
- };
-
- m_recorded_sample_name = m_open_button_and_recorded_sample_name_container->add<GUI::Label>("No sample loaded");
- m_recorded_sample_name->set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- m_wave_editor = add<WaveEditor>(m_track_manager);
- m_wave_editor->set_fixed_height(100);
-}
-
-SamplerWidget::~SamplerWidget()
-{
-}
diff --git a/Applications/Piano/SamplerWidget.h b/Applications/Piano/SamplerWidget.h
deleted file mode 100644
index b99dbcbe02..0000000000
--- a/Applications/Piano/SamplerWidget.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-class TrackManager;
-
-class WaveEditor final : public GUI::Frame {
- C_OBJECT(WaveEditor)
-public:
- virtual ~WaveEditor() override;
-
-private:
- explicit WaveEditor(TrackManager&);
-
- virtual void paint_event(GUI::PaintEvent&) override;
-
- int sample_to_y(double percentage) const;
-
- TrackManager& m_track_manager;
-};
-
-class SamplerWidget final : public GUI::Frame {
- C_OBJECT(SamplerWidget)
-public:
- virtual ~SamplerWidget() override;
-
-private:
- explicit SamplerWidget(TrackManager&);
-
- TrackManager& m_track_manager;
-
- RefPtr<GUI::Widget> m_open_button_and_recorded_sample_name_container;
- RefPtr<GUI::Button> m_open_button;
- RefPtr<GUI::Label> m_recorded_sample_name;
- RefPtr<WaveEditor> m_wave_editor;
-};
diff --git a/Applications/Piano/Track.cpp b/Applications/Piano/Track.cpp
deleted file mode 100644
index 61d4351d06..0000000000
--- a/Applications/Piano/Track.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Track.h"
-#include <AK/NumericLimits.h>
-#include <LibAudio/Loader.h>
-#include <math.h>
-
-Track::Track(const u32& time)
- : m_time(time)
-{
- set_sustain_impl(1000);
- set_attack(5);
- set_decay(1000);
- set_release(5);
-}
-
-Track::~Track()
-{
-}
-
-void Track::fill_sample(Sample& sample)
-{
- Audio::Sample new_sample;
-
- for (size_t note = 0; note < note_count; ++note) {
- if (!m_roll_iters[note].is_end()) {
- if (m_roll_iters[note]->on_sample == m_time) {
- set_note(note, On);
- } else if (m_roll_iters[note]->off_sample == m_time) {
- set_note(note, Off);
- ++m_roll_iters[note];
- if (m_roll_iters[note].is_end())
- m_roll_iters[note] = m_roll_notes[note].begin();
- }
- }
-
- switch (m_envelope[note]) {
- case Done:
- continue;
- case Attack:
- m_power[note] += m_attack_step;
- if (m_power[note] >= 1) {
- m_power[note] = 1;
- m_envelope[note] = Decay;
- }
- break;
- case Decay:
- m_power[note] -= m_decay_step;
- if (m_power[note] < m_sustain_level)
- m_power[note] = m_sustain_level;
- break;
- case Release:
- m_power[note] -= m_release_step[note];
- if (m_power[note] <= 0) {
- m_power[note] = 0;
- m_envelope[note] = Done;
- continue;
- }
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- Audio::Sample note_sample;
- switch (m_wave) {
- case Wave::Sine:
- note_sample = sine(note);
- break;
- case Wave::Saw:
- note_sample = saw(note);
- break;
- case Wave::Square:
- note_sample = square(note);
- break;
- case Wave::Triangle:
- note_sample = triangle(note);
- break;
- case Wave::Noise:
- note_sample = noise();
- break;
- case Wave::RecordedSample:
- note_sample = recorded_sample(note);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- new_sample.left += note_sample.left * m_power[note] * volume;
- new_sample.right += note_sample.right * m_power[note] * volume;
- }
-
- if (m_delay) {
- new_sample.left += m_delay_buffer[m_delay_index].left * 0.333333;
- new_sample.right += m_delay_buffer[m_delay_index].right * 0.333333;
- m_delay_buffer[m_delay_index].left = new_sample.left;
- m_delay_buffer[m_delay_index].right = new_sample.right;
- if (++m_delay_index >= m_delay_samples)
- m_delay_index = 0;
- }
-
- sample.left += new_sample.left;
- sample.right += new_sample.right;
-}
-
-void Track::reset()
-{
- memset(m_delay_buffer.data(), 0, m_delay_buffer.size() * sizeof(Sample));
- m_delay_index = 0;
-
- memset(m_note_on, 0, sizeof(m_note_on));
- memset(m_power, 0, sizeof(m_power));
- memset(m_envelope, 0, sizeof(m_envelope));
-}
-
-String Track::set_recorded_sample(const StringView& path)
-{
- NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path);
- if (loader->has_error())
- return String(loader->error_string());
- auto buffer = loader->get_more_samples(60 * sample_rate * sizeof(Sample)); // 1 minute maximum
-
- if (!m_recorded_sample.is_empty())
- m_recorded_sample.clear();
- m_recorded_sample.resize(buffer->sample_count());
-
- double peak = 0;
- for (int i = 0; i < buffer->sample_count(); ++i) {
- double left_abs = fabs(buffer->samples()[i].left);
- double right_abs = fabs(buffer->samples()[i].right);
- if (left_abs > peak)
- peak = left_abs;
- if (right_abs > peak)
- peak = right_abs;
- }
-
- if (peak) {
- for (int i = 0; i < buffer->sample_count(); ++i) {
- m_recorded_sample[i].left = buffer->samples()[i].left / peak;
- m_recorded_sample[i].right = buffer->samples()[i].right / peak;
- }
- }
-
- return String::empty();
-}
-
-// All of the information for these waves is on Wikipedia.
-
-Audio::Sample Track::sine(size_t note)
-{
- double pos = note_frequencies[note] / sample_rate;
- double sin_step = pos * 2 * M_PI;
- double w = sin(m_pos[note]);
- m_pos[note] += sin_step;
- return w;
-}
-
-Audio::Sample Track::saw(size_t note)
-{
- double saw_step = note_frequencies[note] / sample_rate;
- double t = m_pos[note];
- double w = (0.5 - (t - floor(t))) * 2;
- m_pos[note] += saw_step;
- return w;
-}
-
-Audio::Sample Track::square(size_t note)
-{
- double pos = note_frequencies[note] / sample_rate;
- double square_step = pos * 2 * M_PI;
- double w = sin(m_pos[note]) >= 0 ? 1 : -1;
- m_pos[note] += square_step;
- return w;
-}
-
-Audio::Sample Track::triangle(size_t note)
-{
- double triangle_step = note_frequencies[note] / sample_rate;
- double t = m_pos[note];
- double w = fabs(fmod((4 * t) + 1, 4) - 2) - 1;
- m_pos[note] += triangle_step;
- return w;
-}
-
-Audio::Sample Track::noise() const
-{
- double random_percentage = static_cast<double>(rand()) / RAND_MAX;
- double w = (random_percentage * 2) - 1;
- return w;
-}
-
-Audio::Sample Track::recorded_sample(size_t note)
-{
- int t = m_pos[note];
- if (t >= static_cast<int>(m_recorded_sample.size()))
- return 0;
- double w_left = m_recorded_sample[t].left;
- double w_right = m_recorded_sample[t].right;
- if (t + 1 < static_cast<int>(m_recorded_sample.size())) {
- double t_fraction = m_pos[note] - t;
- w_left += (m_recorded_sample[t + 1].left - m_recorded_sample[t].left) * t_fraction;
- w_right += (m_recorded_sample[t + 1].right - m_recorded_sample[t].right) * t_fraction;
- }
- double recorded_sample_step = note_frequencies[note] / middle_c;
- m_pos[note] += recorded_sample_step;
- return { w_left, w_right };
-}
-
-static inline double calculate_step(double distance, int milliseconds)
-{
- if (milliseconds == 0)
- return distance;
-
- constexpr double samples_per_millisecond = sample_rate / 1000.0;
- double samples = milliseconds * samples_per_millisecond;
- double step = distance / samples;
- return step;
-}
-
-void Track::set_note(int note, Switch switch_note)
-{
- ASSERT(note >= 0 && note < note_count);
-
- if (switch_note == On) {
- if (m_note_on[note] == 0) {
- m_pos[note] = 0;
- m_envelope[note] = Attack;
- }
- ++m_note_on[note];
- } else {
- if (m_note_on[note] >= 1) {
- if (m_note_on[note] == 1) {
- m_release_step[note] = calculate_step(m_power[note], m_release);
- m_envelope[note] = Release;
- }
- --m_note_on[note];
- }
- }
-
- ASSERT(m_note_on[note] != NumericLimits<u8>::max());
- ASSERT(m_power[note] >= 0);
-}
-
-void Track::sync_roll(int note)
-{
- auto it = m_roll_notes[note].find_if([&](auto& roll_note) { return roll_note.off_sample > m_time; });
- if (it.is_end())
- m_roll_iters[note] = m_roll_notes[note].begin();
- else
- m_roll_iters[note] = it;
-}
-
-void Track::set_roll_note(int note, u32 on_sample, u32 off_sample)
-{
- RollNote new_roll_note = { on_sample, off_sample };
-
- ASSERT(note >= 0 && note < note_count);
- ASSERT(new_roll_note.off_sample < roll_length);
- ASSERT(new_roll_note.length() >= 2);
-
- for (auto it = m_roll_notes[note].begin(); !it.is_end();) {
- if (it->on_sample > new_roll_note.off_sample) {
- m_roll_notes[note].insert_before(it, new_roll_note);
- sync_roll(note);
- return;
- }
- if (it->on_sample <= new_roll_note.on_sample && it->off_sample >= new_roll_note.on_sample) {
- if (m_time >= it->on_sample && m_time <= it->off_sample)
- set_note(note, Off);
- m_roll_notes[note].remove(it);
- sync_roll(note);
- return;
- }
- if ((new_roll_note.on_sample == 0 || it->on_sample >= new_roll_note.on_sample - 1) && it->on_sample <= new_roll_note.off_sample) {
- if (m_time >= new_roll_note.off_sample && m_time <= it->off_sample)
- set_note(note, Off);
- m_roll_notes[note].remove(it);
- it = m_roll_notes[note].begin();
- continue;
- }
- ++it;
- }
-
- m_roll_notes[note].append(new_roll_note);
- sync_roll(note);
-}
-
-void Track::set_wave(int wave)
-{
- ASSERT(wave >= first_wave && wave <= last_wave);
- m_wave = wave;
-}
-
-void Track::set_wave(Direction direction)
-{
- if (direction == Up) {
- if (++m_wave > last_wave)
- m_wave = first_wave;
- } else {
- if (--m_wave < first_wave)
- m_wave = last_wave;
- }
-}
-
-void Track::set_attack(int attack)
-{
- ASSERT(attack >= 0);
- m_attack = attack;
- m_attack_step = calculate_step(1, m_attack);
-}
-
-void Track::set_decay(int decay)
-{
- ASSERT(decay >= 0);
- m_decay = decay;
- m_decay_step = calculate_step(1 - m_sustain_level, m_decay);
-}
-
-void Track::set_sustain_impl(int sustain)
-{
- ASSERT(sustain >= 0);
- m_sustain = sustain;
- m_sustain_level = sustain / 1000.0;
-}
-
-void Track::set_sustain(int sustain)
-{
- set_sustain_impl(sustain);
- set_decay(m_decay);
-}
-
-void Track::set_release(int release)
-{
- ASSERT(release >= 0);
- m_release = release;
-}
-
-void Track::set_delay(int delay)
-{
- ASSERT(delay >= 0);
- m_delay = delay;
- m_delay_samples = m_delay == 0 ? 0 : (sample_rate / (beats_per_minute / 60)) / m_delay;
- m_delay_buffer.resize(m_delay_samples);
- memset(m_delay_buffer.data(), 0, m_delay_buffer.size() * sizeof(Sample));
- m_delay_index = 0;
-}
diff --git a/Applications/Piano/Track.h b/Applications/Piano/Track.h
deleted file mode 100644
index 0acca429b0..0000000000
--- a/Applications/Piano/Track.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Music.h"
-#include <AK/Noncopyable.h>
-#include <AK/SinglyLinkedList.h>
-#include <LibAudio/Buffer.h>
-
-typedef AK::SinglyLinkedListIterator<SinglyLinkedList<RollNote>, RollNote> RollIter;
-
-class Track {
- AK_MAKE_NONCOPYABLE(Track);
- AK_MAKE_NONMOVABLE(Track);
-
-public:
- explicit Track(const u32& time);
- ~Track();
-
- const Vector<Audio::Sample>& recorded_sample() const { return m_recorded_sample; }
- const SinglyLinkedList<RollNote>& roll_notes(int note) const { return m_roll_notes[note]; }
- int wave() const { return m_wave; }
- int attack() const { return m_attack; }
- int decay() const { return m_decay; }
- int sustain() const { return m_sustain; }
- int release() const { return m_release; }
- int delay() const { return m_delay; }
-
- void fill_sample(Sample& sample);
- void reset();
- String set_recorded_sample(const StringView& path);
- void set_note(int note, Switch);
- void set_roll_note(int note, u32 on_sample, u32 off_sample);
- void set_wave(int wave);
- void set_wave(Direction);
- void set_attack(int attack);
- void set_decay(int decay);
- void set_sustain(int sustain);
- void set_release(int release);
- void set_delay(int delay);
-
-private:
- Audio::Sample sine(size_t note);
- Audio::Sample saw(size_t note);
- Audio::Sample square(size_t note);
- Audio::Sample triangle(size_t note);
- Audio::Sample noise() const;
- Audio::Sample recorded_sample(size_t note);
-
- void sync_roll(int note);
- void set_sustain_impl(int sustain);
-
- Vector<Sample> m_delay_buffer;
-
- Vector<Audio::Sample> m_recorded_sample;
-
- u8 m_note_on[note_count] { 0 };
- double m_power[note_count] { 0 };
- double m_pos[note_count]; // Initialized lazily.
- Envelope m_envelope[note_count] { Done };
-
- int m_wave { first_wave };
- int m_attack;
- double m_attack_step;
- int m_decay;
- double m_decay_step;
- int m_sustain;
- double m_sustain_level;
- int m_release;
- double m_release_step[note_count];
- int m_delay { 0 };
- size_t m_delay_samples { 0 };
- size_t m_delay_index { 0 };
-
- const u32& m_time;
-
- SinglyLinkedList<RollNote> m_roll_notes[note_count];
- RollIter m_roll_iters[note_count];
-};
diff --git a/Applications/Piano/TrackManager.cpp b/Applications/Piano/TrackManager.cpp
deleted file mode 100644
index 5aa1856a11..0000000000
--- a/Applications/Piano/TrackManager.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TrackManager.h"
-
-TrackManager::TrackManager()
-{
- add_track();
-}
-
-TrackManager::~TrackManager()
-{
-}
-
-void TrackManager::fill_buffer(Span<Sample> buffer)
-{
- memset(buffer.data(), 0, buffer_size);
-
- for (size_t i = 0; i < buffer.size(); ++i) {
- for (auto& track : m_tracks)
- track->fill_sample(buffer[i]);
-
- if (++m_time >= roll_length) {
- m_time = 0;
- if (!m_should_loop)
- break;
- }
- }
-
- memcpy(m_current_back_buffer.data(), buffer.data(), buffer_size);
- swap(m_current_front_buffer, m_current_back_buffer);
-}
-
-void TrackManager::reset()
-{
- memset(m_front_buffer.data(), 0, buffer_size);
- memset(m_back_buffer.data(), 0, buffer_size);
-
- m_current_front_buffer = m_front_buffer.span();
- m_current_back_buffer = m_back_buffer.span();
-
- m_time = 0;
-
- for (auto& track : m_tracks)
- track->reset();
-}
-
-void TrackManager::set_note_current_octave(int note, Switch switch_note)
-{
- current_track().set_note(note + octave_base(), switch_note);
-}
-
-void TrackManager::set_octave(Direction direction)
-{
- if (direction == Up) {
- if (m_octave < octave_max)
- ++m_octave;
- } else {
- if (m_octave > octave_min)
- --m_octave;
- }
-}
-
-void TrackManager::set_octave(int octave)
-{
- if (octave <= octave_max && octave >= octave_min) {
- m_octave = octave;
- }
-}
-
-void TrackManager::add_track()
-{
- m_tracks.append(make<Track>(m_time));
-}
-
-void TrackManager::next_track()
-{
- if (++m_current_track >= m_tracks.size())
- m_current_track = 0;
-}
diff --git a/Applications/Piano/TrackManager.h b/Applications/Piano/TrackManager.h
deleted file mode 100644
index 70cb661bc4..0000000000
--- a/Applications/Piano/TrackManager.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Music.h"
-#include "Track.h"
-#include <AK/Array.h>
-#include <AK/Noncopyable.h>
-#include <AK/NonnullOwnPtr.h>
-#include <AK/Vector.h>
-
-class TrackManager {
- AK_MAKE_NONCOPYABLE(TrackManager);
- AK_MAKE_NONMOVABLE(TrackManager);
-
-public:
- TrackManager();
- ~TrackManager();
-
- Track& current_track() { return *m_tracks[m_current_track]; }
- Span<const Sample> buffer() const { return m_current_front_buffer; }
- int octave() const { return m_octave; }
- int octave_base() const { return (m_octave - octave_min) * 12; }
- int time() const { return m_time; }
-
- void fill_buffer(Span<Sample>);
- void reset();
- void set_should_loop(bool b) { m_should_loop = b; }
- void set_note_current_octave(int note, Switch);
- void set_octave(Direction);
- void set_octave(int octave);
- void add_track();
- void next_track();
-
-private:
- Vector<NonnullOwnPtr<Track>> m_tracks;
- size_t m_current_track { 0 };
-
- Array<Sample, sample_count> m_front_buffer;
- Array<Sample, sample_count> m_back_buffer;
- Span<Sample> m_current_front_buffer { m_front_buffer.span() };
- Span<Sample> m_current_back_buffer { m_back_buffer.span() };
-
- int m_octave { 4 };
-
- u32 m_time { 0 };
-
- bool m_should_loop { true };
-};
diff --git a/Applications/Piano/WaveWidget.cpp b/Applications/Piano/WaveWidget.cpp
deleted file mode 100644
index 9c40b46bde..0000000000
--- a/Applications/Piano/WaveWidget.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "WaveWidget.h"
-#include "TrackManager.h"
-#include <AK/NumericLimits.h>
-#include <LibGUI/Painter.h>
-
-WaveWidget::WaveWidget(TrackManager& track_manager)
- : m_track_manager(track_manager)
-{
-}
-
-WaveWidget::~WaveWidget()
-{
-}
-
-int WaveWidget::sample_to_y(int sample) const
-{
- constexpr int nice_scale_factor = 4;
- sample *= nice_scale_factor;
- constexpr double sample_max = NumericLimits<i16>::max();
- double percentage = sample / sample_max;
- double portion_of_half_height = percentage * ((frame_inner_rect().height() - 1) / 2.0);
- double y = (frame_inner_rect().height() / 2.0) + portion_of_half_height;
- return y;
-}
-
-void WaveWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Painter painter(*this);
- painter.fill_rect(frame_inner_rect(), Color::Black);
- painter.translate(frame_thickness(), frame_thickness());
-
- Color left_wave_color = left_wave_colors[m_track_manager.current_track().wave()];
- Color right_wave_color = right_wave_colors[m_track_manager.current_track().wave()];
- auto buffer = m_track_manager.buffer();
- double width_scale = static_cast<double>(frame_inner_rect().width()) / buffer.size();
-
- int prev_x = 0;
- int prev_y_left = sample_to_y(buffer[0].left);
- int prev_y_right = sample_to_y(buffer[0].right);
- painter.set_pixel({ prev_x, prev_y_left }, left_wave_color);
- painter.set_pixel({ prev_x, prev_y_right }, right_wave_color);
-
- for (size_t x = 1; x < buffer.size(); ++x) {
- int y_left = sample_to_y(buffer[x].left);
- int y_right = sample_to_y(buffer[x].right);
-
- Gfx::IntPoint point1_left(prev_x * width_scale, prev_y_left);
- Gfx::IntPoint point2_left(x * width_scale, y_left);
- painter.draw_line(point1_left, point2_left, left_wave_color);
-
- Gfx::IntPoint point1_right(prev_x * width_scale, prev_y_right);
- Gfx::IntPoint point2_right(x * width_scale, y_right);
- painter.draw_line(point1_right, point2_right, right_wave_color);
-
- prev_x = x;
- prev_y_left = y_left;
- prev_y_right = y_right;
- }
-
- GUI::Frame::paint_event(event);
-}
diff --git a/Applications/Piano/WaveWidget.h b/Applications/Piano/WaveWidget.h
deleted file mode 100644
index e8b9cd4d5f..0000000000
--- a/Applications/Piano/WaveWidget.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-class TrackManager;
-
-class WaveWidget final : public GUI::Frame {
- C_OBJECT(WaveWidget)
-public:
- virtual ~WaveWidget() override;
-
-private:
- explicit WaveWidget(TrackManager&);
-
- virtual void paint_event(GUI::PaintEvent&) override;
-
- int sample_to_y(int sample) const;
-
- TrackManager& m_track_manager;
-};
diff --git a/Applications/Piano/main.cpp b/Applications/Piano/main.cpp
deleted file mode 100644
index dc75e2944d..0000000000
--- a/Applications/Piano/main.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "MainWidget.h"
-#include "TrackManager.h"
-#include <AK/Array.h>
-#include <LibAudio/ClientConnection.h>
-#include <LibAudio/WavWriter.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/File.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibThread/Thread.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto audio_client = Audio::ClientConnection::construct();
- audio_client->handshake();
-
- TrackManager track_manager;
-
- auto app_icon = GUI::Icon::default_icon("app-piano");
- auto window = GUI::Window::construct();
- auto& main_widget = window->set_main_widget<MainWidget>(track_manager);
- window->set_title("Piano");
- window->resize(840, 600);
- window->set_icon(app_icon.bitmap_for_size(16));
- window->show();
-
- Audio::WavWriter wav_writer;
- Optional<String> save_path;
- bool need_to_write_wav = false;
-
- auto audio_thread = LibThread::Thread::construct([&] {
- auto audio = Core::File::construct("/dev/audio");
- if (!audio->open(Core::IODevice::WriteOnly)) {
- dbgln("Can't open audio device: {}", audio->error_string());
- return 1;
- }
-
- Array<Sample, sample_count> buffer;
- while (!Core::EventLoop::current().was_exit_requested()) {
- track_manager.fill_buffer(buffer);
- audio->write(reinterpret_cast<u8*>(buffer.data()), buffer_size);
- Core::EventLoop::current().post_event(main_widget, make<Core::CustomEvent>(0));
- Core::EventLoop::wake();
-
- if (need_to_write_wav) {
- need_to_write_wav = false;
- track_manager.reset();
- track_manager.set_should_loop(false);
- do {
- track_manager.fill_buffer(buffer);
- wav_writer.write_samples(reinterpret_cast<u8*>(buffer.data()), buffer_size);
- } while (track_manager.time());
- track_manager.reset();
- track_manager.set_should_loop(true);
- wav_writer.finalize();
- }
- }
- return 0;
- });
- audio_thread->start();
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Piano");
- app_menu.add_action(GUI::Action::create("Export", { Mod_Ctrl, Key_E }, [&](const GUI::Action&) {
- save_path = GUI::FilePicker::get_save_filepath(window, "Untitled", "wav");
- if (!save_path.has_value())
- return;
- wav_writer.set_file(save_path.value());
- if (wav_writer.has_error()) {
- GUI::MessageBox::show(window, String::formatted("Failed to export WAV file: {}", wav_writer.error_string()), "Error", GUI::MessageBox::Type::Error);
- wav_writer.clear_error();
- return;
- }
- need_to_write_wav = true;
- }));
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& edit_menu = menubar->add_menu("Edit");
- main_widget.add_actions(edit_menu);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Piano", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- return app->exec();
-}
diff --git a/Applications/PixelPaint/BrushTool.cpp b/Applications/PixelPaint/BrushTool.cpp
deleted file mode 100644
index 200e270ea7..0000000000
--- a/Applications/PixelPaint/BrushTool.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BrushTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Slider.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Rect.h>
-#include <utility>
-
-namespace PixelPaint {
-
-BrushTool::BrushTool()
-{
-}
-
-BrushTool::~BrushTool()
-{
-}
-
-void BrushTool::on_mousedown(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
-
- m_last_position = event.position();
-}
-
-void BrushTool::on_mousemove(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (!(event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right))
- return;
-
- draw_line(layer.bitmap(), m_editor->color_for(event), m_last_position, event.position());
- layer.did_modify_bitmap(*m_editor->image());
- m_last_position = event.position();
- m_was_drawing = true;
-}
-
-void BrushTool::on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent&)
-{
- if (m_was_drawing) {
- m_editor->did_complete_action();
- m_was_drawing = false;
- }
-}
-
-void BrushTool::draw_point(Gfx::Bitmap& bitmap, const Gfx::Color& color, const Gfx::IntPoint& point)
-{
- for (int y = point.y() - m_size; y < point.y() + m_size; y++) {
- for (int x = point.x() - m_size; x < point.x() + m_size; x++) {
- auto distance = point.distance_from({ x, y });
- if (x < 0 || x >= bitmap.width() || y < 0 || y >= bitmap.height())
- continue;
- if (distance >= m_size)
- continue;
-
- auto falloff = (1.0 - (distance / (float)m_size)) * (1.0f / (100 - m_hardness));
- auto pixel_color = color;
- pixel_color.set_alpha(falloff * 255);
- bitmap.set_pixel(x, y, bitmap.get_pixel(x, y).blend(pixel_color));
- }
- }
-}
-
-void BrushTool::draw_line(Gfx::Bitmap& bitmap, const Gfx::Color& color, const Gfx::IntPoint& start, const Gfx::IntPoint& end)
-{
- int length_x = end.x() - start.x();
- int length_y = end.y() - start.y();
- float y_step = length_y == 0 ? 0 : (float)(length_y) / (float)(length_x);
- if (y_step > abs(length_y))
- y_step = abs(length_y);
- if (y_step < -abs(length_y))
- y_step = -abs(length_y);
- if (y_step == 0 && start.x() == end.x())
- return;
-
- int start_x = start.x();
- int end_x = end.x();
- int start_y = start.y();
- int end_y = end.y();
- if (start_x > end_x) {
- swap(start_x, end_x);
- swap(start_y, end_y);
- }
-
- float y = start_y;
- for (int x = start_x; x <= end_x; x++) {
- int start_step_y = y;
- int end_step_y = y + y_step;
- if (start_step_y > end_step_y)
- swap(start_step_y, end_step_y);
- for (int i = start_step_y; i <= end_step_y; i++)
- draw_point(bitmap, color, { x, i });
- y += y_step;
- }
-}
-
-GUI::Widget* BrushTool::get_properties_widget()
-{
- if (!m_properties_widget) {
- m_properties_widget = GUI::Widget::construct();
- m_properties_widget->set_layout<GUI::VerticalBoxLayout>();
-
- auto& size_container = m_properties_widget->add<GUI::Widget>();
- size_container.set_fixed_height(20);
- size_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& size_label = size_container.add<GUI::Label>("Size:");
- size_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- size_label.set_fixed_size(80, 20);
-
- auto& size_slider = size_container.add<GUI::HorizontalSlider>();
- size_slider.set_fixed_height(20);
- size_slider.set_range(1, 100);
- size_slider.set_value(m_size);
- size_slider.on_change = [this](int value) {
- m_size = value;
- };
-
- auto& hardness_container = m_properties_widget->add<GUI::Widget>();
- hardness_container.set_fixed_height(20);
- hardness_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& hardness_label = hardness_container.add<GUI::Label>("Hardness:");
- hardness_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- hardness_label.set_fixed_size(80, 20);
-
- auto& hardness_slider = hardness_container.add<GUI::HorizontalSlider>();
- hardness_slider.set_fixed_height(20);
- hardness_slider.set_range(1, 99);
- hardness_slider.set_value(m_hardness);
- hardness_slider.on_change = [this](int value) {
- m_hardness = value;
- };
- }
-
- return m_properties_widget.ptr();
-}
-
-}
diff --git a/Applications/PixelPaint/BrushTool.h b/Applications/PixelPaint/BrushTool.h
deleted file mode 100644
index 939ccdeef4..0000000000
--- a/Applications/PixelPaint/BrushTool.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-
-namespace PixelPaint {
-
-class BrushTool final : public Tool {
-public:
- BrushTool();
- virtual ~BrushTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual GUI::Widget* get_properties_widget() override;
-
-private:
- RefPtr<GUI::Widget> m_properties_widget;
- int m_size { 20 };
- int m_hardness { 80 };
- bool m_was_drawing { false };
- Gfx::IntPoint m_last_position;
-
- void draw_line(Gfx::Bitmap& bitmap, const Gfx::Color& color, const Gfx::IntPoint& start, const Gfx::IntPoint& end);
- void draw_point(Gfx::Bitmap& bitmap, const Gfx::Color& color, const Gfx::IntPoint& point);
-};
-
-}
diff --git a/Applications/PixelPaint/BucketTool.cpp b/Applications/PixelPaint/BucketTool.cpp
deleted file mode 100644
index 6cffddac20..0000000000
--- a/Applications/PixelPaint/BucketTool.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BucketTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <AK/Queue.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Slider.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Rect.h>
-
-namespace PixelPaint {
-
-BucketTool::BucketTool()
-{
-}
-
-BucketTool::~BucketTool()
-{
-}
-
-static float color_distance_squared(const Gfx::Color& lhs, const Gfx::Color& rhs)
-{
- int a = rhs.red() - lhs.red();
- int b = rhs.green() - lhs.green();
- int c = rhs.blue() - lhs.blue();
- return (a * a + b * b + c * c) / (255.0f * 255.0f);
-}
-
-static void flood_fill(Gfx::Bitmap& bitmap, const Gfx::IntPoint& start_position, Color target_color, Color fill_color, int threshold)
-{
- ASSERT(bitmap.bpp() == 32);
-
- if (target_color == fill_color)
- return;
-
- if (!bitmap.rect().contains(start_position))
- return;
-
- float threshold_normalized_squared = (threshold / 100.0f) * (threshold / 100.0f);
-
- Queue<Gfx::IntPoint> queue;
- queue.enqueue(start_position);
- while (!queue.is_empty()) {
- auto position = queue.dequeue();
-
- auto pixel_color = bitmap.get_pixel<Gfx::StorageFormat::RGBA32>(position.x(), position.y());
- if (color_distance_squared(pixel_color, target_color) > threshold_normalized_squared)
- continue;
-
- bitmap.set_pixel<Gfx::StorageFormat::RGBA32>(position.x(), position.y(), fill_color);
-
- if (position.x() != 0)
- queue.enqueue(position.translated(-1, 0));
-
- if (position.x() != bitmap.width() - 1)
- queue.enqueue(position.translated(1, 0));
-
- if (position.y() != 0)
- queue.enqueue(position.translated(0, -1));
-
- if (position.y() != bitmap.height() - 1)
- queue.enqueue(position.translated(0, 1));
- }
-}
-
-void BucketTool::on_mousedown(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (!layer.rect().contains(event.position()))
- return;
-
- GUI::Painter painter(layer.bitmap());
- auto target_color = layer.bitmap().get_pixel(event.x(), event.y());
-
- flood_fill(layer.bitmap(), event.position(), target_color, m_editor->color_for(event), m_threshold);
-
- layer.did_modify_bitmap(*m_editor->image());
- m_editor->did_complete_action();
-}
-
-GUI::Widget* BucketTool::get_properties_widget()
-{
- if (!m_properties_widget) {
- m_properties_widget = GUI::Widget::construct();
- m_properties_widget->set_layout<GUI::VerticalBoxLayout>();
-
- auto& threshold_container = m_properties_widget->add<GUI::Widget>();
- threshold_container.set_fixed_height(20);
- threshold_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& threshold_label = threshold_container.add<GUI::Label>("Threshold:");
- threshold_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- threshold_label.set_fixed_size(80, 20);
-
- auto& threshold_slider = threshold_container.add<GUI::HorizontalSlider>();
- threshold_slider.set_fixed_height(20);
- threshold_slider.set_range(0, 100);
- threshold_slider.set_value(m_threshold);
- threshold_slider.on_change = [this](int value) {
- m_threshold = value;
- };
- }
-
- return m_properties_widget.ptr();
-}
-
-}
diff --git a/Applications/PixelPaint/BucketTool.h b/Applications/PixelPaint/BucketTool.h
deleted file mode 100644
index b4bf700815..0000000000
--- a/Applications/PixelPaint/BucketTool.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-
-namespace PixelPaint {
-
-class BucketTool final : public Tool {
-public:
- BucketTool();
- virtual ~BucketTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual GUI::Widget* get_properties_widget() override;
-
-private:
- RefPtr<GUI::Widget> m_properties_widget;
- int m_threshold { 0 };
-};
-
-}
diff --git a/Applications/PixelPaint/CMakeLists.txt b/Applications/PixelPaint/CMakeLists.txt
deleted file mode 100644
index 713845c80e..0000000000
--- a/Applications/PixelPaint/CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-set(SOURCES
- BrushTool.cpp
- BucketTool.cpp
- CreateNewImageDialog.cpp
- CreateNewLayerDialog.cpp
- EllipseTool.cpp
- EraseTool.cpp
- Image.cpp
- ImageEditor.cpp
- Layer.cpp
- LayerListWidget.cpp
- LayerPropertiesWidget.cpp
- LineTool.cpp
- main.cpp
- MoveTool.cpp
- PaletteWidget.cpp
- PenTool.cpp
- PickerTool.cpp
- RectangleTool.cpp
- SprayTool.cpp
- ToolboxWidget.cpp
- ToolPropertiesWidget.cpp
- Tool.cpp
-)
-
-serenity_app(PixelPaint ICON app-pixel-paint)
-target_link_libraries(PixelPaint LibGUI LibGfx)
diff --git a/Applications/PixelPaint/CreateNewImageDialog.cpp b/Applications/PixelPaint/CreateNewImageDialog.cpp
deleted file mode 100644
index 0696b69ba8..0000000000
--- a/Applications/PixelPaint/CreateNewImageDialog.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CreateNewImageDialog.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TextBox.h>
-
-namespace PixelPaint {
-
-CreateNewImageDialog::CreateNewImageDialog(GUI::Window* parent_window)
- : Dialog(parent_window)
-{
- set_title("Create new image");
- resize(200, 200);
-
- auto& main_widget = set_main_widget<GUI::Widget>();
- main_widget.set_fill_with_background_color(true);
-
- auto& layout = main_widget.set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins({ 4, 4, 4, 4 });
-
- auto& name_label = main_widget.add<GUI::Label>("Name:");
- name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- m_name_textbox = main_widget.add<GUI::TextBox>();
- m_name_textbox->on_change = [this] {
- m_image_name = m_name_textbox->text();
- };
-
- auto& width_label = main_widget.add<GUI::Label>("Width:");
- width_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- auto& width_spinbox = main_widget.add<GUI::SpinBox>();
-
- auto& height_label = main_widget.add<GUI::Label>("Height:");
- height_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- auto& height_spinbox = main_widget.add<GUI::SpinBox>();
-
- auto& button_container = main_widget.add<GUI::Widget>();
- button_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& ok_button = button_container.add<GUI::Button>("OK");
- ok_button.on_click = [this](auto) {
- done(ExecOK);
- };
-
- auto& cancel_button = button_container.add<GUI::Button>("Cancel");
- cancel_button.on_click = [this](auto) {
- done(ExecCancel);
- };
-
- width_spinbox.on_change = [this](int value) {
- m_image_size.set_width(value);
- };
-
- height_spinbox.on_change = [this](int value) {
- m_image_size.set_height(value);
- };
-
- width_spinbox.set_range(0, 16384);
- height_spinbox.set_range(0, 16384);
-}
-
-}
diff --git a/Applications/PixelPaint/CreateNewImageDialog.h b/Applications/PixelPaint/CreateNewImageDialog.h
deleted file mode 100644
index b46b65adab..0000000000
--- a/Applications/PixelPaint/CreateNewImageDialog.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Dialog.h>
-
-namespace PixelPaint {
-
-class CreateNewImageDialog final : public GUI::Dialog {
- C_OBJECT(CreateNewImageDialog)
-
-public:
- const Gfx::IntSize& image_size() const { return m_image_size; }
- const String& image_name() const { return m_image_name; }
-
-private:
- CreateNewImageDialog(GUI::Window* parent_window);
-
- String m_image_name;
- Gfx::IntSize m_image_size;
-
- RefPtr<GUI::TextBox> m_name_textbox;
-};
-
-}
diff --git a/Applications/PixelPaint/CreateNewLayerDialog.cpp b/Applications/PixelPaint/CreateNewLayerDialog.cpp
deleted file mode 100644
index 02f65b51ad..0000000000
--- a/Applications/PixelPaint/CreateNewLayerDialog.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CreateNewLayerDialog.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TextBox.h>
-
-namespace PixelPaint {
-
-CreateNewLayerDialog::CreateNewLayerDialog(const Gfx::IntSize& suggested_size, GUI::Window* parent_window)
- : Dialog(parent_window)
-{
- set_title("Create new layer");
- set_icon(parent_window->icon());
- resize(200, 200);
-
- auto& main_widget = set_main_widget<GUI::Widget>();
- main_widget.set_fill_with_background_color(true);
-
- auto& layout = main_widget.set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins({ 4, 4, 4, 4 });
-
- auto& name_label = main_widget.add<GUI::Label>("Name:");
- name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- m_name_textbox = main_widget.add<GUI::TextBox>();
- m_name_textbox->on_change = [this] {
- m_layer_name = m_name_textbox->text();
- };
-
- auto& width_label = main_widget.add<GUI::Label>("Width:");
- width_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- auto& width_spinbox = main_widget.add<GUI::SpinBox>();
-
- auto& height_label = main_widget.add<GUI::Label>("Height:");
- height_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- auto& height_spinbox = main_widget.add<GUI::SpinBox>();
-
- auto& button_container = main_widget.add<GUI::Widget>();
- button_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& ok_button = button_container.add<GUI::Button>("OK");
- ok_button.on_click = [this](auto) {
- done(ExecOK);
- };
-
- auto& cancel_button = button_container.add<GUI::Button>("Cancel");
- cancel_button.on_click = [this](auto) {
- done(ExecCancel);
- };
-
- width_spinbox.on_change = [this](int value) {
- m_layer_size.set_width(value);
- };
-
- height_spinbox.on_change = [this](int value) {
- m_layer_size.set_height(value);
- };
-
- width_spinbox.set_range(0, 16384);
- height_spinbox.set_range(0, 16384);
-
- width_spinbox.set_value(suggested_size.width());
- height_spinbox.set_value(suggested_size.height());
-}
-
-}
diff --git a/Applications/PixelPaint/CreateNewLayerDialog.h b/Applications/PixelPaint/CreateNewLayerDialog.h
deleted file mode 100644
index bb07ff9943..0000000000
--- a/Applications/PixelPaint/CreateNewLayerDialog.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Dialog.h>
-
-namespace PixelPaint {
-
-class CreateNewLayerDialog final : public GUI::Dialog {
- C_OBJECT(CreateNewLayerDialog);
-
-public:
- const Gfx::IntSize& layer_size() const { return m_layer_size; }
- const String& layer_name() const { return m_layer_name; }
-
-private:
- CreateNewLayerDialog(const Gfx::IntSize& suggested_size, GUI::Window* parent_window);
-
- Gfx::IntSize m_layer_size;
- String m_layer_name;
-
- RefPtr<GUI::TextBox> m_name_textbox;
-};
-
-}
diff --git a/Applications/PixelPaint/EllipseTool.cpp b/Applications/PixelPaint/EllipseTool.cpp
deleted file mode 100644
index 0501e2fb96..0000000000
--- a/Applications/PixelPaint/EllipseTool.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "EllipseTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Rect.h>
-#include <math.h>
-
-namespace PixelPaint {
-
-EllipseTool::EllipseTool()
-{
-}
-
-EllipseTool::~EllipseTool()
-{
-}
-
-void EllipseTool::draw_using(GUI::Painter& painter, const Gfx::IntRect& ellipse_intersecting_rect)
-{
- switch (m_mode) {
- case Mode::Outline:
- painter.draw_ellipse_intersecting(ellipse_intersecting_rect, m_editor->color_for(m_drawing_button), m_thickness);
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void EllipseTool::on_mousedown(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
-
- if (m_drawing_button != GUI::MouseButton::None)
- return;
-
- m_drawing_button = event.button();
- m_ellipse_start_position = event.position();
- m_ellipse_end_position = event.position();
- m_editor->update();
-}
-
-void EllipseTool::on_mouseup(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() == m_drawing_button) {
- GUI::Painter painter(layer.bitmap());
- draw_using(painter, Gfx::IntRect::from_two_points(m_ellipse_start_position, m_ellipse_end_position));
- m_drawing_button = GUI::MouseButton::None;
- m_editor->update();
- m_editor->did_complete_action();
- }
-}
-
-void EllipseTool::on_mousemove(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- m_ellipse_end_position = event.position();
- m_editor->update();
-}
-
-void EllipseTool::on_second_paint(const Layer& layer, GUI::PaintEvent& event)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- GUI::Painter painter(*m_editor);
- painter.add_clip_rect(event.rect());
- auto preview_start = m_editor->layer_position_to_editor_position(layer, m_ellipse_start_position).to_type<int>();
- auto preview_end = m_editor->layer_position_to_editor_position(layer, m_ellipse_end_position).to_type<int>();
- draw_using(painter, Gfx::IntRect::from_two_points(preview_start, preview_end));
-}
-
-void EllipseTool::on_keydown(GUI::KeyEvent& event)
-{
- if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
- m_drawing_button = GUI::MouseButton::None;
- m_editor->update();
- event.accept();
- }
-}
-
-void EllipseTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_context_menu->add_action(GUI::Action::create("Outline", [this](auto&) {
- m_mode = Mode::Outline;
- }));
- m_context_menu->add_separator();
- m_thickness_actions.set_exclusive(true);
- auto insert_action = [&](int size, bool checked = false) {
- auto action = GUI::Action::create_checkable(String::number(size), [this, size](auto&) {
- m_thickness = size;
- });
- action->set_checked(checked);
- m_thickness_actions.add_action(*action);
- m_context_menu->add_action(move(action));
- };
- insert_action(1, true);
- insert_action(2);
- insert_action(3);
- insert_action(4);
- }
- m_context_menu->popup(event.screen_position());
-}
-
-}
diff --git a/Applications/PixelPaint/EllipseTool.h b/Applications/PixelPaint/EllipseTool.h
deleted file mode 100644
index 0b1c10c89a..0000000000
--- a/Applications/PixelPaint/EllipseTool.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibGUI/ActionGroup.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class EllipseTool final : public Tool {
-public:
- EllipseTool();
- virtual ~EllipseTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
- virtual void on_second_paint(const Layer&, GUI::PaintEvent&) override;
- virtual void on_keydown(GUI::KeyEvent&) override;
-
-private:
- enum class Mode {
- Outline,
- // FIXME: Add Mode::Fill
- };
-
- void draw_using(GUI::Painter&, const Gfx::IntRect&);
-
- GUI::MouseButton m_drawing_button { GUI::MouseButton::None };
- Gfx::IntPoint m_ellipse_start_position;
- Gfx::IntPoint m_ellipse_end_position;
- RefPtr<GUI::Menu> m_context_menu;
- int m_thickness { 1 };
- GUI::ActionGroup m_thickness_actions;
- Mode m_mode { Mode::Outline };
-};
-
-}
diff --git a/Applications/PixelPaint/EraseTool.cpp b/Applications/PixelPaint/EraseTool.cpp
deleted file mode 100644
index 19d1482ba8..0000000000
--- a/Applications/PixelPaint/EraseTool.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "EraseTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Bitmap.h>
-
-namespace PixelPaint {
-
-EraseTool::EraseTool()
-{
-}
-
-EraseTool::~EraseTool()
-{
-}
-
-Gfx::IntRect EraseTool::build_rect(const Gfx::IntPoint& pos, const Gfx::IntRect& widget_rect)
-{
- const int base_eraser_size = 10;
- const int eraser_size = (base_eraser_size * m_thickness);
- const int eraser_radius = eraser_size / 2;
- const auto ex = pos.x();
- const auto ey = pos.y();
- return Gfx::IntRect(ex - eraser_radius, ey - eraser_radius, eraser_size, eraser_size).intersected(widget_rect);
-}
-
-void EraseTool::on_mousedown(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
- Gfx::IntRect r = build_rect(event.position(), layer.rect());
- GUI::Painter painter(layer.bitmap());
- painter.clear_rect(r, get_color());
- layer.did_modify_bitmap(*m_editor->image());
-}
-
-void EraseTool::on_mousemove(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right) {
- Gfx::IntRect r = build_rect(event.position(), layer.rect());
- GUI::Painter painter(layer.bitmap());
- painter.clear_rect(r, get_color());
- layer.did_modify_bitmap(*m_editor->image());
- }
-}
-
-void EraseTool::on_mouseup(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
- m_editor->did_complete_action();
-}
-
-void EraseTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
-
- auto eraser_color_toggler = GUI::Action::create_checkable("Use secondary color", [&](auto& action) {
- m_use_secondary_color = action.is_checked();
- });
- eraser_color_toggler->set_checked(m_use_secondary_color);
-
- m_context_menu->add_action(eraser_color_toggler);
- m_context_menu->add_separator();
-
- m_thickness_actions.set_exclusive(true);
- auto insert_action = [&](int size, bool checked = false) {
- auto action = GUI::Action::create_checkable(String::number(size), [this, size](auto&) {
- m_thickness = size;
- });
- action->set_checked(checked);
- m_thickness_actions.add_action(*action);
- m_context_menu->add_action(move(action));
- };
- insert_action(1, true);
- insert_action(2);
- insert_action(3);
- insert_action(4);
- }
-
- m_context_menu->popup(event.screen_position());
-}
-
-Color EraseTool::get_color() const
-{
- if (m_use_secondary_color)
- return m_editor->secondary_color();
- return Color(255, 255, 255, 0);
-}
-
-}
diff --git a/Applications/PixelPaint/EraseTool.h b/Applications/PixelPaint/EraseTool.h
deleted file mode 100644
index 16241e87f0..0000000000
--- a/Applications/PixelPaint/EraseTool.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibGUI/ActionGroup.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class EraseTool final : public Tool {
-public:
- EraseTool();
- virtual ~EraseTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
-
-private:
- Gfx::Color get_color() const;
- Gfx::IntRect build_rect(const Gfx::IntPoint& pos, const Gfx::IntRect& widget_rect);
- RefPtr<GUI::Menu> m_context_menu;
-
- bool m_use_secondary_color { false };
- int m_thickness { 1 };
- GUI::ActionGroup m_thickness_actions;
-};
-
-}
diff --git a/Applications/PixelPaint/FilterParams.h b/Applications/PixelPaint/FilterParams.h
deleted file mode 100644
index 398caecf9f..0000000000
--- a/Applications/PixelPaint/FilterParams.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/Dialog.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/TextBox.h>
-#include <LibGfx/Filters/BoxBlurFilter.h>
-#include <LibGfx/Filters/GenericConvolutionFilter.h>
-#include <LibGfx/Filters/LaplacianFilter.h>
-#include <LibGfx/Filters/SharpenFilter.h>
-#include <LibGfx/Filters/SpatialGaussianBlurFilter.h>
-
-namespace PixelPaint {
-
-template<typename Filter>
-struct FilterParameters {
-};
-
-template<size_t N>
-class GenericConvolutionFilterInputDialog : public GUI::Dialog {
- C_OBJECT(GenericConvolutionFilterInputDialog);
-
-public:
- const Matrix<N, float>& matrix() const { return m_matrix; }
- bool should_wrap() const { return m_should_wrap; }
-
-private:
- explicit GenericConvolutionFilterInputDialog(GUI::Window* parent_window)
- : Dialog(parent_window)
- {
- // FIXME: Help! Make this GUI less ugly.
- StringBuilder builder;
- builder.appendf("%zux%zu", N, N);
- builder.append(" Convolution");
- set_title(builder.string_view());
-
- resize(200, 250);
- auto& main_widget = set_main_widget<GUI::Frame>();
- main_widget.set_frame_shape(Gfx::FrameShape::Container);
- main_widget.set_frame_shadow(Gfx::FrameShadow::Raised);
- main_widget.set_fill_with_background_color(true);
- auto& layout = main_widget.template set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins({ 4, 4, 4, 4 });
-
- size_t index = 0;
- size_t columns = N;
- size_t rows = N;
-
- for (size_t row = 0; row < rows; ++row) {
- auto& horizontal_container = main_widget.template add<GUI::Widget>();
- horizontal_container.template set_layout<GUI::HorizontalBoxLayout>();
- for (size_t column = 0; column < columns; ++column) {
- if (index < columns * rows) {
- auto& textbox = horizontal_container.template add<GUI::TextBox>();
- textbox.on_change = [&, row = row, column = column] {
- auto& element = m_matrix.elements()[row][column];
- char* endptr = nullptr;
- auto value = strtof(textbox.text().characters(), &endptr);
- if (endptr != nullptr)
- element = value;
- else
- textbox.set_text("");
- };
- } else {
- horizontal_container.template add<GUI::Widget>();
- }
- }
- }
-
- auto& norm_checkbox = main_widget.template add<GUI::CheckBox>("Normalize");
- norm_checkbox.set_checked(false);
-
- auto& wrap_checkbox = main_widget.template add<GUI::CheckBox>("Wrap");
- wrap_checkbox.set_checked(m_should_wrap);
-
- auto& button = main_widget.template add<GUI::Button>("Done");
- button.on_click = [&](auto) {
- m_should_wrap = wrap_checkbox.is_checked();
- if (norm_checkbox.is_checked())
- normalize(m_matrix);
- done(ExecOK);
- };
- }
-
- Matrix<N, float> m_matrix {};
- bool m_should_wrap { false };
-};
-
-template<size_t N>
-struct FilterParameters<Gfx::SpatialGaussianBlurFilter<N>> {
- static OwnPtr<typename Gfx::SpatialGaussianBlurFilter<N>::Parameters> get()
- {
- constexpr static ssize_t offset = N / 2;
- Matrix<N, float> kernel;
- auto sigma = 1.0f;
- auto s = 2.0f * sigma * sigma;
-
- for (auto x = -offset; x <= offset; x++) {
- for (auto y = -offset; y <= offset; y++) {
- auto r = sqrt(x * x + y * y);
- kernel.elements()[x + offset][y + offset] = (exp(-(r * r) / s)) / (M_PI * s);
- }
- }
-
- normalize(kernel);
-
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
- }
-};
-
-template<>
-struct FilterParameters<Gfx::SharpenFilter> {
- static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get()
- {
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 5, -1, 0, -1, 0));
- }
-};
-
-template<>
-struct FilterParameters<Gfx::LaplacianFilter> {
- static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get(bool diagonal)
- {
- if (diagonal)
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(-1, -1, -1, -1, 8, -1, -1, -1, -1));
-
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 4, -1, 0, -1, 0));
- }
-};
-
-template<size_t N>
-struct FilterParameters<Gfx::GenericConvolutionFilter<N>> {
- static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get(GUI::Window* parent_window)
- {
- auto input = GenericConvolutionFilterInputDialog<N>::construct(parent_window);
- input->exec();
- if (input->result() == GUI::Dialog::ExecOK)
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(input->matrix(), input->should_wrap());
-
- return {};
- }
-};
-
-template<size_t N>
-struct FilterParameters<Gfx::BoxBlurFilter<N>> {
- static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get()
- {
- Matrix<N, float> kernel;
-
- for (size_t i = 0; i < N; ++i) {
- for (size_t j = 0; j < N; ++j) {
- kernel.elements()[i][j] = 1;
- }
- }
-
- normalize(kernel);
-
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
- }
-};
-
-}
diff --git a/Applications/PixelPaint/Image.cpp b/Applications/PixelPaint/Image.cpp
deleted file mode 100644
index 09a075dfe0..0000000000
--- a/Applications/PixelPaint/Image.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Image.h"
-#include "Layer.h"
-#include <AK/Base64.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonObjectSerializer.h>
-#include <AK/JsonValue.h>
-#include <AK/StringBuilder.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/BMPWriter.h>
-#include <LibGfx/ImageDecoder.h>
-#include <stdio.h>
-
-//#define PAINT_DEBUG
-
-namespace PixelPaint {
-
-RefPtr<Image> Image::create_with_size(const Gfx::IntSize& size)
-{
- if (size.is_empty())
- return nullptr;
-
- if (size.width() > 16384 || size.height() > 16384)
- return nullptr;
-
- return adopt(*new Image(size));
-}
-
-Image::Image(const Gfx::IntSize& size)
- : m_size(size)
-{
-}
-
-void Image::paint_into(GUI::Painter& painter, const Gfx::IntRect& dest_rect)
-{
- float scale = (float)dest_rect.width() / (float)rect().width();
- Gfx::PainterStateSaver saver(painter);
- painter.add_clip_rect(dest_rect);
- for (auto& layer : m_layers) {
- if (!layer.is_visible())
- continue;
- auto target = dest_rect.translated(layer.location().x() * scale, layer.location().y() * scale);
- target.set_size(layer.size().width() * scale, layer.size().height() * scale);
- painter.draw_scaled_bitmap(target, layer.bitmap(), layer.rect(), (float)layer.opacity_percent() / 100.0f);
- }
-}
-
-RefPtr<Image> Image::create_from_file(const String& file_path)
-{
- auto file = fopen(file_path.characters(), "r");
- fseek(file, 0L, SEEK_END);
- auto length = ftell(file);
- rewind(file);
-
- auto buffer = ByteBuffer::create_uninitialized(length);
- fread(buffer.data(), sizeof(u8), length, file);
- fclose(file);
-
- auto json_or_error = JsonValue::from_string(String::copy(buffer));
- if (!json_or_error.has_value())
- return nullptr;
-
- auto json = json_or_error.value().as_object();
- auto image = create_with_size({ json.get("width").to_i32(), json.get("height").to_i32() });
- json.get("layers").as_array().for_each([&](JsonValue json_layer) {
- auto json_layer_object = json_layer.as_object();
- auto width = json_layer_object.get("width").to_i32();
- auto height = json_layer_object.get("height").to_i32();
- auto name = json_layer_object.get("name").as_string();
- auto layer = Layer::create_with_size(*image, { width, height }, name);
- layer->set_location({ json_layer_object.get("locationx").to_i32(), json_layer_object.get("locationy").to_i32() });
- layer->set_opacity_percent(json_layer_object.get("opacity_percent").to_i32());
- layer->set_visible(json_layer_object.get("visible").as_bool());
- layer->set_selected(json_layer_object.get("selected").as_bool());
-
- auto bitmap_base64_encoded = json_layer_object.get("bitmap").as_string();
- auto bitmap_data = decode_base64(bitmap_base64_encoded);
- auto image_decoder = Gfx::ImageDecoder::create(bitmap_data);
- layer->set_bitmap(*image_decoder->bitmap());
- image->add_layer(*layer);
- });
-
- return image;
-}
-
-void Image::save(const String& file_path) const
-{
- // Build json file
- StringBuilder builder;
- JsonObjectSerializer json(builder);
- json.add("width", m_size.width());
- json.add("height", m_size.height());
- {
- auto json_layers = json.add_array("layers");
- for (const auto& layer : m_layers) {
- Gfx::BMPWriter bmp_dumber;
- auto json_layer = json_layers.add_object();
- json_layer.add("width", layer.size().width());
- json_layer.add("height", layer.size().height());
- json_layer.add("name", layer.name());
- json_layer.add("locationx", layer.location().x());
- json_layer.add("locationy", layer.location().y());
- json_layer.add("opacity_percent", layer.opacity_percent());
- json_layer.add("visible", layer.is_visible());
- json_layer.add("selected", layer.is_selected());
- json_layer.add("bitmap", encode_base64(bmp_dumber.dump(layer.bitmap())));
- }
- }
- json.finish();
-
- // Write json to disk
- auto file = fopen(file_path.characters(), "w");
- auto byte_buffer = builder.to_byte_buffer();
- fwrite(byte_buffer.data(), sizeof(u8), byte_buffer.size(), file);
- fclose(file);
-}
-
-void Image::export_bmp(const String& file_path)
-{
- auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, m_size);
- GUI::Painter painter(*bitmap);
- paint_into(painter, { 0, 0, m_size.width(), m_size.height() });
-
- Gfx::BMPWriter dumper;
- auto bmp = dumper.dump(bitmap);
- auto file = fopen(file_path.characters(), "wb");
- fwrite(bmp.data(), sizeof(u8), bmp.size(), file);
- fclose(file);
-}
-
-void Image::add_layer(NonnullRefPtr<Layer> layer)
-{
- for (auto& existing_layer : m_layers) {
- ASSERT(&existing_layer != layer.ptr());
- }
- m_layers.append(move(layer));
-
- for (auto* client : m_clients)
- client->image_did_add_layer(m_layers.size() - 1);
-
- did_modify_layer_stack();
-}
-
-RefPtr<Image> Image::take_snapshot() const
-{
- auto snapshot = create_with_size(m_size);
- for (const auto& layer : m_layers)
- snapshot->add_layer(*Layer::create_snapshot(*snapshot, layer));
- return snapshot;
-}
-
-void Image::restore_snapshot(const Image& snapshot)
-{
- m_layers.clear();
- select_layer(nullptr);
- for (const auto& snapshot_layer : snapshot.m_layers) {
- auto layer = Layer::create_snapshot(*this, snapshot_layer);
- if (layer->is_selected())
- select_layer(layer.ptr());
- add_layer(*layer);
- }
-
- did_modify_layer_stack();
-}
-
-size_t Image::index_of(const Layer& layer) const
-{
- for (size_t i = 0; i < m_layers.size(); ++i) {
- if (&m_layers.at(i) == &layer)
- return i;
- }
- ASSERT_NOT_REACHED();
-}
-
-void Image::move_layer_to_back(Layer& layer)
-{
- NonnullRefPtr<Layer> protector(layer);
- auto index = index_of(layer);
- m_layers.remove(index);
- m_layers.prepend(layer);
-
- did_modify_layer_stack();
-}
-
-void Image::move_layer_to_front(Layer& layer)
-{
- NonnullRefPtr<Layer> protector(layer);
- auto index = index_of(layer);
- m_layers.remove(index);
- m_layers.append(layer);
-
- did_modify_layer_stack();
-}
-
-void Image::move_layer_down(Layer& layer)
-{
- NonnullRefPtr<Layer> protector(layer);
- auto index = index_of(layer);
- if (!index)
- return;
- m_layers.remove(index);
- m_layers.insert(index - 1, layer);
-
- did_modify_layer_stack();
-}
-
-void Image::move_layer_up(Layer& layer)
-{
- NonnullRefPtr<Layer> protector(layer);
- auto index = index_of(layer);
- if (index == m_layers.size() - 1)
- return;
- m_layers.remove(index);
- m_layers.insert(index + 1, layer);
-
- did_modify_layer_stack();
-}
-
-void Image::change_layer_index(size_t old_index, size_t new_index)
-{
- ASSERT(old_index < m_layers.size());
- ASSERT(new_index < m_layers.size());
- auto layer = m_layers.take(old_index);
- m_layers.insert(new_index, move(layer));
- did_modify_layer_stack();
-}
-
-void Image::did_modify_layer_stack()
-{
- for (auto* client : m_clients)
- client->image_did_modify_layer_stack();
-
- did_change();
-}
-
-void Image::remove_layer(Layer& layer)
-{
- NonnullRefPtr<Layer> protector(layer);
- auto index = index_of(layer);
- m_layers.remove(index);
-
- for (auto* client : m_clients)
- client->image_did_remove_layer(index);
-
- did_modify_layer_stack();
-}
-
-void Image::select_layer(Layer* layer)
-{
- for (auto* client : m_clients)
- client->image_select_layer(layer);
-}
-
-void Image::add_client(ImageClient& client)
-{
- ASSERT(!m_clients.contains(&client));
- m_clients.set(&client);
-}
-
-void Image::remove_client(ImageClient& client)
-{
- ASSERT(m_clients.contains(&client));
- m_clients.remove(&client);
-}
-
-void Image::layer_did_modify_bitmap(Badge<Layer>, const Layer& layer)
-{
- auto layer_index = index_of(layer);
- for (auto* client : m_clients)
- client->image_did_modify_layer(layer_index);
-
- did_change();
-}
-
-void Image::layer_did_modify_properties(Badge<Layer>, const Layer& layer)
-{
- auto layer_index = index_of(layer);
- for (auto* client : m_clients)
- client->image_did_modify_layer(layer_index);
-
- did_change();
-}
-
-void Image::did_change()
-{
- for (auto* client : m_clients)
- client->image_did_change();
-}
-
-ImageUndoCommand::ImageUndoCommand(Image& image)
- : m_snapshot(image.take_snapshot())
- , m_image(image)
-{
-}
-
-void ImageUndoCommand::undo()
-{
- m_image.restore_snapshot(*m_snapshot);
-}
-
-void ImageUndoCommand::redo()
-{
- undo();
-}
-
-}
diff --git a/Applications/PixelPaint/Image.h b/Applications/PixelPaint/Image.h
deleted file mode 100644
index 63184b3ad3..0000000000
--- a/Applications/PixelPaint/Image.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/HashTable.h>
-#include <AK/NonnullRefPtrVector.h>
-#include <AK/RefCounted.h>
-#include <AK/RefPtr.h>
-#include <AK/Vector.h>
-#include <LibGUI/Command.h>
-#include <LibGUI/Forward.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-#include <LibGfx/Size.h>
-
-namespace PixelPaint {
-
-class Layer;
-
-class ImageClient {
-public:
- virtual void image_did_add_layer(size_t) { }
- virtual void image_did_remove_layer(size_t) { }
- virtual void image_did_modify_layer(size_t) { }
- virtual void image_did_modify_layer_stack() { }
- virtual void image_did_change() { }
- virtual void image_select_layer(Layer*) { }
-};
-
-class Image : public RefCounted<Image> {
-public:
- static RefPtr<Image> create_with_size(const Gfx::IntSize&);
- static RefPtr<Image> create_from_file(const String& file_path);
-
- size_t layer_count() const { return m_layers.size(); }
- const Layer& layer(size_t index) const { return m_layers.at(index); }
- Layer& layer(size_t index) { return m_layers.at(index); }
-
- const Gfx::IntSize& size() const { return m_size; }
- Gfx::IntRect rect() const { return { {}, m_size }; }
-
- void add_layer(NonnullRefPtr<Layer>);
- RefPtr<Image> take_snapshot() const;
- void restore_snapshot(const Image&);
-
- void paint_into(GUI::Painter&, const Gfx::IntRect& dest_rect);
- void save(const String& file_path) const;
- void export_bmp(const String& file_path);
-
- void move_layer_to_front(Layer&);
- void move_layer_to_back(Layer&);
- void move_layer_up(Layer&);
- void move_layer_down(Layer&);
- void change_layer_index(size_t old_index, size_t new_index);
- void remove_layer(Layer&);
- void select_layer(Layer*);
-
- void add_client(ImageClient&);
- void remove_client(ImageClient&);
-
- void layer_did_modify_bitmap(Badge<Layer>, const Layer&);
- void layer_did_modify_properties(Badge<Layer>, const Layer&);
-
- size_t index_of(const Layer&) const;
-
-private:
- explicit Image(const Gfx::IntSize&);
-
- void did_change();
- void did_modify_layer_stack();
-
- Gfx::IntSize m_size;
- NonnullRefPtrVector<Layer> m_layers;
-
- HashTable<ImageClient*> m_clients;
-};
-
-class ImageUndoCommand : public GUI::Command {
-public:
- ImageUndoCommand(Image& image);
-
- virtual void undo() override;
- virtual void redo() override;
-
-private:
- RefPtr<Image> m_snapshot;
- Image& m_image;
-};
-
-}
diff --git a/Applications/PixelPaint/ImageEditor.cpp b/Applications/PixelPaint/ImageEditor.cpp
deleted file mode 100644
index f29551c050..0000000000
--- a/Applications/PixelPaint/ImageEditor.cpp
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ImageEditor.h"
-#include "Image.h"
-#include "Layer.h"
-#include "MoveTool.h"
-#include "Tool.h"
-#include <LibGUI/Command.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/Rect.h>
-
-namespace PixelPaint {
-
-ImageEditor::ImageEditor()
- : m_undo_stack(make<GUI::UndoStack>())
-{
- set_focus_policy(GUI::FocusPolicy::StrongFocus);
-}
-
-ImageEditor::~ImageEditor()
-{
- if (m_image)
- m_image->remove_client(*this);
-}
-
-void ImageEditor::set_image(RefPtr<Image> image)
-{
- if (m_image)
- m_image->remove_client(*this);
-
- m_image = move(image);
- m_active_layer = nullptr;
- m_undo_stack = make<GUI::UndoStack>();
- m_undo_stack->push(make<ImageUndoCommand>(*m_image));
- update();
- relayout();
-
- if (m_image)
- m_image->add_client(*this);
-}
-
-void ImageEditor::did_complete_action()
-{
- if (!m_image)
- return;
- m_undo_stack->finalize_current_combo();
- m_undo_stack->push(make<ImageUndoCommand>(*m_image));
-}
-
-bool ImageEditor::undo()
-{
- if (!m_image)
- return false;
- if (m_undo_stack->can_undo()) {
- m_undo_stack->undo();
- layers_did_change();
- return true;
- }
- return false;
-}
-
-bool ImageEditor::redo()
-{
- if (!m_image)
- return false;
- if (m_undo_stack->can_redo()) {
- m_undo_stack->redo();
- layers_did_change();
- return true;
- }
- return false;
-}
-
-void ImageEditor::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.add_clip_rect(frame_inner_rect());
-
- Gfx::StylePainter::paint_transparency_grid(painter, rect(), palette());
-
- if (m_image) {
- painter.draw_rect(m_editor_image_rect.inflated(2, 2), Color::Black);
- m_image->paint_into(painter, m_editor_image_rect);
- }
-
- if (m_active_layer) {
- painter.draw_rect(enclosing_int_rect(image_rect_to_editor_rect(m_active_layer->relative_rect())).inflated(2, 2), Color::Black);
- }
-}
-
-Gfx::FloatRect ImageEditor::layer_rect_to_editor_rect(const Layer& layer, const Gfx::IntRect& layer_rect) const
-{
- return image_rect_to_editor_rect(layer_rect.translated(layer.location()));
-}
-
-Gfx::FloatRect ImageEditor::image_rect_to_editor_rect(const Gfx::IntRect& image_rect) const
-{
- Gfx::FloatRect editor_rect;
- editor_rect.set_location(image_position_to_editor_position(image_rect.location()));
- editor_rect.set_width((float)image_rect.width() * m_scale);
- editor_rect.set_height((float)image_rect.height() * m_scale);
- return editor_rect;
-}
-
-Gfx::FloatRect ImageEditor::editor_rect_to_image_rect(const Gfx::IntRect& editor_rect) const
-{
- Gfx::FloatRect image_rect;
- image_rect.set_location(editor_position_to_image_position(editor_rect.location()));
- image_rect.set_width((float)editor_rect.width() / m_scale);
- image_rect.set_height((float)editor_rect.height() / m_scale);
- return image_rect;
-}
-
-Gfx::FloatPoint ImageEditor::layer_position_to_editor_position(const Layer& layer, const Gfx::IntPoint& layer_position) const
-{
- return image_position_to_editor_position(layer_position.translated(layer.location()));
-}
-
-Gfx::FloatPoint ImageEditor::image_position_to_editor_position(const Gfx::IntPoint& image_position) const
-{
- Gfx::FloatPoint editor_position;
- editor_position.set_x(m_editor_image_rect.x() + ((float)image_position.x() * m_scale));
- editor_position.set_y(m_editor_image_rect.y() + ((float)image_position.y() * m_scale));
- return editor_position;
-}
-
-Gfx::FloatPoint ImageEditor::editor_position_to_image_position(const Gfx::IntPoint& editor_position) const
-{
- Gfx::FloatPoint image_position;
- image_position.set_x(((float)editor_position.x() - m_editor_image_rect.x()) / m_scale);
- image_position.set_y(((float)editor_position.y() - m_editor_image_rect.y()) / m_scale);
- return image_position;
-}
-
-void ImageEditor::second_paint_event(GUI::PaintEvent& event)
-{
- if (m_active_tool && m_active_layer)
- m_active_tool->on_second_paint(*m_active_layer, event);
-}
-
-GUI::MouseEvent ImageEditor::event_with_pan_and_scale_applied(const GUI::MouseEvent& event) const
-{
- auto image_position = editor_position_to_image_position(event.position());
- return {
- static_cast<GUI::Event::Type>(event.type()),
- Gfx::IntPoint(image_position.x(), image_position.y()),
- event.buttons(),
- event.button(),
- event.modifiers(),
- event.wheel_delta()
- };
-}
-
-GUI::MouseEvent ImageEditor::event_adjusted_for_layer(const GUI::MouseEvent& event, const Layer& layer) const
-{
- auto image_position = editor_position_to_image_position(event.position());
- image_position.move_by(-layer.location().x(), -layer.location().y());
- return {
- static_cast<GUI::Event::Type>(event.type()),
- Gfx::IntPoint(image_position.x(), image_position.y()),
- event.buttons(),
- event.button(),
- event.modifiers(),
- event.wheel_delta()
- };
-}
-
-void ImageEditor::mousedown_event(GUI::MouseEvent& event)
-{
- if (event.button() == GUI::MouseButton::Middle) {
- m_click_position = event.position();
- m_saved_pan_origin = m_pan_origin;
- return;
- }
-
- if (!m_active_tool)
- return;
-
- if (is<MoveTool>(*m_active_tool)) {
- if (auto* other_layer = layer_at_editor_position(event.position())) {
- set_active_layer(other_layer);
- }
- }
-
- if (!m_active_layer)
- return;
-
- auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
- auto image_event = event_with_pan_and_scale_applied(event);
- m_active_tool->on_mousedown(*m_active_layer, layer_event, image_event);
-}
-
-void ImageEditor::mousemove_event(GUI::MouseEvent& event)
-{
- if (event.buttons() & GUI::MouseButton::Middle) {
- auto delta = event.position() - m_click_position;
- m_pan_origin = m_saved_pan_origin.translated(
- -delta.x() / m_scale,
- -delta.y() / m_scale);
-
- relayout();
- return;
- }
-
- if (!m_active_layer || !m_active_tool)
- return;
- auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
- auto image_event = event_with_pan_and_scale_applied(event);
-
- m_active_tool->on_mousemove(*m_active_layer, layer_event, image_event);
-}
-
-void ImageEditor::mouseup_event(GUI::MouseEvent& event)
-{
- if (!m_active_layer || !m_active_tool)
- return;
- auto layer_event = event_adjusted_for_layer(event, *m_active_layer);
- auto image_event = event_with_pan_and_scale_applied(event);
- m_active_tool->on_mouseup(*m_active_layer, layer_event, image_event);
-}
-
-void ImageEditor::mousewheel_event(GUI::MouseEvent& event)
-{
- auto old_scale = m_scale;
-
- m_scale += -event.wheel_delta() * 0.1f;
- if (m_scale < 0.1f)
- m_scale = 0.1f;
- if (m_scale > 100.0f)
- m_scale = 100.0f;
-
- auto focus_point = Gfx::FloatPoint(
- m_pan_origin.x() - ((float)event.x() - (float)width() / 2.0) / old_scale,
- m_pan_origin.y() - ((float)event.y() - (float)height() / 2.0) / old_scale);
-
- m_pan_origin = Gfx::FloatPoint(
- focus_point.x() - m_scale / old_scale * (focus_point.x() - m_pan_origin.x()),
- focus_point.y() - m_scale / old_scale * (focus_point.y() - m_pan_origin.y()));
-
- if (old_scale != m_scale)
- relayout();
-}
-
-void ImageEditor::context_menu_event(GUI::ContextMenuEvent& event)
-{
- if (!m_active_layer || !m_active_tool)
- return;
- m_active_tool->on_context_menu(*m_active_layer, event);
-}
-
-void ImageEditor::resize_event(GUI::ResizeEvent& event)
-{
- relayout();
- GUI::Frame::resize_event(event);
-}
-
-void ImageEditor::keydown_event(GUI::KeyEvent& event)
-{
- if (m_active_tool)
- m_active_tool->on_keydown(event);
-}
-
-void ImageEditor::keyup_event(GUI::KeyEvent& event)
-{
- if (m_active_tool)
- m_active_tool->on_keyup(event);
-}
-
-void ImageEditor::set_active_layer(Layer* layer)
-{
- if (m_active_layer == layer)
- return;
- m_active_layer = layer;
-
- if (m_active_layer) {
- size_t index = 0;
- for (; index < m_image->layer_count(); ++index) {
- if (&m_image->layer(index) == layer)
- break;
- }
- if (on_active_layer_change)
- on_active_layer_change(layer);
- } else {
- if (on_active_layer_change)
- on_active_layer_change({});
- }
-
- layers_did_change();
-}
-
-void ImageEditor::set_active_tool(Tool* tool)
-{
- if (m_active_tool == tool)
- return;
-
- if (m_active_tool)
- m_active_tool->clear();
-
- m_active_tool = tool;
-
- if (m_active_tool)
- m_active_tool->setup(*this);
-}
-
-void ImageEditor::layers_did_change()
-{
- update();
-}
-
-Color ImageEditor::color_for(GUI::MouseButton button) const
-{
- if (button == GUI::MouseButton::Left)
- return m_primary_color;
- if (button == GUI::MouseButton::Right)
- return m_secondary_color;
- ASSERT_NOT_REACHED();
-}
-
-Color ImageEditor::color_for(const GUI::MouseEvent& event) const
-{
- if (event.buttons() & GUI::MouseButton::Left)
- return m_primary_color;
- if (event.buttons() & GUI::MouseButton::Right)
- return m_secondary_color;
- ASSERT_NOT_REACHED();
-}
-
-void ImageEditor::set_primary_color(Color color)
-{
- if (m_primary_color == color)
- return;
- m_primary_color = color;
- if (on_primary_color_change)
- on_primary_color_change(color);
-}
-
-void ImageEditor::set_secondary_color(Color color)
-{
- if (m_secondary_color == color)
- return;
- m_secondary_color = color;
- if (on_secondary_color_change)
- on_secondary_color_change(color);
-}
-
-Layer* ImageEditor::layer_at_editor_position(const Gfx::IntPoint& editor_position)
-{
- if (!m_image)
- return nullptr;
- auto image_position = editor_position_to_image_position(editor_position);
- for (ssize_t i = m_image->layer_count() - 1; i >= 0; --i) {
- auto& layer = m_image->layer(i);
- if (!layer.is_visible())
- continue;
- if (layer.relative_rect().contains(Gfx::IntPoint(image_position.x(), image_position.y())))
- return const_cast<Layer*>(&layer);
- }
- return nullptr;
-}
-
-void ImageEditor::relayout()
-{
- if (!image())
- return;
- auto& image = *this->image();
-
- Gfx::IntSize new_size;
- new_size.set_width(image.size().width() * m_scale);
- new_size.set_height(image.size().height() * m_scale);
- m_editor_image_rect.set_size(new_size);
-
- Gfx::IntPoint new_location;
- new_location.set_x((width() / 2) - (new_size.width() / 2) - (m_pan_origin.x() * m_scale));
- new_location.set_y((height() / 2) - (new_size.height() / 2) - (m_pan_origin.y() * m_scale));
- m_editor_image_rect.set_location(new_location);
-
- update();
-}
-
-void ImageEditor::image_did_change()
-{
- update();
-}
-
-void ImageEditor::image_select_layer(Layer* layer)
-{
- set_active_layer(layer);
-}
-
-}
diff --git a/Applications/PixelPaint/ImageEditor.h b/Applications/PixelPaint/ImageEditor.h
deleted file mode 100644
index b6cdc8fb62..0000000000
--- a/Applications/PixelPaint/ImageEditor.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Image.h"
-#include <LibGUI/Frame.h>
-#include <LibGUI/UndoStack.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class Layer;
-class Tool;
-
-class ImageEditor final
- : public GUI::Frame
- , public ImageClient {
- C_OBJECT(ImageEditor);
-
-public:
- virtual ~ImageEditor() override;
-
- const Image* image() const { return m_image; }
- Image* image() { return m_image; }
-
- void set_image(RefPtr<Image>);
-
- Layer* active_layer() { return m_active_layer; }
- void set_active_layer(Layer*);
-
- Tool* active_tool() { return m_active_tool; }
- void set_active_tool(Tool*);
-
- void did_complete_action();
- bool undo();
- bool redo();
-
- void layers_did_change();
-
- Layer* layer_at_editor_position(const Gfx::IntPoint&);
-
- Color primary_color() const { return m_primary_color; }
- void set_primary_color(Color);
-
- Color secondary_color() const { return m_secondary_color; }
- void set_secondary_color(Color);
-
- Color color_for(const GUI::MouseEvent&) const;
- Color color_for(GUI::MouseButton) const;
-
- Function<void(Color)> on_primary_color_change;
- Function<void(Color)> on_secondary_color_change;
-
- Function<void(Layer*)> on_active_layer_change;
-
- Gfx::FloatRect layer_rect_to_editor_rect(const Layer&, const Gfx::IntRect&) const;
- Gfx::FloatRect image_rect_to_editor_rect(const Gfx::IntRect&) const;
- Gfx::FloatRect editor_rect_to_image_rect(const Gfx::IntRect&) const;
- Gfx::FloatPoint layer_position_to_editor_position(const Layer&, const Gfx::IntPoint&) const;
- Gfx::FloatPoint image_position_to_editor_position(const Gfx::IntPoint&) const;
- Gfx::FloatPoint editor_position_to_image_position(const Gfx::IntPoint&) const;
-
-private:
- ImageEditor();
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void second_paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
- virtual void mousewheel_event(GUI::MouseEvent&) override;
- virtual void keydown_event(GUI::KeyEvent&) override;
- virtual void keyup_event(GUI::KeyEvent&) override;
- virtual void context_menu_event(GUI::ContextMenuEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- virtual void image_did_change() override;
- virtual void image_select_layer(Layer*) override;
-
- GUI::MouseEvent event_adjusted_for_layer(const GUI::MouseEvent&, const Layer&) const;
- GUI::MouseEvent event_with_pan_and_scale_applied(const GUI::MouseEvent&) const;
-
- void relayout();
-
- RefPtr<Image> m_image;
- RefPtr<Layer> m_active_layer;
- OwnPtr<GUI::UndoStack> m_undo_stack;
-
- Tool* m_active_tool { nullptr };
-
- Color m_primary_color { Color::Black };
- Color m_secondary_color { Color::White };
-
- Gfx::IntRect m_editor_image_rect;
- float m_scale { 1 };
- Gfx::FloatPoint m_pan_origin;
- Gfx::FloatPoint m_saved_pan_origin;
- Gfx::IntPoint m_click_position;
-};
-
-}
diff --git a/Applications/PixelPaint/Layer.cpp b/Applications/PixelPaint/Layer.cpp
deleted file mode 100644
index e607113c32..0000000000
--- a/Applications/PixelPaint/Layer.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Layer.h"
-#include "Image.h"
-#include <LibGfx/Bitmap.h>
-
-namespace PixelPaint {
-
-RefPtr<Layer> Layer::create_with_size(Image& image, const Gfx::IntSize& size, const String& name)
-{
- if (size.is_empty())
- return nullptr;
-
- if (size.width() > 16384 || size.height() > 16384)
- return nullptr;
-
- return adopt(*new Layer(image, size, name));
-}
-
-RefPtr<Layer> Layer::create_with_bitmap(Image& image, const Gfx::Bitmap& bitmap, const String& name)
-{
- if (bitmap.size().is_empty())
- return nullptr;
-
- if (bitmap.size().width() > 16384 || bitmap.size().height() > 16384)
- return nullptr;
-
- return adopt(*new Layer(image, bitmap, name));
-}
-
-RefPtr<Layer> Layer::create_snapshot(Image& image, const Layer& layer)
-{
- auto snapshot = create_with_bitmap(image, *layer.bitmap().clone(), layer.name());
- snapshot->set_opacity_percent(layer.opacity_percent());
- snapshot->set_visible(layer.is_visible());
- snapshot->set_selected(layer.is_selected());
- snapshot->set_location(layer.location());
- return snapshot;
-}
-
-Layer::Layer(Image& image, const Gfx::IntSize& size, const String& name)
- : m_image(image)
- , m_name(name)
-{
- m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size);
-}
-
-Layer::Layer(Image& image, const Gfx::Bitmap& bitmap, const String& name)
- : m_image(image)
- , m_name(name)
- , m_bitmap(bitmap)
-{
-}
-
-void Layer::did_modify_bitmap(Image& image)
-{
- image.layer_did_modify_bitmap({}, *this);
-}
-
-void Layer::set_visible(bool visible)
-{
- if (m_visible == visible)
- return;
- m_visible = visible;
- m_image.layer_did_modify_properties({}, *this);
-}
-
-void Layer::set_opacity_percent(int opacity_percent)
-{
- if (m_opacity_percent == opacity_percent)
- return;
- m_opacity_percent = opacity_percent;
- m_image.layer_did_modify_properties({}, *this);
-}
-
-void Layer::set_name(const String& name)
-{
- if (m_name == name)
- return;
- m_name = name;
- m_image.layer_did_modify_properties({}, *this);
-}
-
-}
diff --git a/Applications/PixelPaint/Layer.h b/Applications/PixelPaint/Layer.h
deleted file mode 100644
index b3b7d4d603..0000000000
--- a/Applications/PixelPaint/Layer.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Noncopyable.h>
-#include <AK/RefCounted.h>
-#include <AK/String.h>
-#include <AK/Weakable.h>
-#include <LibGfx/Bitmap.h>
-
-namespace PixelPaint {
-
-class Image;
-
-class Layer
- : public RefCounted<Layer>
- , public Weakable<Layer> {
-
- AK_MAKE_NONCOPYABLE(Layer);
- AK_MAKE_NONMOVABLE(Layer);
-
-public:
- static RefPtr<Layer> create_with_size(Image&, const Gfx::IntSize&, const String& name);
- static RefPtr<Layer> create_with_bitmap(Image&, const Gfx::Bitmap&, const String& name);
- static RefPtr<Layer> create_snapshot(Image&, const Layer&);
-
- ~Layer() { }
-
- const Gfx::IntPoint& location() const { return m_location; }
- void set_location(const Gfx::IntPoint& location) { m_location = location; }
-
- const Gfx::Bitmap& bitmap() const { return *m_bitmap; }
- Gfx::Bitmap& bitmap() { return *m_bitmap; }
- Gfx::IntSize size() const { return bitmap().size(); }
-
- Gfx::IntRect relative_rect() const { return { location(), size() }; }
- Gfx::IntRect rect() const { return { {}, size() }; }
-
- const String& name() const { return m_name; }
- void set_name(const String&);
-
- void set_bitmap(Gfx::Bitmap& bitmap) { m_bitmap = bitmap; }
-
- void did_modify_bitmap(Image&);
-
- void set_selected(bool selected) { m_selected = selected; }
- bool is_selected() const { return m_selected; }
-
- bool is_visible() const { return m_visible; }
- void set_visible(bool visible);
-
- int opacity_percent() const { return m_opacity_percent; }
- void set_opacity_percent(int);
-
-private:
- Layer(Image&, const Gfx::IntSize&, const String& name);
- Layer(Image&, const Gfx::Bitmap&, const String& name);
-
- Image& m_image;
-
- String m_name;
- Gfx::IntPoint m_location;
- RefPtr<Gfx::Bitmap> m_bitmap;
-
- bool m_selected { false };
- bool m_visible { true };
-
- int m_opacity_percent { 100 };
-};
-
-}
diff --git a/Applications/PixelPaint/LayerListWidget.cpp b/Applications/PixelPaint/LayerListWidget.cpp
deleted file mode 100644
index 756772bb87..0000000000
--- a/Applications/PixelPaint/LayerListWidget.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "LayerListWidget.h"
-#include "Image.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/Palette.h>
-
-namespace PixelPaint {
-
-LayerListWidget::LayerListWidget()
-{
-}
-
-LayerListWidget::~LayerListWidget()
-{
- if (m_image)
- m_image->remove_client(*this);
-}
-
-void LayerListWidget::set_image(Image* image)
-{
- if (m_image == image)
- return;
- if (m_image)
- m_image->remove_client(*this);
- m_image = image;
- if (m_image)
- m_image->add_client(*this);
-
- rebuild_gadgets();
-}
-
-void LayerListWidget::rebuild_gadgets()
-{
- m_gadgets.clear();
- if (m_image) {
- for (size_t layer_index = 0; layer_index < m_image->layer_count(); ++layer_index) {
- m_gadgets.append({ layer_index, {}, {}, false, {} });
- }
- }
- relayout_gadgets();
-}
-
-void LayerListWidget::resize_event(GUI::ResizeEvent& event)
-{
- Widget::resize_event(event);
- relayout_gadgets();
-}
-
-void LayerListWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- painter.fill_rect(event.rect(), palette().button());
-
- if (!m_image)
- return;
-
- painter.fill_rect(event.rect(), palette().button());
-
- auto paint_gadget = [&](auto& gadget) {
- auto& layer = m_image->layer(gadget.layer_index);
-
- auto adjusted_rect = gadget.rect;
-
- if (gadget.is_moving) {
- adjusted_rect.move_by(0, gadget.movement_delta.y());
- }
-
- if (gadget.is_moving) {
- painter.fill_rect(adjusted_rect, palette().selection().lightened(1.5f));
- } else if (layer.is_selected()) {
- painter.fill_rect(adjusted_rect, palette().selection());
- }
-
- painter.draw_rect(adjusted_rect, Color::Black);
-
- Gfx::IntRect thumbnail_rect { adjusted_rect.x(), adjusted_rect.y(), adjusted_rect.height(), adjusted_rect.height() };
- thumbnail_rect.shrink(8, 8);
- painter.draw_scaled_bitmap(thumbnail_rect, layer.bitmap(), layer.bitmap().rect());
-
- Gfx::IntRect text_rect { thumbnail_rect.right() + 10, adjusted_rect.y(), adjusted_rect.width(), adjusted_rect.height() };
- text_rect.intersect(adjusted_rect);
-
- painter.draw_text(text_rect, layer.name(), Gfx::TextAlignment::CenterLeft, layer.is_selected() ? palette().selection_text() : palette().button_text());
- };
-
- for (auto& gadget : m_gadgets) {
- if (!gadget.is_moving)
- paint_gadget(gadget);
- }
-
- if (m_moving_gadget_index.has_value())
- paint_gadget(m_gadgets[m_moving_gadget_index.value()]);
-}
-
-Optional<size_t> LayerListWidget::gadget_at(const Gfx::IntPoint& position)
-{
- for (size_t i = 0; i < m_gadgets.size(); ++i) {
- if (m_gadgets[i].rect.contains(position))
- return i;
- }
- return {};
-}
-
-void LayerListWidget::mousedown_event(GUI::MouseEvent& event)
-{
- if (!m_image)
- return;
- if (event.button() != GUI::MouseButton::Left)
- return;
- auto gadget_index = gadget_at(event.position());
- if (!gadget_index.has_value()) {
- if (on_layer_select)
- on_layer_select(nullptr);
- return;
- }
- m_moving_gadget_index = gadget_index;
- m_moving_event_origin = event.position();
- auto& gadget = m_gadgets[m_moving_gadget_index.value()];
- auto& layer = m_image->layer(gadget_index.value());
- set_selected_layer(&layer);
- gadget.is_moving = true;
- gadget.movement_delta = {};
- update();
-}
-
-void LayerListWidget::mousemove_event(GUI::MouseEvent& event)
-{
- if (!m_image)
- return;
- if (!m_moving_gadget_index.has_value())
- return;
-
- auto delta = event.position() - m_moving_event_origin;
- auto& gadget = m_gadgets[m_moving_gadget_index.value()];
- ASSERT(gadget.is_moving);
- gadget.movement_delta = delta;
- relayout_gadgets();
-}
-
-void LayerListWidget::mouseup_event(GUI::MouseEvent& event)
-{
- if (!m_image)
- return;
- if (event.button() != GUI::MouseButton::Left)
- return;
- if (!m_moving_gadget_index.has_value())
- return;
-
- size_t old_index = m_moving_gadget_index.value();
- size_t new_index = hole_index_during_move();
- if (new_index >= m_image->layer_count())
- new_index = m_image->layer_count() - 1;
-
- m_moving_gadget_index = {};
- m_image->change_layer_index(old_index, new_index);
-}
-
-void LayerListWidget::image_did_add_layer(size_t layer_index)
-{
- if (m_moving_gadget_index.has_value()) {
- m_gadgets[m_moving_gadget_index.value()].is_moving = false;
- m_moving_gadget_index = {};
- }
- Gadget gadget { layer_index, {}, {}, false, {} };
- m_gadgets.insert(layer_index, move(gadget));
- relayout_gadgets();
-}
-
-void LayerListWidget::image_did_remove_layer(size_t layer_index)
-{
- if (m_moving_gadget_index.has_value()) {
- m_gadgets[m_moving_gadget_index.value()].is_moving = false;
- m_moving_gadget_index = {};
- }
- m_gadgets.remove(layer_index);
- relayout_gadgets();
-}
-
-void LayerListWidget::image_did_modify_layer(size_t layer_index)
-{
- update(m_gadgets[layer_index].rect);
-}
-
-void LayerListWidget::image_did_modify_layer_stack()
-{
- rebuild_gadgets();
-}
-
-static constexpr int gadget_height = 30;
-static constexpr int gadget_spacing = 1;
-static constexpr int vertical_step = gadget_height + gadget_spacing;
-
-size_t LayerListWidget::hole_index_during_move() const
-{
- ASSERT(is_moving_gadget());
- auto& moving_gadget = m_gadgets[m_moving_gadget_index.value()];
- int center_y_of_moving_gadget = moving_gadget.rect.translated(0, moving_gadget.movement_delta.y()).center().y();
- return center_y_of_moving_gadget / vertical_step;
-}
-
-void LayerListWidget::select_bottom_layer()
-{
- if (!m_image || !m_image->layer_count())
- return;
- set_selected_layer(&m_image->layer(0));
-}
-
-void LayerListWidget::select_top_layer()
-{
- if (!m_image || !m_image->layer_count())
- return;
- set_selected_layer(&m_image->layer(m_image->layer_count() - 1));
-}
-
-void LayerListWidget::move_selection(int delta)
-{
- if (!m_image || !m_image->layer_count())
- return;
- int new_layer_index = min(max(0, (int)m_image->layer_count() + delta), (int)m_image->layer_count() - 1);
- set_selected_layer(&m_image->layer(new_layer_index));
-}
-
-void LayerListWidget::relayout_gadgets()
-{
- int y = 0;
-
- Optional<size_t> hole_index;
- if (is_moving_gadget())
- hole_index = hole_index_during_move();
-
- size_t index = 0;
- for (auto& gadget : m_gadgets) {
- if (gadget.is_moving)
- continue;
- if (hole_index.has_value() && index == hole_index.value())
- y += vertical_step;
- gadget.rect = { 0, y, width(), gadget_height };
- y += vertical_step;
- ++index;
- }
-
- update();
-}
-
-void LayerListWidget::set_selected_layer(Layer* layer)
-{
- if (!m_image)
- return;
- for (size_t i = 0; i < m_image->layer_count(); ++i)
- m_image->layer(i).set_selected(layer == &m_image->layer(i));
- if (on_layer_select)
- on_layer_select(layer);
- update();
-}
-
-}
diff --git a/Applications/PixelPaint/LayerListWidget.h b/Applications/PixelPaint/LayerListWidget.h
deleted file mode 100644
index 9550913b8e..0000000000
--- a/Applications/PixelPaint/LayerListWidget.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Image.h"
-#include <LibGUI/Widget.h>
-
-namespace PixelPaint {
-
-class LayerListWidget final
- : public GUI::Widget
- , ImageClient {
- C_OBJECT(LayerListWidget);
-
-public:
- virtual ~LayerListWidget() override;
-
- void set_image(Image*);
-
- void set_selected_layer(Layer*);
- Function<void(Layer*)> on_layer_select;
-
- void select_bottom_layer();
- void select_top_layer();
- void move_selection(int delta);
-
-private:
- explicit LayerListWidget();
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- virtual void image_did_add_layer(size_t) override;
- virtual void image_did_remove_layer(size_t) override;
- virtual void image_did_modify_layer(size_t) override;
- virtual void image_did_modify_layer_stack() override;
-
- void rebuild_gadgets();
- void relayout_gadgets();
-
- size_t hole_index_during_move() const;
-
- struct Gadget {
- size_t layer_index { 0 };
- Gfx::IntRect rect;
- Gfx::IntRect temporary_rect_during_move;
- bool is_moving { false };
- Gfx::IntPoint movement_delta;
- };
-
- bool is_moving_gadget() const { return m_moving_gadget_index.has_value(); }
-
- Optional<size_t> gadget_at(const Gfx::IntPoint&);
-
- Vector<Gadget> m_gadgets;
- RefPtr<Image> m_image;
-
- Optional<size_t> m_moving_gadget_index;
- Gfx::IntPoint m_moving_event_origin;
-};
-
-}
diff --git a/Applications/PixelPaint/LayerPropertiesWidget.cpp b/Applications/PixelPaint/LayerPropertiesWidget.cpp
deleted file mode 100644
index cfdee65c0a..0000000000
--- a/Applications/PixelPaint/LayerPropertiesWidget.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "LayerPropertiesWidget.h"
-#include "Layer.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/OpacitySlider.h>
-#include <LibGUI/TextBox.h>
-#include <LibGfx/Font.h>
-
-namespace PixelPaint {
-
-LayerPropertiesWidget::LayerPropertiesWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
-
- auto& group_box = add<GUI::GroupBox>("Layer properties");
- auto& layout = group_box.set_layout<GUI::VerticalBoxLayout>();
-
- layout.set_margins({ 10, 20, 10, 10 });
-
- auto& name_container = group_box.add<GUI::Widget>();
- name_container.set_fixed_height(20);
- name_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& name_label = name_container.add<GUI::Label>("Name:");
- name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- name_label.set_fixed_size(80, 20);
-
- m_name_textbox = name_container.add<GUI::TextBox>();
- m_name_textbox->set_fixed_height(20);
- m_name_textbox->on_change = [this] {
- if (m_layer)
- m_layer->set_name(m_name_textbox->text());
- };
-
- auto& opacity_container = group_box.add<GUI::Widget>();
- opacity_container.set_fixed_height(20);
- opacity_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& opacity_label = opacity_container.add<GUI::Label>("Opacity:");
- opacity_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- opacity_label.set_fixed_size(80, 20);
-
- m_opacity_slider = opacity_container.add<GUI::OpacitySlider>();
- m_opacity_slider->set_range(0, 100);
- m_opacity_slider->on_change = [this](int value) {
- if (m_layer)
- m_layer->set_opacity_percent(value);
- };
-
- m_visibility_checkbox = group_box.add<GUI::CheckBox>("Visible");
- m_visibility_checkbox->set_fixed_height(20);
- m_visibility_checkbox->on_checked = [this](bool checked) {
- if (m_layer)
- m_layer->set_visible(checked);
- };
-}
-
-LayerPropertiesWidget::~LayerPropertiesWidget()
-{
-}
-
-void LayerPropertiesWidget::set_layer(Layer* layer)
-{
- if (m_layer == layer)
- return;
-
- if (layer) {
- m_layer = layer->make_weak_ptr();
- m_name_textbox->set_text(layer->name());
- m_opacity_slider->set_value(layer->opacity_percent());
- m_visibility_checkbox->set_checked(layer->is_visible());
- set_enabled(true);
- } else {
- m_layer = nullptr;
- set_enabled(false);
- }
-}
-
-}
diff --git a/Applications/PixelPaint/LayerPropertiesWidget.h b/Applications/PixelPaint/LayerPropertiesWidget.h
deleted file mode 100644
index e07e02ec93..0000000000
--- a/Applications/PixelPaint/LayerPropertiesWidget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-namespace PixelPaint {
-
-class Layer;
-
-class LayerPropertiesWidget final : public GUI::Widget {
- C_OBJECT(LayerPropertiesWidget);
-
-public:
- virtual ~LayerPropertiesWidget() override;
-
- void set_layer(Layer*);
-
-private:
- LayerPropertiesWidget();
-
- RefPtr<GUI::CheckBox> m_visibility_checkbox;
- RefPtr<GUI::OpacitySlider> m_opacity_slider;
- RefPtr<GUI::TextBox> m_name_textbox;
-
- WeakPtr<Layer> m_layer;
-};
-
-}
diff --git a/Applications/PixelPaint/LineTool.cpp b/Applications/PixelPaint/LineTool.cpp
deleted file mode 100644
index 7c3e37e836..0000000000
--- a/Applications/PixelPaint/LineTool.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "LineTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <math.h>
-
-namespace PixelPaint {
-
-static Gfx::IntPoint constrain_line_angle(const Gfx::IntPoint& start_pos, const Gfx::IntPoint& end_pos, float angle_increment)
-{
- float current_angle = atan2(end_pos.y() - start_pos.y(), end_pos.x() - start_pos.x()) + M_PI * 2.;
-
- float constrained_angle = ((int)((current_angle + angle_increment / 2.) / angle_increment)) * angle_increment;
-
- auto diff = end_pos - start_pos;
- float line_length = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
-
- return { start_pos.x() + (int)(cos(constrained_angle) * line_length),
- start_pos.y() + (int)(sin(constrained_angle) * line_length) };
-}
-
-LineTool::LineTool()
-{
-}
-
-LineTool::~LineTool()
-{
-}
-
-void LineTool::on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent&)
-{
- if (layer_event.button() != GUI::MouseButton::Left && layer_event.button() != GUI::MouseButton::Right)
- return;
-
- if (m_drawing_button != GUI::MouseButton::None)
- return;
-
- m_drawing_button = layer_event.button();
-
- m_line_start_position = layer_event.position();
- m_line_end_position = layer_event.position();
-
- m_editor->update();
-}
-
-void LineTool::on_mouseup(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() == m_drawing_button) {
- GUI::Painter painter(layer.bitmap());
- painter.draw_line(m_line_start_position, m_line_end_position, m_editor->color_for(m_drawing_button), m_thickness);
- m_drawing_button = GUI::MouseButton::None;
- layer.did_modify_bitmap(*m_editor->image());
- m_editor->did_complete_action();
- }
-}
-
-void LineTool::on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent&)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- if (!m_constrain_angle) {
- m_line_end_position = layer_event.position();
- } else {
- const float ANGLE_STEP = M_PI / 8.0f;
- m_line_end_position = constrain_line_angle(m_line_start_position, layer_event.position(), ANGLE_STEP);
- }
- m_editor->update();
-}
-
-void LineTool::on_second_paint(const Layer& layer, GUI::PaintEvent& event)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- GUI::Painter painter(*m_editor);
- painter.add_clip_rect(event.rect());
- auto preview_start = m_editor->layer_position_to_editor_position(layer, m_line_start_position).to_type<int>();
- auto preview_end = m_editor->layer_position_to_editor_position(layer, m_line_end_position).to_type<int>();
- painter.draw_line(preview_start, preview_end, m_editor->color_for(m_drawing_button), m_thickness);
-}
-
-void LineTool::on_keydown(GUI::KeyEvent& event)
-{
- if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
- m_drawing_button = GUI::MouseButton::None;
- m_editor->update();
- event.accept();
- }
-
- if (event.key() == Key_Shift) {
- m_constrain_angle = true;
- m_editor->update();
- event.accept();
- }
-}
-
-void LineTool::on_keyup(GUI::KeyEvent& event)
-{
- if (event.key() == Key_Shift) {
- m_constrain_angle = false;
- m_editor->update();
- event.accept();
- }
-}
-
-void LineTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_thickness_actions.set_exclusive(true);
- auto insert_action = [&](int size, bool checked = false) {
- auto action = GUI::Action::create_checkable(String::number(size), [this, size](auto&) {
- m_thickness = size;
- });
- action->set_checked(checked);
- m_thickness_actions.add_action(*action);
- m_context_menu->add_action(move(action));
- };
- insert_action(1, true);
- insert_action(2);
- insert_action(3);
- insert_action(4);
- }
- m_context_menu->popup(event.screen_position());
-}
-
-}
diff --git a/Applications/PixelPaint/LineTool.h b/Applications/PixelPaint/LineTool.h
deleted file mode 100644
index aa8757655c..0000000000
--- a/Applications/PixelPaint/LineTool.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibGUI/ActionGroup.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class LineTool final : public Tool {
-public:
- LineTool();
- virtual ~LineTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
- virtual void on_second_paint(const Layer&, GUI::PaintEvent&) override;
- virtual void on_keydown(GUI::KeyEvent&) override;
- virtual void on_keyup(GUI::KeyEvent&) override;
-
-private:
- GUI::MouseButton m_drawing_button { GUI::MouseButton::None };
- Gfx::IntPoint m_line_start_position;
- Gfx::IntPoint m_line_end_position;
-
- RefPtr<GUI::Menu> m_context_menu;
- GUI::ActionGroup m_thickness_actions;
- int m_thickness { 1 };
- bool m_constrain_angle { false };
-};
-
-}
diff --git a/Applications/PixelPaint/MoveTool.cpp b/Applications/PixelPaint/MoveTool.cpp
deleted file mode 100644
index ebeba5ba89..0000000000
--- a/Applications/PixelPaint/MoveTool.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "MoveTool.h"
-#include "Image.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-
-namespace PixelPaint {
-
-MoveTool::MoveTool()
-{
-}
-
-MoveTool::~MoveTool()
-{
-}
-
-void MoveTool::on_mousedown(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent& image_event)
-{
- if (event.button() != GUI::MouseButton::Left)
- return;
- if (!layer.rect().contains(event.position()))
- return;
- m_layer_being_moved = layer;
- m_event_origin = image_event.position();
- m_layer_origin = layer.location();
- m_editor->window()->set_cursor(Gfx::StandardCursor::Move);
-}
-
-void MoveTool::on_mousemove(Layer&, GUI::MouseEvent&, GUI::MouseEvent& image_event)
-{
- if (!m_layer_being_moved)
- return;
- auto delta = image_event.position() - m_event_origin;
- m_layer_being_moved->set_location(m_layer_origin.translated(delta));
- m_editor->layers_did_change();
-}
-
-void MoveTool::on_mouseup(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left)
- return;
- m_layer_being_moved = nullptr;
- m_editor->window()->set_cursor(Gfx::StandardCursor::None);
- m_editor->did_complete_action();
-}
-
-void MoveTool::on_keydown(GUI::KeyEvent& event)
-{
- if (event.modifiers() != 0)
- return;
-
- auto* layer = m_editor->active_layer();
- if (!layer)
- return;
-
- auto new_location = layer->location();
-
- switch (event.key()) {
- case Key_Up:
- new_location.move_by(0, -1);
- break;
- case Key_Down:
- new_location.move_by(0, 1);
- break;
- case Key_Left:
- new_location.move_by(-1, 0);
- break;
- case Key_Right:
- new_location.move_by(1, 0);
- break;
- default:
- return;
- }
-
- layer->set_location(new_location);
- m_editor->layers_did_change();
-}
-
-void MoveTool::on_context_menu(Layer& layer, GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_context_menu->add_action(GUI::CommonActions::make_move_to_front_action(
- [this](auto&) {
- m_editor->image()->move_layer_to_front(*m_context_menu_layer);
- m_editor->layers_did_change();
- },
- m_editor));
- m_context_menu->add_action(GUI::CommonActions::make_move_to_back_action(
- [this](auto&) {
- m_editor->image()->move_layer_to_back(*m_context_menu_layer);
- m_editor->layers_did_change();
- },
- m_editor));
- m_context_menu->add_separator();
- m_context_menu->add_action(GUI::Action::create(
- "Delete layer", Gfx::Bitmap::load_from_file("/res/icons/16x16/delete.png"), [this](auto&) {
- m_editor->image()->remove_layer(*m_context_menu_layer);
- // FIXME: This should not be done imperatively here. Perhaps a Image::Client interface that ImageEditor can implement?
- if (m_editor->active_layer() == m_context_menu_layer)
- m_editor->set_active_layer(nullptr);
- m_editor->layers_did_change();
- },
- m_editor));
- }
- m_context_menu_layer = layer;
- m_context_menu->popup(event.screen_position());
-}
-
-}
diff --git a/Applications/PixelPaint/MoveTool.h b/Applications/PixelPaint/MoveTool.h
deleted file mode 100644
index a0c16e5282..0000000000
--- a/Applications/PixelPaint/MoveTool.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-
-namespace PixelPaint {
-
-class MoveTool final : public Tool {
-public:
- MoveTool();
- virtual ~MoveTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_keydown(GUI::KeyEvent&) override;
- virtual void on_context_menu(Layer&, GUI::ContextMenuEvent&) override;
-
-private:
- RefPtr<Layer> m_layer_being_moved;
- Gfx::IntPoint m_event_origin;
- Gfx::IntPoint m_layer_origin;
- RefPtr<GUI::Menu> m_context_menu;
- RefPtr<Layer> m_context_menu_layer;
-};
-
-}
diff --git a/Applications/PixelPaint/PaletteWidget.cpp b/Applications/PixelPaint/PaletteWidget.cpp
deleted file mode 100644
index 52620b4b31..0000000000
--- a/Applications/PixelPaint/PaletteWidget.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PaletteWidget.h"
-#include "ImageEditor.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/ColorPicker.h>
-#include <LibGfx/Palette.h>
-
-namespace PixelPaint {
-
-class ColorWidget : public GUI::Frame {
- C_OBJECT(ColorWidget);
-
-public:
- explicit ColorWidget(Color color, PaletteWidget& palette_widget)
- : m_palette_widget(palette_widget)
- , m_color(color)
- {
- }
-
- virtual ~ColorWidget() override
- {
- }
-
- virtual void mousedown_event(GUI::MouseEvent& event) override
- {
- if (event.modifiers() & KeyModifier::Mod_Ctrl && event.button() == GUI::MouseButton::Left) {
- auto dialog = GUI::ColorPicker::construct(m_color, window());
- if (dialog->exec() == GUI::Dialog::ExecOK) {
- m_color = dialog->color();
- auto pal = palette();
- pal.set_color(ColorRole::Background, m_color);
- set_palette(pal);
- update();
- }
- return;
- }
-
- if (event.button() == GUI::MouseButton::Left)
- m_palette_widget.set_primary_color(m_color);
- else if (event.button() == GUI::MouseButton::Right)
- m_palette_widget.set_secondary_color(m_color);
- }
-
-private:
- PaletteWidget& m_palette_widget;
- Color m_color;
-};
-
-PaletteWidget::PaletteWidget(ImageEditor& editor)
- : m_editor(editor)
-{
- set_frame_shape(Gfx::FrameShape::Panel);
- set_frame_shadow(Gfx::FrameShadow::Raised);
- set_frame_thickness(0);
- set_fill_with_background_color(true);
-
- set_fixed_height(34);
-
- m_secondary_color_widget = add<GUI::Frame>();
- m_secondary_color_widget->set_relative_rect({ 2, 2, 60, 31 });
- m_secondary_color_widget->set_fill_with_background_color(true);
- set_secondary_color(m_editor.secondary_color());
-
- m_primary_color_widget = add<GUI::Frame>();
- Gfx::IntRect rect { 0, 0, 38, 15 };
- rect.center_within(m_secondary_color_widget->relative_rect());
- m_primary_color_widget->set_relative_rect(rect);
- m_primary_color_widget->set_fill_with_background_color(true);
- set_primary_color(m_editor.primary_color());
-
- m_editor.on_primary_color_change = [this](Color color) {
- set_primary_color(color);
- };
-
- m_editor.on_secondary_color_change = [this](Color color) {
- set_secondary_color(color);
- };
-
- auto& color_container = add<GUI::Widget>();
- color_container.set_relative_rect(m_secondary_color_widget->relative_rect().right() + 2, 2, 500, 32);
- color_container.set_layout<GUI::VerticalBoxLayout>();
- color_container.layout()->set_spacing(1);
-
- auto& top_color_container = color_container.add<GUI::Widget>();
- top_color_container.set_layout<GUI::HorizontalBoxLayout>();
- top_color_container.layout()->set_spacing(1);
-
- auto& bottom_color_container = color_container.add<GUI::Widget>();
- bottom_color_container.set_layout<GUI::HorizontalBoxLayout>();
- bottom_color_container.layout()->set_spacing(1);
-
- auto add_color_widget = [&](GUI::Widget& container, Color color) {
- auto& color_widget = container.add<ColorWidget>(color, *this);
- color_widget.set_fill_with_background_color(true);
- auto pal = color_widget.palette();
- pal.set_color(ColorRole::Background, color);
- color_widget.set_palette(pal);
- };
-
- add_color_widget(top_color_container, Color::from_rgb(0x000000));
- add_color_widget(top_color_container, Color::from_rgb(0x808080));
- add_color_widget(top_color_container, Color::from_rgb(0x800000));
- add_color_widget(top_color_container, Color::from_rgb(0x808000));
- add_color_widget(top_color_container, Color::from_rgb(0x008000));
- add_color_widget(top_color_container, Color::from_rgb(0x008080));
- add_color_widget(top_color_container, Color::from_rgb(0x000080));
- add_color_widget(top_color_container, Color::from_rgb(0x800080));
- add_color_widget(top_color_container, Color::from_rgb(0x808040));
- add_color_widget(top_color_container, Color::from_rgb(0x004040));
- add_color_widget(top_color_container, Color::from_rgb(0x0080ff));
- add_color_widget(top_color_container, Color::from_rgb(0x004080));
- add_color_widget(top_color_container, Color::from_rgb(0x8000ff));
- add_color_widget(top_color_container, Color::from_rgb(0x804000));
-
- add_color_widget(bottom_color_container, Color::from_rgb(0xffffff));
- add_color_widget(bottom_color_container, Color::from_rgb(0xc0c0c0));
- add_color_widget(bottom_color_container, Color::from_rgb(0xff0000));
- add_color_widget(bottom_color_container, Color::from_rgb(0xffff00));
- add_color_widget(bottom_color_container, Color::from_rgb(0x00ff00));
- add_color_widget(bottom_color_container, Color::from_rgb(0x00ffff));
- add_color_widget(bottom_color_container, Color::from_rgb(0x0000ff));
- add_color_widget(bottom_color_container, Color::from_rgb(0xff00ff));
- add_color_widget(bottom_color_container, Color::from_rgb(0xffff80));
- add_color_widget(bottom_color_container, Color::from_rgb(0x00ff80));
- add_color_widget(bottom_color_container, Color::from_rgb(0x80ffff));
- add_color_widget(bottom_color_container, Color::from_rgb(0x8080ff));
- add_color_widget(bottom_color_container, Color::from_rgb(0xff0080));
- add_color_widget(bottom_color_container, Color::from_rgb(0xff8040));
-}
-
-PaletteWidget::~PaletteWidget()
-{
-}
-
-void PaletteWidget::set_primary_color(Color color)
-{
- m_editor.set_primary_color(color);
- auto pal = m_primary_color_widget->palette();
- pal.set_color(ColorRole::Background, color);
- m_primary_color_widget->set_palette(pal);
- m_primary_color_widget->update();
-}
-
-void PaletteWidget::set_secondary_color(Color color)
-{
- m_editor.set_secondary_color(color);
- auto pal = m_secondary_color_widget->palette();
- pal.set_color(ColorRole::Background, color);
- m_secondary_color_widget->set_palette(pal);
- m_secondary_color_widget->update();
-}
-
-}
diff --git a/Applications/PixelPaint/PaletteWidget.h b/Applications/PixelPaint/PaletteWidget.h
deleted file mode 100644
index 02c843f038..0000000000
--- a/Applications/PixelPaint/PaletteWidget.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-namespace PixelPaint {
-
-class ImageEditor;
-
-class PaletteWidget final : public GUI::Frame {
- C_OBJECT(PaletteWidget);
-
-public:
- virtual ~PaletteWidget() override;
-
- void set_primary_color(Color);
- void set_secondary_color(Color);
-
-private:
- explicit PaletteWidget(ImageEditor&);
-
- ImageEditor& m_editor;
- RefPtr<GUI::Frame> m_primary_color_widget;
- RefPtr<GUI::Frame> m_secondary_color_widget;
-};
-
-}
diff --git a/Applications/PixelPaint/PenTool.cpp b/Applications/PixelPaint/PenTool.cpp
deleted file mode 100644
index 579231edf7..0000000000
--- a/Applications/PixelPaint/PenTool.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PenTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Slider.h>
-
-namespace PixelPaint {
-
-PenTool::PenTool()
-{
-}
-
-PenTool::~PenTool()
-{
-}
-
-void PenTool::on_mousedown(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
-
- GUI::Painter painter(layer.bitmap());
- painter.draw_line(event.position(), event.position(), m_editor->color_for(event), m_thickness);
- layer.did_modify_bitmap(*m_editor->image());
- m_last_drawing_event_position = event.position();
-}
-
-void PenTool::on_mouseup(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() == GUI::MouseButton::Left || event.button() == GUI::MouseButton::Right) {
- m_last_drawing_event_position = { -1, -1 };
- m_editor->did_complete_action();
- }
-}
-
-void PenTool::on_mousemove(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (!(event.buttons() & GUI::MouseButton::Left || event.buttons() & GUI::MouseButton::Right))
- return;
- GUI::Painter painter(layer.bitmap());
-
- if (m_last_drawing_event_position != Gfx::IntPoint(-1, -1))
- painter.draw_line(m_last_drawing_event_position, event.position(), m_editor->color_for(event), m_thickness);
- else
- painter.draw_line(event.position(), event.position(), m_editor->color_for(event), m_thickness);
- layer.did_modify_bitmap(*m_editor->image());
-
- m_last_drawing_event_position = event.position();
-}
-
-void PenTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_thickness_actions.set_exclusive(true);
- auto insert_action = [&](int size, bool checked = false) {
- auto action = GUI::Action::create_checkable(String::number(size), [this, size](auto&) {
- m_thickness = size;
- });
- action->set_checked(checked);
- m_thickness_actions.add_action(*action);
- m_context_menu->add_action(move(action));
- };
- insert_action(1, true);
- insert_action(2);
- insert_action(3);
- insert_action(4);
- }
- m_context_menu->popup(event.screen_position());
-}
-
-GUI::Widget* PenTool::get_properties_widget()
-{
- if (!m_properties_widget) {
- m_properties_widget = GUI::Widget::construct();
- m_properties_widget->set_layout<GUI::VerticalBoxLayout>();
-
- auto& thickness_container = m_properties_widget->add<GUI::Widget>();
- thickness_container.set_fixed_height(20);
- thickness_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& thickness_label = thickness_container.add<GUI::Label>("Thickness:");
- thickness_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- thickness_label.set_fixed_size(80, 20);
-
- auto& thickness_slider = thickness_container.add<GUI::HorizontalSlider>();
- thickness_slider.set_fixed_height(20);
- thickness_slider.set_range(1, 20);
- thickness_slider.set_value(m_thickness);
- thickness_slider.on_change = [this](int value) {
- m_thickness = value;
- };
- }
-
- return m_properties_widget.ptr();
-}
-
-}
diff --git a/Applications/PixelPaint/PenTool.h b/Applications/PixelPaint/PenTool.h
deleted file mode 100644
index 137e58251e..0000000000
--- a/Applications/PixelPaint/PenTool.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibGUI/ActionGroup.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class PenTool final : public Tool {
-public:
- PenTool();
- virtual ~PenTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
- virtual GUI::Widget* get_properties_widget() override;
-
-private:
- Gfx::IntPoint m_last_drawing_event_position { -1, -1 };
- RefPtr<GUI::Menu> m_context_menu;
- RefPtr<GUI::Widget> m_properties_widget;
- int m_thickness { 1 };
- GUI::ActionGroup m_thickness_actions;
-};
-
-}
diff --git a/Applications/PixelPaint/PickerTool.cpp b/Applications/PixelPaint/PickerTool.cpp
deleted file mode 100644
index 86a7acf961..0000000000
--- a/Applications/PixelPaint/PickerTool.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PickerTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGfx/Bitmap.h>
-
-namespace PixelPaint {
-
-PickerTool::PickerTool()
-{
-}
-
-PickerTool::~PickerTool()
-{
-}
-
-void PickerTool::on_mousedown(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (!layer.rect().contains(event.position()))
- return;
- auto color = layer.bitmap().get_pixel(event.position());
- if (event.button() == GUI::MouseButton::Left)
- m_editor->set_primary_color(color);
- else if (event.button() == GUI::MouseButton::Right)
- m_editor->set_secondary_color(color);
-}
-
-}
diff --git a/Applications/PixelPaint/PickerTool.h b/Applications/PixelPaint/PickerTool.h
deleted file mode 100644
index 163a0aeeee..0000000000
--- a/Applications/PixelPaint/PickerTool.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-
-namespace PixelPaint {
-
-class PickerTool final : public Tool {
-public:
- PickerTool();
- virtual ~PickerTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
-};
-
-}
diff --git a/Applications/PixelPaint/RectangleTool.cpp b/Applications/PixelPaint/RectangleTool.cpp
deleted file mode 100644
index a5b023f18b..0000000000
--- a/Applications/PixelPaint/RectangleTool.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "RectangleTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Rect.h>
-#include <math.h>
-
-namespace PixelPaint {
-
-RectangleTool::RectangleTool()
-{
-}
-
-RectangleTool::~RectangleTool()
-{
-}
-
-void RectangleTool::draw_using(GUI::Painter& painter, const Gfx::IntRect& rect)
-{
- switch (m_mode) {
- case Mode::Fill:
- painter.fill_rect(rect, m_editor->color_for(m_drawing_button));
- break;
- case Mode::Outline:
- painter.draw_rect(rect, m_editor->color_for(m_drawing_button));
- break;
- case Mode::Gradient:
- painter.fill_rect_with_gradient(rect, m_editor->primary_color(), m_editor->secondary_color());
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void RectangleTool::on_mousedown(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() != GUI::MouseButton::Left && event.button() != GUI::MouseButton::Right)
- return;
-
- if (m_drawing_button != GUI::MouseButton::None)
- return;
-
- m_drawing_button = event.button();
- m_rectangle_start_position = event.position();
- m_rectangle_end_position = event.position();
- m_editor->update();
-}
-
-void RectangleTool::on_mouseup(Layer& layer, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (event.button() == m_drawing_button) {
- GUI::Painter painter(layer.bitmap());
- auto rect = Gfx::IntRect::from_two_points(m_rectangle_start_position, m_rectangle_end_position);
- draw_using(painter, rect);
- m_drawing_button = GUI::MouseButton::None;
- layer.did_modify_bitmap(*m_editor->image());
- m_editor->did_complete_action();
- }
-}
-
-void RectangleTool::on_mousemove(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- m_rectangle_end_position = event.position();
- m_editor->update();
-}
-
-void RectangleTool::on_second_paint(const Layer& layer, GUI::PaintEvent& event)
-{
- if (m_drawing_button == GUI::MouseButton::None)
- return;
-
- GUI::Painter painter(*m_editor);
- painter.add_clip_rect(event.rect());
- auto rect = Gfx::IntRect::from_two_points(
- m_editor->layer_position_to_editor_position(layer, m_rectangle_start_position).to_type<int>(),
- m_editor->layer_position_to_editor_position(layer, m_rectangle_end_position).to_type<int>());
- draw_using(painter, rect);
-}
-
-void RectangleTool::on_keydown(GUI::KeyEvent& event)
-{
- if (event.key() == Key_Escape && m_drawing_button != GUI::MouseButton::None) {
- m_drawing_button = GUI::MouseButton::None;
- m_editor->update();
- event.accept();
- }
-}
-
-void RectangleTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_context_menu->add_action(GUI::Action::create("Fill", [this](auto&) {
- m_mode = Mode::Fill;
- }));
- m_context_menu->add_action(GUI::Action::create("Outline", [this](auto&) {
- m_mode = Mode::Outline;
- }));
- m_context_menu->add_action(GUI::Action::create("Gradient", [this](auto&) {
- m_mode = Mode::Gradient;
- }));
- }
- m_context_menu->popup(event.screen_position());
-}
-
-}
diff --git a/Applications/PixelPaint/RectangleTool.h b/Applications/PixelPaint/RectangleTool.h
deleted file mode 100644
index f7d8c53273..0000000000
--- a/Applications/PixelPaint/RectangleTool.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibGUI/Forward.h>
-#include <LibGfx/Point.h>
-
-namespace PixelPaint {
-
-class RectangleTool final : public Tool {
-public:
- RectangleTool();
- virtual ~RectangleTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
- virtual void on_second_paint(const Layer&, GUI::PaintEvent&) override;
- virtual void on_keydown(GUI::KeyEvent&) override;
-
-private:
- enum class Mode {
- Outline,
- Fill,
- Gradient,
- };
-
- void draw_using(GUI::Painter&, const Gfx::IntRect&);
-
- GUI::MouseButton m_drawing_button { GUI::MouseButton::None };
- Gfx::IntPoint m_rectangle_start_position;
- Gfx::IntPoint m_rectangle_end_position;
- RefPtr<GUI::Menu> m_context_menu;
- Mode m_mode { Mode::Outline };
-};
-
-}
diff --git a/Applications/PixelPaint/SprayTool.cpp b/Applications/PixelPaint/SprayTool.cpp
deleted file mode 100644
index 9997c29674..0000000000
--- a/Applications/PixelPaint/SprayTool.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SprayTool.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include <AK/Queue.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Slider.h>
-#include <LibGfx/Bitmap.h>
-#include <math.h>
-#include <stdio.h>
-
-namespace PixelPaint {
-
-SprayTool::SprayTool()
-{
- m_timer = Core::Timer::construct();
- m_timer->on_timeout = [&]() {
- paint_it();
- };
- m_timer->set_interval(200);
-}
-
-SprayTool::~SprayTool()
-{
-}
-
-static double nrand()
-{
- return double(rand()) / double(RAND_MAX);
-}
-
-void SprayTool::paint_it()
-{
- auto* layer = m_editor->active_layer();
- if (!layer)
- return;
-
- auto& bitmap = layer->bitmap();
- GUI::Painter painter(bitmap);
- ASSERT(bitmap.bpp() == 32);
- m_editor->update();
- const double minimal_radius = 2;
- const double base_radius = minimal_radius * m_thickness;
- for (int i = 0; i < M_PI * base_radius * base_radius * (m_density / 100.0f); i++) {
- double radius = base_radius * nrand();
- double angle = 2 * M_PI * nrand();
- const int xpos = m_last_pos.x() + radius * cos(angle);
- const int ypos = m_last_pos.y() - radius * sin(angle);
- if (xpos < 0 || xpos >= bitmap.width())
- continue;
- if (ypos < 0 || ypos >= bitmap.height())
- continue;
- bitmap.set_pixel<Gfx::StorageFormat::RGBA32>(xpos, ypos, m_color);
- }
-
- layer->did_modify_bitmap(*m_editor->image());
-}
-
-void SprayTool::on_mousedown(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- m_color = m_editor->color_for(event);
- m_last_pos = event.position();
- m_timer->start();
- paint_it();
-}
-
-void SprayTool::on_mousemove(Layer&, GUI::MouseEvent& event, GUI::MouseEvent&)
-{
- m_last_pos = event.position();
- if (m_timer->is_active()) {
- paint_it();
- m_timer->restart(m_timer->interval());
- }
-}
-
-void SprayTool::on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent&)
-{
- if (m_timer->is_active()) {
- m_timer->stop();
- m_editor->did_complete_action();
- }
-}
-
-void SprayTool::on_tool_button_contextmenu(GUI::ContextMenuEvent& event)
-{
- if (!m_context_menu) {
- m_context_menu = GUI::Menu::construct();
- m_thickness_actions.set_exclusive(true);
- auto insert_action = [&](int size, bool checked = false) {
- auto action = GUI::Action::create_checkable(String::number(size), [this, size](auto&) {
- m_thickness = size;
- });
- action->set_checked(checked);
- m_thickness_actions.add_action(*action);
- m_context_menu->add_action(move(action));
- };
- insert_action(1, true);
- insert_action(2);
- insert_action(3);
- insert_action(4);
- }
- m_context_menu->popup(event.screen_position());
-}
-
-GUI::Widget* SprayTool::get_properties_widget()
-{
- if (!m_properties_widget) {
- m_properties_widget = GUI::Widget::construct();
- m_properties_widget->set_layout<GUI::VerticalBoxLayout>();
-
- auto& thickness_container = m_properties_widget->add<GUI::Widget>();
- thickness_container.set_fixed_height(20);
- thickness_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& thickness_label = thickness_container.add<GUI::Label>("Thickness:");
- thickness_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- thickness_label.set_fixed_size(80, 20);
-
- auto& thickness_slider = thickness_container.add<GUI::HorizontalSlider>();
- thickness_slider.set_fixed_height(20);
- thickness_slider.set_range(1, 20);
- thickness_slider.set_value(m_thickness);
- thickness_slider.on_change = [this](int value) {
- m_thickness = value;
- };
-
- auto& density_container = m_properties_widget->add<GUI::Widget>();
- density_container.set_fixed_height(20);
- density_container.set_layout<GUI::HorizontalBoxLayout>();
-
- auto& density_label = density_container.add<GUI::Label>("Density:");
- density_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- density_label.set_fixed_size(80, 20);
-
- auto& density_slider = density_container.add<GUI::HorizontalSlider>();
- density_slider.set_fixed_height(30);
- density_slider.set_range(1, 100);
- density_slider.set_value(m_density);
- density_slider.on_change = [this](int value) {
- m_density = value;
- };
- }
-
- return m_properties_widget.ptr();
-}
-
-}
diff --git a/Applications/PixelPaint/SprayTool.h b/Applications/PixelPaint/SprayTool.h
deleted file mode 100644
index a3e55efd52..0000000000
--- a/Applications/PixelPaint/SprayTool.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Tool.h"
-#include <LibCore/Timer.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Painter.h>
-
-namespace PixelPaint {
-
-class SprayTool final : public Tool {
-public:
- SprayTool();
- virtual ~SprayTool() override;
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mouseup(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_mousemove(Layer&, GUI::MouseEvent& layer_event, GUI::MouseEvent& image_event) override;
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) override;
- virtual GUI::Widget* get_properties_widget() override;
-
-private:
- void paint_it();
-
- RefPtr<GUI::Widget> m_properties_widget;
- RefPtr<Core::Timer> m_timer;
- Gfx::IntPoint m_last_pos;
- Color m_color;
- RefPtr<GUI::Menu> m_context_menu;
- GUI::ActionGroup m_thickness_actions;
- int m_thickness { 10 };
- int m_density { 40 };
-};
-
-}
diff --git a/Applications/PixelPaint/Tool.cpp b/Applications/PixelPaint/Tool.cpp
deleted file mode 100644
index 846e017410..0000000000
--- a/Applications/PixelPaint/Tool.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Tool.h"
-#include "ImageEditor.h"
-#include <LibGUI/Action.h>
-
-namespace PixelPaint {
-
-Tool::Tool()
-{
-}
-
-Tool::~Tool()
-{
-}
-
-void Tool::setup(ImageEditor& editor)
-{
- m_editor = editor;
-}
-
-void Tool::set_action(GUI::Action* action)
-{
- m_action = action;
-}
-
-}
diff --git a/Applications/PixelPaint/Tool.h b/Applications/PixelPaint/Tool.h
deleted file mode 100644
index e7deb5f1cb..0000000000
--- a/Applications/PixelPaint/Tool.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Event.h>
-#include <LibGUI/Forward.h>
-
-namespace PixelPaint {
-
-class ImageEditor;
-class Layer;
-
-class Tool {
-public:
- virtual ~Tool();
-
- virtual void on_mousedown(Layer&, GUI::MouseEvent&, GUI::MouseEvent&) { }
- virtual void on_mousemove(Layer&, GUI::MouseEvent&, GUI::MouseEvent&) { }
- virtual void on_mouseup(Layer&, GUI::MouseEvent&, GUI::MouseEvent&) { }
- virtual void on_context_menu(Layer&, GUI::ContextMenuEvent&) { }
- virtual void on_tool_button_contextmenu(GUI::ContextMenuEvent&) { }
- virtual void on_second_paint(const Layer&, GUI::PaintEvent&) { }
- virtual void on_keydown(GUI::KeyEvent&) { }
- virtual void on_keyup(GUI::KeyEvent&) { }
- virtual GUI::Widget* get_properties_widget() { return nullptr; }
-
- void clear() { m_editor = nullptr; }
- void setup(ImageEditor&);
-
- GUI::Action* action() { return m_action; }
- void set_action(GUI::Action*);
-
-protected:
- Tool();
- WeakPtr<ImageEditor> m_editor;
- RefPtr<GUI::Action> m_action;
-};
-
-}
diff --git a/Applications/PixelPaint/ToolPropertiesWidget.cpp b/Applications/PixelPaint/ToolPropertiesWidget.cpp
deleted file mode 100644
index a27103d3e7..0000000000
--- a/Applications/PixelPaint/ToolPropertiesWidget.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ToolPropertiesWidget.h"
-#include "Tool.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/GroupBox.h>
-
-namespace PixelPaint {
-
-ToolPropertiesWidget::ToolPropertiesWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
-
- m_group_box = add<GUI::GroupBox>("Tool properties");
- auto& layout = m_group_box->set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins({ 10, 20, 10, 10 });
-}
-
-void ToolPropertiesWidget::set_active_tool(Tool* tool)
-{
- if (tool == m_active_tool)
- return;
-
- if (m_active_tool_widget != nullptr)
- m_group_box->remove_child(*m_active_tool_widget);
-
- m_active_tool = tool;
- m_active_tool_widget = tool->get_properties_widget();
- if (m_active_tool_widget != nullptr)
- m_group_box->add_child(*m_active_tool_widget);
-}
-
-ToolPropertiesWidget::~ToolPropertiesWidget()
-{
-}
-
-}
diff --git a/Applications/PixelPaint/ToolPropertiesWidget.h b/Applications/PixelPaint/ToolPropertiesWidget.h
deleted file mode 100644
index 41c1675cfa..0000000000
--- a/Applications/PixelPaint/ToolPropertiesWidget.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2020, Ben Jilks <benjyjilks@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/RefPtr.h>
-#include <LibGUI/Forward.h>
-#include <LibGUI/Widget.h>
-
-namespace PixelPaint {
-
-class Tool;
-
-class ToolPropertiesWidget final : public GUI::Widget {
- C_OBJECT(ToolPropertiesWidget);
-
-public:
- virtual ~ToolPropertiesWidget() override;
-
- void set_active_tool(Tool*);
-
-private:
- ToolPropertiesWidget();
-
- RefPtr<GUI::GroupBox> m_group_box;
-
- Tool* m_active_tool { nullptr };
- GUI::Widget* m_active_tool_widget { nullptr };
-};
-
-}
diff --git a/Applications/PixelPaint/ToolboxWidget.cpp b/Applications/PixelPaint/ToolboxWidget.cpp
deleted file mode 100644
index c746901887..0000000000
--- a/Applications/PixelPaint/ToolboxWidget.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ToolboxWidget.h"
-#include "BrushTool.h"
-#include "BucketTool.h"
-#include "EllipseTool.h"
-#include "EraseTool.h"
-#include "LineTool.h"
-#include "MoveTool.h"
-#include "PenTool.h"
-#include "PickerTool.h"
-#include "RectangleTool.h"
-#include "SprayTool.h"
-#include <AK/StringBuilder.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Window.h>
-
-namespace PixelPaint {
-
-class ToolButton final : public GUI::Button {
- C_OBJECT(ToolButton)
-public:
- ToolButton(ToolboxWidget& toolbox, const String& name, const GUI::Shortcut& shortcut, OwnPtr<Tool> tool)
- : m_toolbox(toolbox)
- , m_tool(move(tool))
- {
- StringBuilder builder;
- builder.append(name);
- builder.append(" (");
- builder.append(shortcut.to_string());
- builder.append(")");
- set_tooltip(builder.to_string());
-
- m_action = GUI::Action::create_checkable(
- name, shortcut, [this](auto& action) {
- if (action.is_checked())
- m_toolbox.on_tool_selection(m_tool);
- else
- m_toolbox.on_tool_selection(nullptr);
- },
- toolbox.window());
-
- m_tool->set_action(m_action);
- set_action(*m_action);
- m_toolbox.m_action_group.add_action(*m_action);
- }
-
- const Tool& tool() const { return *m_tool; }
- Tool& tool() { return *m_tool; }
-
- virtual bool is_uncheckable() const override { return false; }
-
- virtual void context_menu_event(GUI::ContextMenuEvent& event) override
- {
- m_action->activate();
- m_tool->on_tool_button_contextmenu(event);
- }
-
-private:
- ToolboxWidget& m_toolbox;
- OwnPtr<Tool> m_tool;
- RefPtr<GUI::Action> m_action;
-};
-
-ToolboxWidget::ToolboxWidget()
-{
- set_fill_with_background_color(true);
-
- set_frame_thickness(1);
- set_frame_shape(Gfx::FrameShape::Panel);
- set_frame_shadow(Gfx::FrameShadow::Raised);
-
- set_fixed_width(48);
-
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
-
- m_action_group.set_exclusive(true);
- m_action_group.set_unchecking_allowed(false);
-
- deferred_invoke([this](auto&) {
- setup_tools();
- });
-}
-
-ToolboxWidget::~ToolboxWidget()
-{
-}
-
-void ToolboxWidget::setup_tools()
-{
- auto add_tool = [&](const StringView& name, const StringView& icon_name, const GUI::Shortcut& shortcut, NonnullOwnPtr<Tool> tool) -> ToolButton& {
- m_tools.append(tool.ptr());
- auto& button = add<ToolButton>(*this, name, shortcut, move(tool));
- button.set_focus_policy(GUI::FocusPolicy::TabFocus);
- button.set_fixed_height(32);
- button.set_checkable(true);
- button.set_icon(Gfx::Bitmap::load_from_file(String::formatted("/res/icons/pixelpaint/{}.png", icon_name)));
- return button;
- };
-
- add_tool("Move", "move", { 0, Key_M }, make<MoveTool>());
- add_tool("Pen", "pen", { 0, Key_N }, make<PenTool>());
- add_tool("Brush", "brush", { 0, Key_P }, make<BrushTool>());
- add_tool("Bucket Fill", "bucket", { Mod_Shift, Key_B }, make<BucketTool>());
- add_tool("Spray", "spray", { Mod_Shift, Key_S }, make<SprayTool>());
- add_tool("Color Picker", "picker", { 0, Key_O }, make<PickerTool>());
- add_tool("Erase", "eraser", { Mod_Shift, Key_E }, make<EraseTool>());
- add_tool("Line", "line", { Mod_Ctrl | Mod_Shift, Key_L }, make<LineTool>());
- add_tool("Rectangle", "rectangle", { Mod_Ctrl | Mod_Shift, Key_R }, make<RectangleTool>());
- add_tool("Ellipse", "circle", { Mod_Ctrl | Mod_Shift, Key_E }, make<EllipseTool>());
-}
-
-}
diff --git a/Applications/PixelPaint/ToolboxWidget.h b/Applications/PixelPaint/ToolboxWidget.h
deleted file mode 100644
index 23794179f6..0000000000
--- a/Applications/PixelPaint/ToolboxWidget.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Frame.h>
-
-namespace PixelPaint {
-
-class Tool;
-
-class ToolboxWidget final : public GUI::Frame {
- C_OBJECT(ToolboxWidget)
-public:
- virtual ~ToolboxWidget() override;
-
- Function<void(Tool*)> on_tool_selection;
-
- template<typename Callback>
- void for_each_tool(Callback callback)
- {
- for (auto& tool : m_tools)
- callback(*tool);
- }
-
-private:
- friend class ToolButton;
-
- void setup_tools();
-
- explicit ToolboxWidget();
- GUI::ActionGroup m_action_group;
- Vector<Tool*> m_tools;
-};
-
-}
diff --git a/Applications/PixelPaint/main.cpp b/Applications/PixelPaint/main.cpp
deleted file mode 100644
index 02164a52ce..0000000000
--- a/Applications/PixelPaint/main.cpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CreateNewImageDialog.h"
-#include "CreateNewLayerDialog.h"
-#include "FilterParams.h"
-#include "Image.h"
-#include "ImageEditor.h"
-#include "Layer.h"
-#include "LayerListWidget.h"
-#include "LayerPropertiesWidget.h"
-#include "PaletteWidget.h"
-#include "Tool.h"
-#include "ToolPropertiesWidget.h"
-#include "ToolboxWidget.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Matrix4x4.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio thread shared_buffer accept rpath unix wpath cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread shared_buffer accept rpath wpath cpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-pixel-paint");
-
- auto window = GUI::Window::construct();
- window->set_title("PixelPaint");
- window->resize(950, 570);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto& horizontal_container = window->set_main_widget<GUI::Widget>();
- horizontal_container.set_layout<GUI::HorizontalBoxLayout>();
- horizontal_container.layout()->set_spacing(0);
-
- auto& toolbox = horizontal_container.add<PixelPaint::ToolboxWidget>();
-
- auto& vertical_container = horizontal_container.add<GUI::Widget>();
- vertical_container.set_layout<GUI::VerticalBoxLayout>();
- vertical_container.layout()->set_spacing(0);
-
- auto& image_editor = vertical_container.add<PixelPaint::ImageEditor>();
- image_editor.set_focus(true);
-
- vertical_container.add<PixelPaint::PaletteWidget>(image_editor);
-
- auto& right_panel = horizontal_container.add<GUI::Widget>();
- right_panel.set_fill_with_background_color(true);
- right_panel.set_fixed_width(230);
- right_panel.set_layout<GUI::VerticalBoxLayout>();
-
- auto& layer_list_widget = right_panel.add<PixelPaint::LayerListWidget>();
-
- auto& layer_properties_widget = right_panel.add<PixelPaint::LayerPropertiesWidget>();
-
- auto& tool_properties_widget = right_panel.add<PixelPaint::ToolPropertiesWidget>();
-
- toolbox.on_tool_selection = [&](auto* tool) {
- image_editor.set_active_tool(tool);
- tool_properties_widget.set_active_tool(tool);
- };
-
- window->show();
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("PixelPaint");
-
- app_menu.add_action(
- GUI::Action::create(
- "New", [&](auto&) {
- auto dialog = PixelPaint::CreateNewImageDialog::construct(window);
- if (dialog->exec() == GUI::Dialog::ExecOK) {
- auto image = PixelPaint::Image::create_with_size(dialog->image_size());
- auto bg_layer = PixelPaint::Layer::create_with_size(*image, image->size(), "Background");
- image->add_layer(*bg_layer);
- bg_layer->bitmap().fill(Color::White);
-
- image_editor.set_image(image);
- layer_list_widget.set_image(image);
- image_editor.set_active_layer(bg_layer);
- }
- },
- window));
- app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(window);
-
- if (!open_path.has_value())
- return;
-
- auto image = PixelPaint::Image::create_from_file(open_path.value());
- image_editor.set_image(image);
- layer_list_widget.set_image(image);
- }));
- app_menu.add_action(GUI::CommonActions::make_save_as_action([&](auto&) {
- if (!image_editor.image())
- return;
-
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "pp");
-
- if (!save_path.has_value())
- return;
-
- image_editor.image()->save(save_path.value());
- }));
- auto& export_submenu = app_menu.add_submenu("Export");
- export_submenu.add_action(
- GUI::Action::create(
- "As BMP", [&](auto&) {
- if (!image_editor.image())
- return;
-
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "bmp");
-
- if (!save_path.has_value())
- return;
-
- image_editor.image()->export_bmp(save_path.value());
- },
- window));
-
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& edit_menu = menubar->add_menu("Edit");
- auto paste_action = GUI::CommonActions::make_paste_action([&](auto&) {
- ASSERT(image_editor.image());
- auto bitmap = GUI::Clipboard::the().bitmap();
- if (!bitmap)
- return;
-
- auto layer = PixelPaint::Layer::create_with_bitmap(*image_editor.image(), *bitmap, "Pasted layer");
- image_editor.image()->add_layer(layer.release_nonnull());
- });
- GUI::Clipboard::the().on_change = [&](auto& mime_type) {
- paste_action->set_enabled(mime_type == "image/x-serenityos");
- };
- paste_action->set_enabled(GUI::Clipboard::the().mime_type() == "image/x-serenityos");
-
- edit_menu.add_action(paste_action);
-
- auto undo_action = GUI::CommonActions::make_undo_action([&](auto&) {
- ASSERT(image_editor.image());
- image_editor.undo();
- });
- edit_menu.add_action(undo_action);
-
- auto redo_action = GUI::CommonActions::make_redo_action([&](auto&) {
- ASSERT(image_editor.image());
- image_editor.redo();
- });
- edit_menu.add_action(redo_action);
-
- auto& tool_menu = menubar->add_menu("Tool");
- toolbox.for_each_tool([&](auto& tool) {
- if (tool.action())
- tool_menu.add_action(*tool.action());
- return IterationDecision::Continue;
- });
-
- auto& layer_menu = menubar->add_menu("Layer");
- layer_menu.add_action(GUI::Action::create(
- "Create new layer...", { Mod_Ctrl | Mod_Shift, Key_N }, [&](auto&) {
- auto dialog = PixelPaint::CreateNewLayerDialog::construct(image_editor.image()->size(), window);
- if (dialog->exec() == GUI::Dialog::ExecOK) {
- auto layer = PixelPaint::Layer::create_with_size(*image_editor.image(), dialog->layer_size(), dialog->layer_name());
- if (!layer) {
- GUI::MessageBox::show_error(window, String::formatted("Unable to create layer with size {}", dialog->size().to_string()));
- return;
- }
- image_editor.image()->add_layer(layer.release_nonnull());
- image_editor.layers_did_change();
- }
- },
- window));
-
- layer_menu.add_separator();
- layer_menu.add_action(GUI::Action::create(
- "Select previous layer", { 0, Key_PageUp }, [&](auto&) {
- layer_list_widget.move_selection(1);
- },
- window));
- layer_menu.add_action(GUI::Action::create(
- "Select next layer", { 0, Key_PageDown }, [&](auto&) {
- layer_list_widget.move_selection(-1);
- },
- window));
- layer_menu.add_action(GUI::Action::create(
- "Select top layer", { 0, Key_Home }, [&](auto&) {
- layer_list_widget.select_top_layer();
- },
- window));
- layer_menu.add_action(GUI::Action::create(
- "Select bottom layer", { 0, Key_End }, [&](auto&) {
- layer_list_widget.select_bottom_layer();
- },
- window));
- layer_menu.add_separator();
- layer_menu.add_action(GUI::Action::create(
- "Move active layer up", { Mod_Ctrl, Key_PageUp }, [&](auto&) {
- auto active_layer = image_editor.active_layer();
- if (!active_layer)
- return;
- image_editor.image()->move_layer_up(*active_layer);
- },
- window));
- layer_menu.add_action(GUI::Action::create(
- "Move active layer down", { Mod_Ctrl, Key_PageDown }, [&](auto&) {
- auto active_layer = image_editor.active_layer();
- if (!active_layer)
- return;
- image_editor.image()->move_layer_down(*active_layer);
- },
- window));
- layer_menu.add_separator();
- layer_menu.add_action(GUI::Action::create(
- "Remove active layer", { Mod_Ctrl, Key_D }, [&](auto&) {
- auto active_layer = image_editor.active_layer();
- if (!active_layer)
- return;
- image_editor.image()->remove_layer(*active_layer);
- image_editor.set_active_layer(nullptr);
- },
- window));
-
- auto& filter_menu = menubar->add_menu("Filter");
- auto& spatial_filters_menu = filter_menu.add_submenu("Spatial");
-
- auto& edge_detect_submenu = spatial_filters_menu.add_submenu("Edge Detect");
- edge_detect_submenu.add_action(GUI::Action::create("Laplacian (cardinal)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::LaplacianFilter filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(false)) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- edge_detect_submenu.add_action(GUI::Action::create("Laplacian (diagonal)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::LaplacianFilter filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(true)) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- auto& blur_submenu = spatial_filters_menu.add_submenu("Blur and Sharpen");
- blur_submenu.add_action(GUI::Action::create("Gaussian Blur (3x3)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::SpatialGaussianBlurFilter<3> filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<3>>::get()) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- blur_submenu.add_action(GUI::Action::create("Gaussian Blur (5x5)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::SpatialGaussianBlurFilter<5> filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<5>>::get()) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- blur_submenu.add_action(GUI::Action::create("Box Blur (3x3)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::BoxBlurFilter<3> filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<3>>::get()) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- blur_submenu.add_action(GUI::Action::create("Box Blur (5x5)", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::BoxBlurFilter<5> filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<5>>::get()) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
- blur_submenu.add_action(GUI::Action::create("Sharpen", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::SharpenFilter filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::SharpenFilter>::get()) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
-
- spatial_filters_menu.add_separator();
- spatial_filters_menu.add_action(GUI::Action::create("Generic 5x5 Convolution", [&](auto&) {
- if (auto* layer = image_editor.active_layer()) {
- Gfx::GenericConvolutionFilter<5> filter;
- if (auto parameters = PixelPaint::FilterParameters<Gfx::GenericConvolutionFilter<5>>::get(window)) {
- filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
- image_editor.did_complete_action();
- }
- }
- }));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("PixelPaint", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- image_editor.on_active_layer_change = [&](auto* layer) {
- layer_list_widget.set_selected_layer(layer);
- layer_properties_widget.set_layer(layer);
- };
-
- auto image = PixelPaint::Image::create_with_size({ 640, 480 });
-
- auto bg_layer = PixelPaint::Layer::create_with_size(*image, { 640, 480 }, "Background");
- image->add_layer(*bg_layer);
- bg_layer->bitmap().fill(Color::White);
-
- auto fg_layer1 = PixelPaint::Layer::create_with_size(*image, { 200, 200 }, "FG Layer 1");
- fg_layer1->set_location({ 50, 50 });
- image->add_layer(*fg_layer1);
- fg_layer1->bitmap().fill(Color::Yellow);
-
- auto fg_layer2 = PixelPaint::Layer::create_with_size(*image, { 100, 100 }, "FG Layer 2");
- fg_layer2->set_location({ 300, 300 });
- image->add_layer(*fg_layer2);
- fg_layer2->bitmap().fill(Color::Blue);
-
- layer_list_widget.on_layer_select = [&](auto* layer) {
- image_editor.set_active_layer(layer);
- };
-
- layer_list_widget.set_image(image);
-
- image_editor.set_image(image);
- image_editor.set_active_layer(bg_layer);
-
- return app->exec();
-}
diff --git a/Applications/QuickShow/CMakeLists.txt b/Applications/QuickShow/CMakeLists.txt
deleted file mode 100644
index 8d2b46e217..0000000000
--- a/Applications/QuickShow/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- main.cpp
- QSWidget.cpp
-)
-
-serenity_app(QuickShow ICON filetype-image)
-target_link_libraries(QuickShow LibGUI LibGfx)
diff --git a/Applications/QuickShow/QSWidget.cpp b/Applications/QuickShow/QSWidget.cpp
deleted file mode 100644
index 94dbe858ea..0000000000
--- a/Applications/QuickShow/QSWidget.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "QSWidget.h"
-#include <AK/StringBuilder.h>
-#include <LibCore/DirIterator.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Orientation.h>
-#include <LibGfx/Palette.h>
-
-QSWidget::QSWidget()
-{
- set_fill_with_background_color(false);
-}
-
-QSWidget::~QSWidget()
-{
-}
-
-void QSWidget::clear()
-{
- m_bitmap = nullptr;
- m_path = {};
-
- set_scale(100);
- update();
-}
-
-void QSWidget::flip(Gfx::Orientation orientation)
-{
- m_bitmap = m_bitmap->flipped(orientation);
- set_scale(m_scale);
-
- resize_window();
-}
-
-void QSWidget::rotate(Gfx::RotationDirection rotation_direction)
-{
- m_bitmap = m_bitmap->rotated(rotation_direction);
- set_scale(m_scale);
-
- resize_window();
-}
-
-void QSWidget::navigate(Directions direction)
-{
- if (m_path == nullptr)
- return;
-
- auto parts = m_path.split('/');
- parts.remove(parts.size() - 1);
- StringBuilder sb;
- sb.append("/");
- sb.join("/", parts);
- AK::String current_dir = sb.to_string();
-
- if (m_files_in_same_dir.is_empty()) {
- Core::DirIterator iterator(current_dir, Core::DirIterator::Flags::SkipDots);
- while (iterator.has_next()) {
- String file = iterator.next_full_path();
- if (!Gfx::Bitmap::is_path_a_supported_image_format(file))
- continue;
- m_files_in_same_dir.append(file);
- }
- }
-
- auto current_index = m_files_in_same_dir.find_first_index(m_path);
- if (!current_index.has_value()) {
- return;
- }
-
- size_t index = current_index.value();
- if (direction == Directions::Back) {
- if (index == 0) {
- GUI::MessageBox::show(window(), "This is the first file.", "Cannot open image", GUI::MessageBox::Type::Error);
- return;
- }
-
- index--;
- } else if (direction == Directions::Forward) {
- if (index == m_files_in_same_dir.size() - 1) {
- GUI::MessageBox::show(window(), "This is the last file.", "Cannot open image", GUI::MessageBox::Type::Error);
- return;
- }
-
- index++;
- } else if (direction == Directions::First) {
- index = 0;
- } else if (direction == Directions::Last) {
- index = m_files_in_same_dir.size() - 1;
- }
-
- this->load_from_file(m_files_in_same_dir.at(index));
-}
-
-void QSWidget::set_scale(int scale)
-{
- if (m_bitmap.is_null())
- return;
-
- if (m_scale == scale) {
- update();
- return;
- }
-
- if (scale < 10)
- scale = 10;
- if (scale > 1000)
- scale = 1000;
-
- if (scale == 100)
- m_pan_origin = { 0, 0 };
-
- m_scale = scale;
- float scale_factor = (float)m_scale / 100.0f;
-
- Gfx::IntSize new_size;
- new_size.set_width(m_bitmap->width() * scale_factor);
- new_size.set_height(m_bitmap->height() * scale_factor);
- m_bitmap_rect.set_size(new_size);
-
- if (on_scale_change)
- on_scale_change(m_scale, m_bitmap_rect);
-
- relayout();
-}
-
-void QSWidget::relayout()
-{
- if (m_bitmap.is_null())
- return;
-
- float scale_factor = (float)m_scale / 100.0f;
- Gfx::IntSize new_size = m_bitmap_rect.size();
-
- Gfx::IntPoint new_location;
- new_location.set_x((width() / 2) - (new_size.width() / 2) - (m_pan_origin.x() * scale_factor));
- new_location.set_y((height() / 2) - (new_size.height() / 2) - (m_pan_origin.y() * scale_factor));
- m_bitmap_rect.set_location(new_location);
-
- update();
-}
-
-void QSWidget::resize_event(GUI::ResizeEvent& event)
-{
- relayout();
- GUI::Widget::resize_event(event);
-}
-
-void QSWidget::doubleclick_event(GUI::MouseEvent&)
-{
- on_doubleclick();
-}
-
-void QSWidget::paint_event(GUI::PaintEvent& event)
-{
- Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.add_clip_rect(frame_inner_rect());
-
- Gfx::StylePainter::paint_transparency_grid(painter, frame_inner_rect(), palette());
-
- if (!m_bitmap.is_null())
- painter.draw_scaled_bitmap(m_bitmap_rect, *m_bitmap, m_bitmap->rect());
-}
-
-void QSWidget::mousedown_event(GUI::MouseEvent& event)
-{
- if (event.button() != GUI::MouseButton::Left)
- return;
- m_click_position = event.position();
- m_saved_pan_origin = m_pan_origin;
-}
-
-void QSWidget::mouseup_event([[maybe_unused]] GUI::MouseEvent& event) { }
-
-void QSWidget::mousemove_event(GUI::MouseEvent& event)
-{
- if (!(event.buttons() & GUI::MouseButton::Left))
- return;
-
- auto delta = event.position() - m_click_position;
- float scale_factor = (float)m_scale / 100.0f;
- m_pan_origin = m_saved_pan_origin.translated(
- -delta.x() / scale_factor,
- -delta.y() / scale_factor);
-
- relayout();
-}
-
-void QSWidget::mousewheel_event(GUI::MouseEvent& event)
-{
- int new_scale = m_scale - event.wheel_delta() * 10;
- if (new_scale < 10)
- new_scale = 10;
- if (new_scale > 1000)
- new_scale = 1000;
-
- if (new_scale == m_scale) {
- return;
- }
-
- auto old_scale_factor = (float)m_scale / 100.0f;
- auto new_scale_factor = (float)new_scale / 100.0f;
-
- auto focus_point = Gfx::FloatPoint(
- m_pan_origin.x() - ((float)event.x() - (float)width() / 2.0) / old_scale_factor,
- m_pan_origin.y() - ((float)event.y() - (float)height() / 2.0) / old_scale_factor);
-
- m_pan_origin = Gfx::FloatPoint(
- focus_point.x() - new_scale_factor / old_scale_factor * (focus_point.x() - m_pan_origin.x()),
- focus_point.y() - new_scale_factor / old_scale_factor * (focus_point.y() - m_pan_origin.y()));
-
- set_scale(new_scale);
-}
-
-void QSWidget::load_from_file(const String& path)
-{
- auto bitmap = Gfx::Bitmap::load_from_file(path);
- if (!bitmap) {
- GUI::MessageBox::show(window(), String::formatted("Failed to open {}", path), "Cannot open image", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_path = path;
- m_bitmap = bitmap;
- m_scale = -1;
- set_scale(100);
-}
-
-void QSWidget::drop_event(GUI::DropEvent& event)
-{
- event.accept();
- if (on_drop)
- on_drop(event);
-}
-
-void QSWidget::resize_window()
-{
- if (window()->is_fullscreen())
- return;
-
- if (!m_bitmap)
- return;
-
- auto new_size = m_bitmap->size();
-
- if (new_size.width() < 300)
- new_size.set_width(300);
- if (new_size.height() < 200)
- new_size.set_height(200);
-
- new_size.set_height(new_size.height() + m_toolbar_height);
- window()->resize(new_size);
-}
diff --git a/Applications/QuickShow/QSWidget.h b/Applications/QuickShow/QSWidget.h
deleted file mode 100644
index 047241e25e..0000000000
--- a/Applications/QuickShow/QSWidget.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Point.h>
-
-class QSLabel;
-
-class QSWidget final : public GUI::Frame {
- C_OBJECT(QSWidget)
-public:
- enum Directions {
- First,
- Back,
- Forward,
- Last
- };
-
- virtual ~QSWidget() override;
-
- const Gfx::Bitmap* bitmap() const { return m_bitmap.ptr(); }
- const String& path() const { return m_path; }
- void set_scale(int);
- int scale() { return m_scale; }
- void set_toolbar_height(int height) { m_toolbar_height = height; }
- int toolbar_height() { return m_toolbar_height; }
-
- void clear();
- void flip(Gfx::Orientation);
- void rotate(Gfx::RotationDirection);
- void navigate(Directions);
- void load_from_file(const String&);
-
- Function<void(int, Gfx::IntRect)> on_scale_change;
- Function<void()> on_doubleclick;
- Function<void(const GUI::DropEvent&)> on_drop;
-
-private:
- QSWidget();
- virtual void doubleclick_event(GUI::MouseEvent&) override;
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void mousewheel_event(GUI::MouseEvent&) override;
- virtual void drop_event(GUI::DropEvent&) override;
-
- void relayout();
- void resize_window();
-
- String m_path;
- RefPtr<Gfx::Bitmap> m_bitmap;
- int m_toolbar_height { 28 };
-
- Gfx::IntRect m_bitmap_rect;
- int m_scale { -1 };
- Gfx::FloatPoint m_pan_origin;
-
- Gfx::IntPoint m_click_position;
- Gfx::FloatPoint m_saved_pan_origin;
- Vector<String> m_files_in_same_dir;
-};
diff --git a/Applications/QuickShow/main.cpp b/Applications/QuickShow/main.cpp
deleted file mode 100644
index 2319c24a9a..0000000000
--- a/Applications/QuickShow/main.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "QSWidget.h"
-#include <AK/URL.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/MimeData.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/Rect.h>
-#include <serenity.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <string.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept cpath rpath wpath unix cpath fattr proc exec thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept cpath rpath wpath proc exec thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("filetype-image");
-
- const char* path = nullptr;
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(path, "The image file to be displayed.", "file", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
-
- auto window = GUI::Window::construct();
- window->set_double_buffering_enabled(true);
- window->resize(300, 200);
- window->set_icon(app_icon.bitmap_for_size(16));
- window->set_title("QuickShow");
-
- auto& root_widget = window->set_main_widget<GUI::Widget>();
- root_widget.set_fill_with_background_color(true);
- root_widget.set_layout<GUI::VerticalBoxLayout>();
- root_widget.layout()->set_spacing(2);
-
- auto& toolbar_container = root_widget.add<GUI::ToolBarContainer>();
- auto& main_toolbar = toolbar_container.add<GUI::ToolBar>();
-
- auto& widget = root_widget.add<QSWidget>();
- widget.on_scale_change = [&](int scale, Gfx::IntRect rect) {
- if (!widget.bitmap()) {
- window->set_title("QuickShow");
- return;
- }
-
- window->set_title(String::formatted("{} {} {}% - QuickShow", widget.path(), widget.bitmap()->size().to_string(), scale));
-
- if (window->is_fullscreen())
- return;
-
- if (window->is_maximized())
- return;
-
- auto w = max(window->width(), rect.width() + 4);
- auto h = max(window->height(), rect.height() + widget.toolbar_height() + 6);
- window->resize(w, h);
- };
- widget.on_drop = [&](auto& event) {
- window->move_to_front();
-
- if (event.mime_data().has_urls()) {
- auto urls = event.mime_data().urls();
-
- if (!urls.is_empty()) {
- auto url = urls.first();
- widget.load_from_file(url.path());
- }
-
- pid_t child;
- for (size_t i = 1; i < urls.size(); ++i) {
- const char* argv[] = { "/bin/QuickShow", urls[i].path().characters(), nullptr };
- if ((errno = posix_spawn(&child, "/bin/QuickShow", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child) < 0)
- perror("disown");
- }
- }
- }
- };
- widget.on_doubleclick = [&] {
- window->set_fullscreen(!window->is_fullscreen());
- toolbar_container.set_visible(!window->is_fullscreen());
- };
-
- // Actions
- auto open_action = GUI::CommonActions::make_open_action(
- [&](auto&) {
- Optional<String> path = GUI::FilePicker::get_open_filepath(window, "Open image...");
- if (path.has_value()) {
- widget.load_from_file(path.value());
- }
- });
-
- auto delete_action = GUI::CommonActions::make_delete_action(
- [&](auto&) {
- auto path = widget.path();
- if (path.is_empty())
- return;
-
- auto msgbox_result = GUI::MessageBox::show(window,
- String::formatted("Really delete {}?", path),
- "Confirm deletion",
- GUI::MessageBox::Type::Warning,
- GUI::MessageBox::InputType::OKCancel);
-
- if (msgbox_result == GUI::MessageBox::ExecCancel)
- return;
-
- auto unlink_result = unlink(widget.path().characters());
- dbgln("unlink_result::{}", unlink_result);
-
- if (unlink_result < 0) {
- int saved_errno = errno;
- GUI::MessageBox::show(window,
- String::formatted("unlink({}) failed: {}", path, strerror(saved_errno)),
- "Delete failed",
- GUI::MessageBox::Type::Error);
-
- return;
- }
-
- widget.clear();
- });
-
- auto quit_action = GUI::CommonActions::make_quit_action(
- [&](auto&) {
- app->quit();
- });
-
- auto rotate_left_action = GUI::Action::create("Rotate Left", { Mod_None, Key_L },
- [&](auto&) {
- widget.rotate(Gfx::RotationDirection::Left);
- });
-
- auto rotate_right_action = GUI::Action::create("Rotate Right", { Mod_None, Key_R },
- [&](auto&) {
- widget.rotate(Gfx::RotationDirection::Right);
- });
-
- auto vertical_flip_action = GUI::Action::create("Vertical Flip", { Mod_None, Key_V },
- [&](auto&) {
- widget.flip(Gfx::Orientation::Vertical);
- });
-
- auto horizontal_flip_action = GUI::Action::create("Horizontal Flip", { Mod_None, Key_H },
- [&](auto&) {
- widget.flip(Gfx::Orientation::Horizontal);
- });
-
- auto desktop_wallpaper_action = GUI::Action::create("Set as desktop wallpaper",
- [&](auto&) {
- GUI::Desktop::the().set_wallpaper(widget.path());
- });
-
- auto go_first_action = GUI::Action::create("First", { Mod_None, Key_Home }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-first.png"),
- [&](auto&) {
- widget.navigate(QSWidget::Directions::First);
- });
-
- auto go_back_action = GUI::Action::create("Back", { Mod_None, Key_Left }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-back.png"),
- [&](auto&) {
- widget.navigate(QSWidget::Directions::Back);
- });
-
- auto go_forward_action = GUI::Action::create("Forward", { Mod_None, Key_Right }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-forward.png"),
- [&](auto&) {
- widget.navigate(QSWidget::Directions::Forward);
- });
-
- auto go_last_action = GUI::Action::create("Last", { Mod_None, Key_End }, Gfx::Bitmap::load_from_file("/res/icons/16x16/go-last.png"),
- [&](auto&) {
- widget.navigate(QSWidget::Directions::Last);
- });
-
- auto full_sceen_action = GUI::CommonActions::make_fullscreen_action(
- [&](auto&) {
- widget.on_doubleclick();
- });
-
- auto zoom_in_action = GUI::Action::create("Zoom In", { Mod_None, Key_Plus }, Gfx::Bitmap::load_from_file("/res/icons/16x16/zoom-in.png"),
- [&](auto&) {
- widget.set_scale(widget.scale() + 10);
- });
-
- auto zoom_reset_action = GUI::Action::create("Zoom 100%", { Mod_None, Key_0 }, Gfx::Bitmap::load_from_file("/res/icons/16x16/zoom-reset.png"),
- [&](auto&) {
- widget.set_scale(100);
- });
-
- auto zoom_out_action = GUI::Action::create("Zoom Out", { Mod_None, Key_Minus }, Gfx::Bitmap::load_from_file("/res/icons/16x16/zoom-out.png"),
- [&](auto&) {
- widget.set_scale(widget.scale() - 10);
- });
-
- auto hide_show_toolbar_action = GUI::Action::create("Hide/Show Toolbar", { Mod_Ctrl, Key_T },
- [&](auto&) {
- toolbar_container.set_visible(!toolbar_container.is_visible());
- });
-
- auto copy_action = GUI::CommonActions::make_copy_action([&](auto&) {
- if (widget.bitmap())
- GUI::Clipboard::the().set_bitmap(*widget.bitmap());
- });
-
- main_toolbar.add_action(open_action);
- main_toolbar.add_action(delete_action);
- main_toolbar.add_separator();
- main_toolbar.add_action(go_first_action);
- main_toolbar.add_action(go_back_action);
- main_toolbar.add_action(go_forward_action);
- main_toolbar.add_action(go_last_action);
- main_toolbar.add_separator();
- main_toolbar.add_action(zoom_in_action);
- main_toolbar.add_action(zoom_reset_action);
- main_toolbar.add_action(zoom_out_action);
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("QuickShow");
- app_menu.add_action(open_action);
- app_menu.add_action(delete_action);
- app_menu.add_separator();
- app_menu.add_action(quit_action);
-
- auto& image_menu = menubar->add_menu("Image");
- image_menu.add_action(rotate_left_action);
- image_menu.add_action(rotate_right_action);
- image_menu.add_action(vertical_flip_action);
- image_menu.add_action(horizontal_flip_action);
- image_menu.add_separator();
- image_menu.add_action(desktop_wallpaper_action);
-
- auto& navigate_menu = menubar->add_menu("Navigate");
- navigate_menu.add_action(go_first_action);
- navigate_menu.add_action(go_back_action);
- navigate_menu.add_action(go_forward_action);
- navigate_menu.add_action(go_last_action);
-
- auto& view_menu = menubar->add_menu("View");
- view_menu.add_action(full_sceen_action);
- view_menu.add_separator();
- view_menu.add_action(zoom_in_action);
- view_menu.add_action(zoom_reset_action);
- view_menu.add_action(zoom_out_action);
- view_menu.add_separator();
- view_menu.add_action(hide_show_toolbar_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("QuickShow", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- if (path != nullptr) {
- widget.load_from_file(path);
- }
-
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/SoundPlayer/CMakeLists.txt b/Applications/SoundPlayer/CMakeLists.txt
deleted file mode 100644
index 99e1da4653..0000000000
--- a/Applications/SoundPlayer/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-set(SOURCES
- main.cpp
- PlaybackManager.cpp
- SampleWidget.cpp
- SoundPlayerWidget.cpp
-)
-
-serenity_app(SoundPlayer ICON app-sound-player)
-target_link_libraries(SoundPlayer LibAudio LibGUI)
diff --git a/Applications/SoundPlayer/PlaybackManager.cpp b/Applications/SoundPlayer/PlaybackManager.cpp
deleted file mode 100644
index 1421e75215..0000000000
--- a/Applications/SoundPlayer/PlaybackManager.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PlaybackManager.h"
-
-PlaybackManager::PlaybackManager(NonnullRefPtr<Audio::ClientConnection> connection)
- : m_connection(connection)
-{
- m_timer = Core::Timer::construct(100, [&]() {
- if (!m_loader)
- return;
- next_buffer();
- });
- m_timer->stop();
-}
-
-PlaybackManager::~PlaybackManager()
-{
-}
-
-void PlaybackManager::set_loader(NonnullRefPtr<Audio::Loader>&& loader)
-{
- stop();
- m_loader = loader;
- if (m_loader) {
- m_total_length = m_loader->total_samples() / static_cast<float>(m_loader->sample_rate());
- m_timer->start();
- load_next_buffer();
- } else {
- m_timer->stop();
- }
-}
-
-void PlaybackManager::stop()
-{
- set_paused(true);
- m_connection->clear_buffer(true);
- m_buffers.clear();
- m_last_seek = 0;
- m_next_buffer = nullptr;
- m_current_buffer = nullptr;
- m_next_ptr = 0;
-
- if (m_loader)
- m_loader->reset();
-}
-
-void PlaybackManager::play()
-{
- set_paused(false);
-}
-
-void PlaybackManager::loop(bool loop)
-{
- m_loop = loop;
-}
-
-void PlaybackManager::seek(const int position)
-{
- if (!m_loader)
- return;
-
- m_last_seek = position;
- bool paused_state = m_paused;
- set_paused(true);
-
- m_connection->clear_buffer(true);
- m_next_buffer = nullptr;
- m_current_buffer = nullptr;
- m_next_ptr = 0;
- m_buffers.clear();
- m_loader->seek(position);
-
- if (!paused_state)
- set_paused(false);
-}
-
-void PlaybackManager::pause()
-{
- set_paused(true);
-}
-
-void PlaybackManager::remove_dead_buffers()
-{
- int id = m_connection->get_playing_buffer();
- int current_id = -1;
- if (m_current_buffer)
- current_id = m_current_buffer->shbuf_id();
-
- if (id >= 0 && id != current_id) {
- while (!m_buffers.is_empty()) {
- --m_next_ptr;
- auto buffer = m_buffers.take_first();
-
- if (buffer->shbuf_id() == id) {
- m_current_buffer = buffer;
- break;
- }
- }
- }
-}
-
-void PlaybackManager::load_next_buffer()
-{
- if (m_buffers.size() < 10) {
- for (int i = 0; i < 20 && m_loader->loaded_samples() < m_loader->total_samples(); i++) {
- auto buffer = m_loader->get_more_samples(PLAYBACK_MANAGER_BUFFER_SIZE);
- if (buffer)
- m_buffers.append(buffer);
- }
- }
-
- if (m_next_ptr < m_buffers.size()) {
- m_next_buffer = m_buffers.at(m_next_ptr++);
- } else {
- m_next_buffer = nullptr;
- }
-}
-
-void PlaybackManager::set_paused(bool paused)
-{
- if (!m_next_buffer && m_loader)
- load_next_buffer();
-
- m_paused = paused;
- m_connection->set_paused(paused);
-}
-
-bool PlaybackManager::toggle_pause()
-{
- if (m_paused) {
- play();
- } else {
- pause();
- }
- return m_paused;
-}
-
-void PlaybackManager::next_buffer()
-{
- if (on_update)
- on_update();
-
- if (m_paused)
- return;
-
- remove_dead_buffers();
- if (!m_next_buffer) {
- if (!m_connection->get_remaining_samples() && !m_paused) {
- dbgln("Exhausted samples :^)");
- if (m_loop)
- seek(0);
- else
- stop();
- }
-
- return;
- }
-
- bool enqueued = m_connection->try_enqueue(*m_next_buffer);
- if (!enqueued)
- return;
-
- load_next_buffer();
-}
diff --git a/Applications/SoundPlayer/PlaybackManager.h b/Applications/SoundPlayer/PlaybackManager.h
deleted file mode 100644
index 35be78fe9d..0000000000
--- a/Applications/SoundPlayer/PlaybackManager.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Vector.h>
-#include <LibAudio/Buffer.h>
-#include <LibAudio/ClientConnection.h>
-#include <LibAudio/Loader.h>
-#include <LibCore/Timer.h>
-
-#define PLAYBACK_MANAGER_BUFFER_SIZE 64 * KiB
-#define PLAYBACK_MANAGER_RATE 44100
-
-class PlaybackManager final {
-public:
- PlaybackManager(NonnullRefPtr<Audio::ClientConnection>);
- ~PlaybackManager();
-
- void play();
- void stop();
- void pause();
- void seek(const int position);
- void loop(bool);
- bool toggle_pause();
- void set_loader(NonnullRefPtr<Audio::Loader>&&);
-
- int last_seek() const { return m_last_seek; }
- bool is_paused() const { return m_paused; }
- float total_length() const { return m_total_length; }
- RefPtr<Audio::Buffer> current_buffer() const { return m_current_buffer; }
-
- NonnullRefPtr<Audio::ClientConnection> connection() const { return m_connection; }
-
- Function<void()> on_update;
-
-private:
- void next_buffer();
- void set_paused(bool);
- void load_next_buffer();
- void remove_dead_buffers();
-
- bool m_paused { true };
- bool m_loop = { false };
- size_t m_next_ptr { 0 };
- size_t m_last_seek { 0 };
- float m_total_length { 0 };
- RefPtr<Audio::Loader> m_loader { nullptr };
- NonnullRefPtr<Audio::ClientConnection> m_connection;
- RefPtr<Audio::Buffer> m_next_buffer;
- RefPtr<Audio::Buffer> m_current_buffer;
- Vector<RefPtr<Audio::Buffer>> m_buffers;
- RefPtr<Core::Timer> m_timer;
-};
diff --git a/Applications/SoundPlayer/SampleWidget.cpp b/Applications/SoundPlayer/SampleWidget.cpp
deleted file mode 100644
index b3884a175a..0000000000
--- a/Applications/SoundPlayer/SampleWidget.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SampleWidget.h"
-#include <LibAudio/Buffer.h>
-#include <LibGUI/Painter.h>
-#include <math.h>
-
-SampleWidget::SampleWidget()
-{
-}
-
-SampleWidget::~SampleWidget()
-{
-}
-
-void SampleWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
- GUI::Painter painter(*this);
-
- painter.add_clip_rect(event.rect());
- painter.fill_rect(frame_inner_rect(), Color::Black);
-
- float sample_max = 0;
- int count = 0;
- int x_offset = frame_inner_rect().x();
- int x = x_offset;
- int y_offset = frame_inner_rect().center().y();
-
- if (m_buffer) {
- int samples_per_pixel = m_buffer->sample_count() / frame_inner_rect().width();
- for (int sample_index = 0; sample_index < m_buffer->sample_count() && (x - x_offset) < frame_inner_rect().width(); ++sample_index) {
- float sample = fabsf((float)m_buffer->samples()[sample_index].left);
-
- sample_max = max(sample, sample_max);
- ++count;
-
- if (count >= samples_per_pixel) {
- Gfx::IntPoint min_point = { x, y_offset + static_cast<int>(-sample_max * frame_inner_rect().height() / 2) };
- Gfx::IntPoint max_point = { x++, y_offset + static_cast<int>(sample_max * frame_inner_rect().height() / 2) };
- painter.draw_line(min_point, max_point, Color::Green);
-
- count = 0;
- sample_max = 0;
- }
- }
- } else {
- painter.draw_line({ x, y_offset }, { frame_inner_rect().width(), y_offset }, Color::Green);
- }
-}
-
-void SampleWidget::set_buffer(Audio::Buffer* buffer)
-{
- if (m_buffer == buffer)
- return;
- m_buffer = buffer;
- update();
-}
diff --git a/Applications/SoundPlayer/SampleWidget.h b/Applications/SoundPlayer/SampleWidget.h
deleted file mode 100644
index 7da9c20b38..0000000000
--- a/Applications/SoundPlayer/SampleWidget.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-namespace Audio {
-class Buffer;
-}
-
-class SampleWidget final : public GUI::Frame {
- C_OBJECT(SampleWidget)
-public:
- virtual ~SampleWidget() override;
-
- void set_buffer(Audio::Buffer*);
-
-private:
- SampleWidget();
- virtual void paint_event(GUI::PaintEvent&) override;
-
- RefPtr<Audio::Buffer> m_buffer;
-};
diff --git a/Applications/SoundPlayer/SoundPlayerWidget.cpp b/Applications/SoundPlayer/SoundPlayerWidget.cpp
deleted file mode 100644
index f2066aca89..0000000000
--- a/Applications/SoundPlayer/SoundPlayerWidget.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SoundPlayerWidget.h"
-#include <AK/StringBuilder.h>
-#include <LibCore/MimeData.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <math.h>
-
-SoundPlayerWidget::SoundPlayerWidget(GUI::Window& window, NonnullRefPtr<Audio::ClientConnection> connection)
- : m_window(window)
- , m_connection(connection)
- , m_manager(connection)
-{
- set_fill_with_background_color(true);
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 2, 2, 2, 2 });
-
- auto& status_widget = add<GUI::Widget>();
- status_widget.set_fill_with_background_color(true);
- status_widget.set_layout<GUI::HorizontalBoxLayout>();
-
- m_elapsed = status_widget.add<GUI::Label>();
- m_elapsed->set_frame_shape(Gfx::FrameShape::Container);
- m_elapsed->set_frame_shadow(Gfx::FrameShadow::Sunken);
- m_elapsed->set_frame_thickness(2);
- m_elapsed->set_fixed_width(80);
-
- auto& sample_widget_container = status_widget.add<GUI::Widget>();
- sample_widget_container.set_layout<GUI::HorizontalBoxLayout>();
-
- m_sample_widget = sample_widget_container.add<SampleWidget>();
-
- m_remaining = status_widget.add<GUI::Label>();
- m_remaining->set_frame_shape(Gfx::FrameShape::Container);
- m_remaining->set_frame_shadow(Gfx::FrameShadow::Sunken);
- m_remaining->set_frame_thickness(2);
- m_remaining->set_fixed_width(80);
-
- m_slider = add<Slider>(Orientation::Horizontal);
- m_slider->set_min(0);
- m_slider->set_enabled(false);
- m_slider->on_knob_released = [&](int value) { m_manager.seek(denormalize_rate(value)); };
-
- auto& control_widget = add<GUI::Widget>();
- control_widget.set_fill_with_background_color(true);
- control_widget.set_layout<GUI::HorizontalBoxLayout>();
- control_widget.set_fixed_height(30);
- control_widget.layout()->set_margins({ 10, 2, 10, 2 });
- control_widget.layout()->set_spacing(10);
-
- m_play = control_widget.add<GUI::Button>();
- m_play->set_icon(*m_pause_icon);
- m_play->set_enabled(false);
- m_play->on_click = [this](auto) {
- m_play->set_icon(m_manager.toggle_pause() ? *m_play_icon : *m_pause_icon);
- };
-
- m_stop = control_widget.add<GUI::Button>();
- m_stop->set_enabled(false);
- m_stop->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/stop.png"));
- m_stop->on_click = [this](auto) { m_manager.stop(); };
-
- m_status = add<GUI::Label>();
- m_status->set_frame_shape(Gfx::FrameShape::Box);
- m_status->set_frame_shadow(Gfx::FrameShadow::Raised);
- m_status->set_frame_thickness(4);
- m_status->set_text_alignment(Gfx::TextAlignment::CenterLeft);
- m_status->set_fixed_height(18);
- m_status->set_text("No file open!");
-
- update_position(0);
-
- m_manager.on_update = [&]() { update_ui(); };
-}
-
-SoundPlayerWidget::~SoundPlayerWidget()
-{
-}
-
-SoundPlayerWidget::Slider::~Slider()
-{
-}
-
-void SoundPlayerWidget::hide_scope(bool hide)
-{
- m_sample_widget->set_visible(!hide);
-}
-
-void SoundPlayerWidget::open_file(String path)
-{
- NonnullRefPtr<Audio::Loader> loader = Audio::Loader::create(path);
- if (loader->has_error() || !loader->sample_rate()) {
- const String error_string = loader->error_string();
- GUI::MessageBox::show(window(),
- String::formatted("Failed to load audio file: {} ({})", path, error_string.is_null() ? "Unknown error" : error_string),
- "Filetype error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_sample_ratio = PLAYBACK_MANAGER_RATE / static_cast<float>(loader->sample_rate());
-
- m_slider->set_max(normalize_rate(static_cast<int>(loader->total_samples())));
- m_slider->set_enabled(true);
- m_play->set_enabled(true);
- m_stop->set_enabled(true);
-
- m_window.set_title(String::formatted("{} - SoundPlayer", loader->file()->filename()));
- m_status->set_text(String::formatted(
- "Sample rate {}Hz, {} channel(s), {} bits per sample",
- loader->sample_rate(),
- loader->num_channels(),
- loader->bits_per_sample()));
-
- m_manager.set_loader(move(loader));
- update_position(0);
-}
-
-void SoundPlayerWidget::drop_event(GUI::DropEvent& event)
-{
- event.accept();
- window()->move_to_front();
-
- if (event.mime_data().has_urls()) {
- auto urls = event.mime_data().urls();
- if (urls.is_empty())
- return;
- open_file(urls.first().path());
- }
-}
-
-int SoundPlayerWidget::normalize_rate(int rate) const
-{
- return static_cast<int>(rate * m_sample_ratio);
-}
-
-int SoundPlayerWidget::denormalize_rate(int rate) const
-{
- return static_cast<int>(rate / m_sample_ratio);
-}
-
-void SoundPlayerWidget::update_ui()
-{
- m_sample_widget->set_buffer(m_manager.current_buffer());
- m_play->set_icon(m_manager.is_paused() ? *m_play_icon : *m_pause_icon);
- update_position(m_manager.connection()->get_played_samples());
-}
-
-void SoundPlayerWidget::update_position(const int position)
-{
- int total_norm_samples = position + normalize_rate(m_manager.last_seek());
- float seconds = (total_norm_samples / static_cast<float>(PLAYBACK_MANAGER_RATE));
- float remaining_seconds = m_manager.total_length() - seconds;
-
- m_elapsed->set_text(String::formatted(
- "Elapsed:\n{}:{:02}.{:02}",
- static_cast<int>(seconds / 60),
- static_cast<int>(seconds) % 60,
- static_cast<int>(seconds * 100) % 100));
-
- m_remaining->set_text(String::formatted(
- "Remaining:\n{}:{:02}.{:02}",
- static_cast<int>(remaining_seconds / 60),
- static_cast<int>(remaining_seconds) % 60,
- static_cast<int>(remaining_seconds * 100) % 100));
-
- m_slider->set_value(total_norm_samples);
-}
diff --git a/Applications/SoundPlayer/SoundPlayerWidget.h b/Applications/SoundPlayer/SoundPlayerWidget.h
deleted file mode 100644
index ab7bc60aea..0000000000
--- a/Applications/SoundPlayer/SoundPlayerWidget.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "PlaybackManager.h"
-#include "SampleWidget.h"
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Slider.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-
-class SoundPlayerWidget final : public GUI::Widget {
- C_OBJECT(SoundPlayerWidget)
-public:
- virtual ~SoundPlayerWidget() override;
- void open_file(String path);
- void hide_scope(bool);
- PlaybackManager& manager() { return m_manager; }
-
-private:
- explicit SoundPlayerWidget(GUI::Window&, NonnullRefPtr<Audio::ClientConnection>);
-
- virtual void drop_event(GUI::DropEvent&) override;
-
- void update_position(const int position);
- void update_ui();
- int normalize_rate(int) const;
- int denormalize_rate(int) const;
-
- class Slider final : public GUI::Slider {
- C_OBJECT(Slider)
- public:
- virtual ~Slider() override;
- Function<void(int)> on_knob_released;
- void set_value(int value)
- {
- if (!knob_dragging())
- GUI::Slider::set_value(value);
- }
-
- protected:
- Slider(Orientation orientation)
- : GUI::Slider(orientation)
- {
- }
-
- virtual void mouseup_event(GUI::MouseEvent& event) override
- {
- if (on_knob_released && is_enabled())
- on_knob_released(value());
-
- GUI::Slider::mouseup_event(event);
- }
- };
-
- GUI::Window& m_window;
- NonnullRefPtr<Audio::ClientConnection> m_connection;
- PlaybackManager m_manager;
- float m_sample_ratio { 1.0 };
- RefPtr<GUI::Label> m_status;
- RefPtr<GUI::Label> m_elapsed;
- RefPtr<GUI::Label> m_remaining;
- RefPtr<Slider> m_slider;
- RefPtr<SampleWidget> m_sample_widget;
- RefPtr<Gfx::Bitmap> m_play_icon { Gfx::Bitmap::load_from_file("/res/icons/16x16/play.png") };
- RefPtr<Gfx::Bitmap> m_pause_icon { Gfx::Bitmap::load_from_file("/res/icons/16x16/pause.png") };
- RefPtr<GUI::Button> m_play;
- RefPtr<GUI::Button> m_stop;
-};
diff --git a/Applications/SoundPlayer/main.cpp b/Applications/SoundPlayer/main.cpp
deleted file mode 100644
index 47dbd555c8..0000000000
--- a/Applications/SoundPlayer/main.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SoundPlayerWidget.h"
-#include <LibAudio/ClientConnection.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept rpath thread unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer accept rpath thread unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto audio_client = Audio::ClientConnection::construct();
- audio_client->handshake();
-
- if (pledge("stdio shared_buffer accept rpath thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-sound-player");
-
- auto window = GUI::Window::construct();
- window->set_title("Sound Player");
- window->set_resizable(false);
- window->resize(350, 140);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Sound Player");
- auto& player = window->set_main_widget<SoundPlayerWidget>(window, audio_client);
-
- if (argc > 1) {
- String path = argv[1];
- player.open_file(path);
- player.manager().play();
- }
-
- auto hide_scope = GUI::Action::create_checkable("Hide scope", { Mod_Ctrl, Key_H }, [&](auto& action) {
- player.hide_scope(action.is_checked());
- });
-
- app_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
- Optional<String> path = GUI::FilePicker::get_open_filepath(window, "Open sound file...");
- if (path.has_value()) {
- player.open_file(path.value());
- }
- }));
- app_menu.add_action(move(hide_scope));
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
- app->quit();
- }));
-
- auto& playback_menu = menubar->add_menu("Playback");
-
- auto loop = GUI::Action::create_checkable("Loop", { Mod_Ctrl, Key_R }, [&](auto& action) {
- player.manager().loop(action.is_checked());
- });
-
- playback_menu.add_action(move(loop));
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Sound Player", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- window->show();
- return app->exec();
-}
diff --git a/Applications/SpaceAnalyzer/CMakeLists.txt b/Applications/SpaceAnalyzer/CMakeLists.txt
deleted file mode 100644
index 23cc18f13e..0000000000
--- a/Applications/SpaceAnalyzer/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-compile_gml(SpaceAnalyzer.gml SpaceAnalyzerGML.h space_analyzer_gml)
-
-set(SOURCES
- main.cpp
- TreeMapWidget.cpp
- SpaceAnalyzerGML.h
-)
-
-serenity_app(SpaceAnalyzer ICON app-space-analyzer)
-target_link_libraries(SpaceAnalyzer LibGfx LibGUI)
diff --git a/Applications/SpaceAnalyzer/SpaceAnalyzer.gml b/Applications/SpaceAnalyzer/SpaceAnalyzer.gml
deleted file mode 100644
index a4a3363c6a..0000000000
--- a/Applications/SpaceAnalyzer/SpaceAnalyzer.gml
+++ /dev/null
@@ -1,20 +0,0 @@
-@GUI::Widget {
- layout: @GUI::VerticalBoxLayout {
- spacing: 0
- }
-
- @GUI::ToolBarContainer {
- @GUI::BreadcrumbBar {
- fixed_height: 25
- name: "breadcrumb_bar"
- }
- }
-
- @SpaceAnalyzer::TreeMapWidget {
- name: "tree_map"
- }
-
- @GUI::StatusBar {
- name: "status_bar"
- }
-}
diff --git a/Applications/SpaceAnalyzer/TreeMapWidget.cpp b/Applications/SpaceAnalyzer/TreeMapWidget.cpp
deleted file mode 100644
index 97d9b58a9e..0000000000
--- a/Applications/SpaceAnalyzer/TreeMapWidget.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (c) 2021, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TreeMapWidget.h"
-#include <AK/NumberFormat.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/Font.h>
-#include <WindowServer/WindowManager.h>
-
-namespace SpaceAnalyzer {
-
-REGISTER_WIDGET(SpaceAnalyzer, TreeMapWidget)
-
-TreeMapWidget::TreeMapWidget()
- : m_viewpoint(0)
-{
-}
-
-TreeMapWidget::~TreeMapWidget()
-{
-}
-
-static const Color colors[] = {
- Color(253, 231, 37),
- Color(148, 216, 64),
- Color(60, 188, 117),
- Color(31, 150, 139),
- Color(45, 112, 142),
- Color(63, 71, 136),
- Color(85, 121, 104),
-};
-
-static float get_normalized_aspect_ratio(float a, float b)
-{
- if (a < b) {
- return a / b;
- } else {
- return b / a;
- }
-}
-
-static bool node_is_leaf(const TreeMapNode& node)
-{
- return node.num_children() == 0;
-}
-
-bool TreeMapWidget::rect_can_contain_label(const Gfx::IntRect& rect) const
-{
- return rect.height() > font().presentation_size() && rect.width() > 20;
-}
-
-bool TreeMapWidget::rect_can_contain_children(const Gfx::IntRect& rect) const
-{
- return rect.height() > 10 && rect.width() > 10;
-}
-
-Gfx::IntRect TreeMapWidget::inner_rect_for_frame(const Gfx::IntRect& rect) const
-{
- const int margin = 5;
- Gfx::IntRect tmp_rect = rect;
- tmp_rect.shrink(2, 2); // border
- tmp_rect.shrink(2, 2); // shading
- if (rect_can_contain_label(rect)) {
- tmp_rect.set_y(tmp_rect.y() + font().presentation_size() + margin);
- tmp_rect.set_height(tmp_rect.height() - (font().presentation_size() + margin * 2));
- tmp_rect.set_x(tmp_rect.x() + margin);
- tmp_rect.set_width(tmp_rect.width() - margin * 2);
- }
- return tmp_rect;
-}
-
-void TreeMapWidget::paint_cell_frame(GUI::Painter& painter, const TreeMapNode& node, const Gfx::IntRect& cell_rect, int depth, bool fill_frame) const
-{
- const Gfx::IntRect border_rect = cell_rect.shrunken(2, 2);
- const Gfx::IntRect outer_rect = border_rect.shrunken(2, 2);
- const Gfx::IntRect inner_rect = inner_rect_for_frame(cell_rect);
-
- painter.clear_clip_rect();
- painter.add_clip_rect(cell_rect);
- Color color = colors[depth % (sizeof(colors) / sizeof(colors[0]))];
- if (m_selected_node_cache == &node) {
- color = color.darkened(0.8f);
- }
-
- // Draw borders.
- painter.draw_rect(cell_rect, Color::Black, false);
- painter.draw_line(border_rect.bottom_left(), border_rect.top_left(), color.lightened());
- painter.draw_line(border_rect.top_left(), border_rect.top_right(), color.lightened());
- painter.draw_line(border_rect.top_right(), border_rect.bottom_right(), color.darkened());
- painter.draw_line(border_rect.bottom_left(), border_rect.bottom_right(), color.darkened());
-
- // Paint the background.
- if (fill_frame) {
- painter.fill_rect(outer_rect, color);
- } else {
- for (auto& shard : outer_rect.shatter(inner_rect)) {
- painter.fill_rect(shard, color);
- }
- }
-
- // Paint text.
- if (rect_can_contain_label(outer_rect)) {
- Gfx::IntRect text_rect = outer_rect;
- text_rect.move_by(2, 2);
- painter.draw_text(text_rect, node.name(), font(), Gfx::TextAlignment::TopLeft, Color::Black);
- if (node_is_leaf(node)) {
- text_rect.move_by(0, font().presentation_size() + 1);
- painter.draw_text(text_rect, human_readable_size(node.area()), font(), Gfx::TextAlignment::TopLeft, Color::Black);
- }
- }
-}
-
-template<typename Function>
-void TreeMapWidget::lay_out_children(const TreeMapNode& node, const Gfx::IntRect& rect, int depth, Function callback)
-{
- if (node.num_children() == 0) {
- return;
- }
-
- // Check if the children are sorted yet, if not do that now.
- for (size_t k = 0; k < node.num_children() - 1; k++) {
- if (node.child_at(k).area() < node.child_at(k + 1).area()) {
- node.sort_children_by_area();
- break;
- }
- }
-
- int total_area = node.area();
- Gfx::IntRect canvas = rect;
- bool remaining_nodes_are_too_small = false;
- for (size_t i = 0; !remaining_nodes_are_too_small && i < node.num_children(); i++) {
- const int i_node_area = node.child_at(i).area();
- if (i_node_area == 0)
- break;
-
- const int long_side_size = max(canvas.width(), canvas.height());
- const int short_side_size = min(canvas.width(), canvas.height());
-
- int row_or_column_size = (long long int)long_side_size * i_node_area / total_area;
- int node_area_sum = i_node_area;
- size_t k = i + 1;
-
- // Try to add nodes to this row or column so long as the worst aspect ratio of
- // the new set of nodes is better than the worst aspect ratio of the current set.
- {
- float best_worst_aspect_ratio_so_far = get_normalized_aspect_ratio(row_or_column_size, short_side_size);
- for (; k < node.num_children(); k++) {
- // Do a preliminary calculation of the worst aspect ratio of the nodes at index i and k
- // if that aspect ratio is better than the 'best_worst_aspect_ratio_so_far' we keep it,
- // otherwise it is discarded.
- int k_node_area = node.child_at(k).area();
- if (k_node_area == 0) {
- break;
- }
- int new_node_area_sum = node_area_sum + k_node_area;
- int new_row_or_column_size = (long long int)long_side_size * new_node_area_sum / total_area;
- int i_node_size = (long long int)short_side_size * i_node_area / new_node_area_sum;
- int k_node_size = (long long int)short_side_size * k_node_area / new_node_area_sum;
- float i_node_aspect_ratio = get_normalized_aspect_ratio(new_row_or_column_size, i_node_size);
- float k_node_aspect_ratio = get_normalized_aspect_ratio(new_row_or_column_size, k_node_size);
- float new_worst_aspect_ratio = min(i_node_aspect_ratio, k_node_aspect_ratio);
- if (new_worst_aspect_ratio < best_worst_aspect_ratio_so_far) {
- break;
- }
- best_worst_aspect_ratio_so_far = new_worst_aspect_ratio;
- node_area_sum = new_node_area_sum;
- row_or_column_size = new_row_or_column_size;
- }
- }
-
- // Paint the elements from 'i' up to and including 'k-1'.
- {
- const int fixed_side_size = row_or_column_size;
- int placement_area = node_area_sum;
- int main_dim = short_side_size;
-
- // Lay out nodes in a row or column.
- Orientation orientation = canvas.width() > canvas.height() ? Orientation::Horizontal : Orientation::Vertical;
- Gfx::IntRect layout_rect = canvas;
- layout_rect.set_primary_size_for_orientation(orientation, fixed_side_size);
- for (size_t q = i; q < k; q++) {
- auto& child = node.child_at(q);
- int node_size = (long long int)main_dim * child.area() / placement_area;
- Gfx::IntRect cell_rect = layout_rect;
- cell_rect.set_secondary_size_for_orientation(orientation, node_size);
- Gfx::IntRect inner_rect = inner_rect_for_frame(cell_rect);
- bool is_visual_leaf = child.num_children() == 0 || !rect_can_contain_children(inner_rect);
- callback(child, q, cell_rect, depth, is_visual_leaf ? IsVisualLeaf::Yes : IsVisualLeaf::No, IsRemainder::No);
- if (cell_rect.width() * cell_rect.height() < 16) {
- remaining_nodes_are_too_small = true;
- } else {
- lay_out_children(child, inner_rect, depth + 1, callback);
- }
- layout_rect.set_secondary_offset_for_orientation(orientation, layout_rect.secondary_offset_for_orientation(orientation) + node_size);
- main_dim -= node_size;
- placement_area -= child.area();
- }
- canvas.set_primary_offset_for_orientation(orientation, canvas.primary_offset_for_orientation(orientation) + fixed_side_size);
- canvas.set_primary_size_for_orientation(orientation, canvas.primary_size_for_orientation(orientation) - fixed_side_size);
- }
-
- // Consume nodes that were added to this row or column.
- i = k - 1;
- total_area -= node_area_sum;
- }
-
- // If not the entire canvas was filled with nodes, fill the remaining area with a dither pattern.
- if (!canvas.is_empty()) {
- callback(node, 0, canvas, depth, IsVisualLeaf::No, IsRemainder::Yes);
- }
-}
-
-const TreeMapNode* TreeMapWidget::path_node(size_t n) const
-{
- if (!m_tree.ptr())
- return nullptr;
- const TreeMapNode* iter = &m_tree->root();
- size_t path_index = 0;
- while (iter && path_index < m_path.size() && path_index < n) {
- size_t child_index = m_path[path_index];
- if (child_index >= iter->num_children()) {
- return nullptr;
- }
- iter = &iter->child_at(child_index);
- path_index++;
- }
- return iter;
-}
-
-void TreeMapWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
- GUI::Painter painter(*this);
-
- m_selected_node_cache = path_node(m_path.size());
-
- const TreeMapNode* node = path_node(m_viewpoint);
- if (!node) {
- painter.fill_rect(frame_inner_rect(), Color::MidGray);
- } else if (node_is_leaf(*node)) {
- paint_cell_frame(painter, *node, frame_inner_rect(), m_viewpoint - 1, true);
- } else {
- lay_out_children(*node, frame_inner_rect(), m_viewpoint, [&](const TreeMapNode& node, int, const Gfx::IntRect& rect, int depth, IsVisualLeaf visual_leaf, IsRemainder remainder) {
- if (remainder == IsRemainder::No) {
- bool fill = visual_leaf == IsVisualLeaf::Yes ? true : false;
- paint_cell_frame(painter, node, rect, depth, fill);
- } else {
- Color color = colors[depth % (sizeof(colors) / sizeof(colors[0]))];
- painter.clear_clip_rect();
- painter.add_clip_rect(rect);
- painter.draw_rect(rect, Color::Black);
- painter.fill_rect_with_dither_pattern(rect.shrunken(2, 2), color, Color::Black);
- }
- });
- }
-}
-
-Vector<int> TreeMapWidget::path_to_position(const Gfx::IntPoint& position)
-{
- const TreeMapNode* node = path_node(m_viewpoint);
- if (!node) {
- return {};
- }
- Vector<int> path;
- lay_out_children(*node, frame_inner_rect(), m_viewpoint, [&](const TreeMapNode&, int index, const Gfx::IntRect& rect, int, IsVisualLeaf, IsRemainder is_remainder) {
- if (is_remainder == IsRemainder::No && rect.contains(position)) {
- path.append(index);
- }
- });
- return path;
-}
-
-void TreeMapWidget::mousedown_event(GUI::MouseEvent& event)
-{
- const TreeMapNode* node = path_node(m_viewpoint);
- if (node && !node_is_leaf(*node)) {
- Vector<int> path = path_to_position(event.position());
- if (!path.is_empty()) {
- m_path.shrink(m_viewpoint);
- m_path.append(path);
- if (on_path_change) {
- on_path_change();
- }
- update();
- }
- }
-}
-
-void TreeMapWidget::doubleclick_event(GUI::MouseEvent& event)
-{
- const TreeMapNode* node = path_node(m_viewpoint);
- if (node && !node_is_leaf(*node)) {
- Vector<int> path = path_to_position(event.position());
- m_path.shrink(m_viewpoint);
- m_path.append(path);
- m_viewpoint = m_path.size();
- if (on_path_change) {
- on_path_change();
- }
- update();
- }
-}
-
-void TreeMapWidget::mousewheel_event(GUI::MouseEvent& event)
-{
- int delta = event.wheel_delta();
- // FIXME: The wheel_delta is premultiplied in the window server, we actually want a raw value here.
- int step_size = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetScrollStepSize>()->step_size();
- if (delta > 0) {
- size_t step_back = delta / step_size;
- if (step_back > m_viewpoint)
- step_back = m_viewpoint;
- set_viewpoint(m_viewpoint - step_back);
- } else {
- size_t step_up = (-delta) / step_size;
- set_viewpoint(m_viewpoint + step_up);
- }
-}
-
-void TreeMapWidget::set_tree(RefPtr<TreeMap> tree)
-{
- m_tree = tree;
- m_path.clear();
- m_viewpoint = 0;
- if (on_path_change) {
- on_path_change();
- }
- update();
-}
-
-void TreeMapWidget::set_viewpoint(size_t viewpoint)
-{
- if (viewpoint > m_path.size())
- viewpoint = m_path.size();
- m_viewpoint = viewpoint;
- if (on_path_change) {
- on_path_change();
- }
- update();
-}
-
-size_t TreeMapWidget::path_size() const
-{
- return m_path.size() + 1;
-}
-
-size_t TreeMapWidget::viewpoint() const
-{
- return m_viewpoint;
-}
-
-}
diff --git a/Applications/SpaceAnalyzer/TreeMapWidget.h b/Applications/SpaceAnalyzer/TreeMapWidget.h
deleted file mode 100644
index 8b4e1e9269..0000000000
--- a/Applications/SpaceAnalyzer/TreeMapWidget.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2021, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-#include <LibGfx/Rect.h>
-
-namespace SpaceAnalyzer {
-
-struct TreeMapNode {
- virtual String name() const = 0;
- virtual int64_t area() const = 0;
- virtual size_t num_children() const = 0;
- virtual const TreeMapNode& child_at(size_t i) const = 0;
- virtual void sort_children_by_area() const = 0;
-};
-
-struct TreeMap : public RefCounted<TreeMap> {
- virtual ~TreeMap() { }
- virtual const TreeMapNode& root() const = 0;
-};
-
-class TreeMapWidget final : public GUI::Frame {
- C_OBJECT(TreeMapWidget)
-
-public:
- virtual ~TreeMapWidget() override;
- Function<void()> on_path_change;
- size_t path_size() const;
- const TreeMapNode* path_node(size_t n) const;
- size_t viewpoint() const;
- void set_viewpoint(size_t);
- void set_tree(RefPtr<TreeMap> tree);
-
-private:
- TreeMapWidget();
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void mousedown_event(GUI::MouseEvent&) override;
- virtual void doubleclick_event(GUI::MouseEvent&) override;
- virtual void mousewheel_event(GUI::MouseEvent&) override;
-
- bool rect_can_contain_children(const Gfx::IntRect& rect) const;
- bool rect_can_contain_label(const Gfx::IntRect& rect) const;
- Gfx::IntRect inner_rect_for_frame(const Gfx::IntRect& rect) const;
-
- enum class IsVisualLeaf {
- Yes,
- No
- };
- enum class IsRemainder {
- Yes,
- No
- };
-
- template<typename Function>
- void lay_out_children(const TreeMapNode&, const Gfx::IntRect&, int depth, Function);
- void paint_cell_frame(GUI::Painter&, const TreeMapNode&, const Gfx::IntRect&, int depth, bool fill) const;
- Vector<int> path_to_position(const Gfx::IntPoint&);
-
- RefPtr<TreeMap> m_tree;
- Vector<int> m_path;
- size_t m_viewpoint;
- const void* m_selected_node_cache;
-};
-
-}
diff --git a/Applications/SpaceAnalyzer/main.cpp b/Applications/SpaceAnalyzer/main.cpp
deleted file mode 100644
index 2ce061f786..0000000000
--- a/Applications/SpaceAnalyzer/main.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (c) 2021, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TreeMapWidget.h"
-#include <AK/Queue.h>
-#include <AK/QuickSort.h>
-#include <AK/RefCounted.h>
-#include <Applications/SpaceAnalyzer/SpaceAnalyzerGML.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <LibGUI/AboutDialog.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BreadcrumbBar.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/StatusBar.h>
-#include <sys/stat.h>
-
-static const char* APP_NAME = "Space Analyzer";
-
-struct TreeNode : public SpaceAnalyzer::TreeMapNode {
- TreeNode(String name)
- : m_name(move(name)) {};
-
- virtual String name() const { return m_name; }
- virtual int64_t area() const { return m_area; }
- virtual size_t num_children() const
- {
- if (m_children) {
- return m_children->size();
- }
- return 0;
- }
- virtual const TreeNode& child_at(size_t i) const { return m_children->at(i); }
- virtual void sort_children_by_area() const
- {
- if (m_children) {
- Vector<TreeNode>* children = const_cast<Vector<TreeNode>*>(m_children.ptr());
- quick_sort(*children, [](auto& a, auto& b) { return b.m_area < a.m_area; });
- }
- }
-
- String m_name;
- int64_t m_area { 0 };
- OwnPtr<Vector<TreeNode>> m_children;
-};
-
-struct Tree : public SpaceAnalyzer::TreeMap {
- Tree(String root_name)
- : m_root(move(root_name)) {};
- virtual ~Tree() {};
- TreeNode m_root;
- virtual const SpaceAnalyzer::TreeMapNode& root() const override
- {
- return m_root;
- };
-};
-
-struct MountInfo {
- String mount_point;
- String source;
-};
-
-static void fill_mounts(Vector<MountInfo>& output)
-{
- // Output info about currently mounted filesystems.
- auto df = Core::File::construct("/proc/df");
- if (!df->open(Core::IODevice::ReadOnly)) {
- fprintf(stderr, "Failed to open /proc/df: %s\n", df->error_string());
- return;
- }
-
- auto content = df->read_all();
- auto json = JsonValue::from_string(content);
- ASSERT(json.has_value());
-
- json.value().as_array().for_each([&output](auto& value) {
- auto filesystem_object = value.as_object();
- MountInfo mount_info;
- mount_info.mount_point = filesystem_object.get("mount_point").to_string();
- mount_info.source = filesystem_object.get("source").as_string_or("none");
- output.append(mount_info);
- });
-}
-
-static MountInfo* find_mount_for_path(String path, Vector<MountInfo>& mounts)
-{
- MountInfo* result = nullptr;
- size_t length = 0;
- for (auto& mount_info : mounts) {
- String& mount_point = mount_info.mount_point;
- if (path.starts_with(mount_point)) {
- if (!result || mount_point.length() > length) {
- result = &mount_info;
- length = mount_point.length();
- }
- }
- }
- return result;
-}
-
-static long long int update_totals(TreeNode& node)
-{
- long long int result = 0;
- if (node.m_children) {
- for (auto& child : *node.m_children) {
- result += update_totals(child);
- }
- node.m_area = result;
- } else {
- result = node.m_area;
- }
- return result;
-}
-
-struct QueueEntry {
- QueueEntry(String path, TreeNode* node)
- : path(move(path))
- , node(node) {};
- String path;
- TreeNode* node { nullptr };
-};
-
-static void populate_filesize_tree(TreeNode& root, Vector<MountInfo>& mounts, HashMap<int, int>& error_accumulator)
-{
- ASSERT(!root.m_name.ends_with("/"));
-
- Queue<QueueEntry> queue;
- queue.enqueue(QueueEntry(root.m_name, &root));
-
- StringBuilder builder = StringBuilder();
- builder.append(root.m_name);
- builder.append("/");
- MountInfo* root_mount_info = find_mount_for_path(builder.to_string(), mounts);
- if (!root_mount_info) {
- return;
- }
- while (!queue.is_empty()) {
- QueueEntry queue_entry = queue.dequeue();
-
- builder.clear();
- builder.append(queue_entry.path);
- builder.append("/");
-
- MountInfo* mount_info = find_mount_for_path(builder.to_string(), mounts);
- if (!mount_info || (mount_info != root_mount_info && mount_info->source != root_mount_info->source)) {
- continue;
- }
-
- Core::DirIterator dir_iterator(builder.to_string(), Core::DirIterator::SkipParentAndBaseDir);
- if (dir_iterator.has_error()) {
- int error_sum = error_accumulator.get(dir_iterator.error()).value_or(0);
- error_accumulator.set(dir_iterator.error(), error_sum + 1);
- } else {
- queue_entry.node->m_children = make<Vector<TreeNode>>();
- while (dir_iterator.has_next()) {
- queue_entry.node->m_children->append(TreeNode(dir_iterator.next_path()));
- }
- for (auto& child : *queue_entry.node->m_children) {
- String& name = child.m_name;
- int name_len = name.length();
- builder.append(name);
- struct stat st;
- int stat_result = lstat(builder.to_string().characters(), &st);
- if (stat_result < 0) {
- int error_sum = error_accumulator.get(errno).value_or(0);
- error_accumulator.set(errno, error_sum + 1);
- } else {
- if (S_ISDIR(st.st_mode)) {
- queue.enqueue(QueueEntry(builder.to_string(), &child));
- } else {
- child.m_area = st.st_size;
- }
- }
- builder.trim(name_len);
- }
- }
- }
-
- update_totals(root);
-}
-
-static void analyze(RefPtr<Tree> tree, SpaceAnalyzer::TreeMapWidget& treemapwidget, GUI::StatusBar& statusbar)
-{
- // Build an in-memory tree mirroring the filesystem and for each node
- // calculate the sum of the file size for all its descendants.
- TreeNode* root = &tree->m_root;
- Vector<MountInfo> mounts;
- fill_mounts(mounts);
- HashMap<int, int> error_accumulator;
- populate_filesize_tree(*root, mounts, error_accumulator);
-
- // Display an error summary in the statusbar.
- if (!error_accumulator.is_empty()) {
- StringBuilder builder;
- bool first = true;
- builder.append("Some directories were not analyzed: ");
- for (auto& key : error_accumulator.keys()) {
- if (!first) {
- builder.append(", ");
- }
- builder.append(strerror(key));
- builder.append(" (");
- int value = error_accumulator.get(key).value();
- builder.append(String::number(value));
- if (value == 1) {
- builder.append(" time");
- } else {
- builder.append(" times");
- }
- builder.append(")");
- first = false;
- }
- statusbar.set_text(builder.to_string());
- } else {
- statusbar.set_text("No errors");
- }
- treemapwidget.set_tree(tree);
-}
-
-int main(int argc, char* argv[])
-{
- auto app = GUI::Application::construct(argc, argv);
-
- RefPtr<Tree> tree = adopt(*new Tree(""));
-
- // Configure application window.
- auto app_icon = GUI::Icon::default_icon("app-space-analyzer");
- auto window = GUI::Window::construct();
- window->set_title(APP_NAME);
- window->resize(640, 480);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- // Load widgets.
- auto& mainwidget = window->set_main_widget<GUI::Widget>();
- mainwidget.load_from_gml(space_analyzer_gml);
- auto& breadcrumbbar = *mainwidget.find_descendant_of_type_named<GUI::BreadcrumbBar>("breadcrumb_bar");
- auto& treemapwidget = *mainwidget.find_descendant_of_type_named<SpaceAnalyzer::TreeMapWidget>("tree_map");
- auto& statusbar = *mainwidget.find_descendant_of_type_named<GUI::StatusBar>("status_bar");
-
- // Configure the menubar.
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu(APP_NAME);
- app_menu.add_action(GUI::Action::create("Analyze", [&](auto&) {
- analyze(tree, treemapwidget, statusbar);
- }));
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
- app->quit();
- }));
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action(APP_NAME, app_icon, window));
- app->set_menubar(move(menubar));
-
- // Configure event handlers.
- breadcrumbbar.on_segment_click = [&](size_t index) {
- ASSERT(index < treemapwidget.path_size());
- treemapwidget.set_viewpoint(index);
- };
- treemapwidget.on_path_change = [&]() {
- breadcrumbbar.clear_segments();
- for (size_t k = 0; k < treemapwidget.path_size(); k++) {
- if (k == 0) {
- breadcrumbbar.append_segment("/");
- } else {
- const SpaceAnalyzer::TreeMapNode* node = treemapwidget.path_node(k);
- breadcrumbbar.append_segment(node->name());
- }
- }
- breadcrumbbar.set_selected_segment(treemapwidget.viewpoint());
- };
-
- // At startup automatically do an analysis of root.
- analyze(tree, treemapwidget, statusbar);
-
- window->show();
- return app->exec();
-}
diff --git a/Applications/Spreadsheet/CMakeLists.txt b/Applications/Spreadsheet/CMakeLists.txt
deleted file mode 100644
index f41922655a..0000000000
--- a/Applications/Spreadsheet/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-compile_gml(CondFormatting.gml CondFormattingGML.h cond_fmt_gml)
-compile_gml(CondView.gml CondFormattingViewGML.h cond_fmt_view_gml)
-
-set(SOURCES
- Cell.cpp
- CellSyntaxHighlighter.cpp
- CellType/Date.cpp
- CellType/Format.cpp
- CellType/Identity.cpp
- CellType/Numeric.cpp
- CellType/String.cpp
- CellType/Type.cpp
- CellTypeDialog.cpp
- CondFormattingGML.h
- CondFormattingViewGML.h
- HelpWindow.cpp
- JSIntegration.cpp
- Readers/XSV.cpp
- Spreadsheet.cpp
- SpreadsheetModel.cpp
- SpreadsheetView.cpp
- SpreadsheetWidget.cpp
- Workbook.cpp
- main.cpp
-)
-
-serenity_app(Spreadsheet ICON app-spreadsheet)
-target_link_libraries(Spreadsheet LibGUI LibJS LibWeb)
diff --git a/Applications/Spreadsheet/Cell.cpp b/Applications/Spreadsheet/Cell.cpp
deleted file mode 100644
index d2f511753f..0000000000
--- a/Applications/Spreadsheet/Cell.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Cell.h"
-#include "Spreadsheet.h"
-#include <AK/StringBuilder.h>
-#include <AK/TemporaryChange.h>
-
-namespace Spreadsheet {
-
-void Cell::set_data(String new_data)
-{
- if (m_data == new_data)
- return;
-
- if (new_data.starts_with("=")) {
- new_data = new_data.substring(1, new_data.length() - 1);
- m_kind = Formula;
- } else {
- m_kind = LiteralString;
- }
-
- m_data = move(new_data);
- m_dirty = true;
- m_evaluated_externally = false;
-}
-
-void Cell::set_data(JS::Value new_data)
-{
- m_dirty = true;
- m_evaluated_externally = true;
-
- StringBuilder builder;
-
- builder.append(new_data.to_string_without_side_effects());
- m_data = builder.build();
-
- m_evaluated_data = move(new_data);
-}
-
-void Cell::set_type(const CellType* type)
-{
- m_type = type;
-}
-
-void Cell::set_type(const StringView& name)
-{
- auto* cell_type = CellType::get_by_name(name);
- if (cell_type) {
- return set_type(cell_type);
- }
-
- ASSERT_NOT_REACHED();
-}
-
-void Cell::set_type_metadata(CellTypeMetadata&& metadata)
-{
- m_type_metadata = move(metadata);
-}
-
-const CellType& Cell::type() const
-{
- if (m_type)
- return *m_type;
-
- if (m_kind == LiteralString) {
- if (m_data.to_int().has_value())
- return *CellType::get_by_name("Numeric");
- }
-
- return *CellType::get_by_name("Identity");
-}
-
-String Cell::typed_display() const
-{
- return type().display(const_cast<Cell&>(*this), m_type_metadata);
-}
-
-JS::Value Cell::typed_js_data() const
-{
- return type().js_value(const_cast<Cell&>(*this), m_type_metadata);
-}
-
-void Cell::update_data(Badge<Sheet>)
-{
- TemporaryChange cell_change { m_sheet->current_evaluated_cell(), this };
- if (!m_dirty)
- return;
-
- m_js_exception = {};
-
- if (m_dirty) {
- m_dirty = false;
- if (m_kind == Formula) {
- if (!m_evaluated_externally) {
- auto [value, exception] = m_sheet->evaluate(m_data, this);
- m_evaluated_data = value;
- m_js_exception = move(exception);
- }
- }
-
- for (auto& ref : m_referencing_cells) {
- if (ref) {
- ref->m_dirty = true;
- ref->update();
- }
- }
- }
-
- m_evaluated_formats.background_color.clear();
- m_evaluated_formats.foreground_color.clear();
- if (!m_js_exception) {
- StringBuilder builder;
- for (auto& fmt : m_conditional_formats) {
- if (!fmt.condition.is_empty()) {
- builder.clear();
- builder.append("return (");
- builder.append(fmt.condition);
- builder.append(')');
- auto [value, exception] = m_sheet->evaluate(builder.string_view(), this);
- if (exception) {
- m_js_exception = move(exception);
- } else {
- if (value.to_boolean()) {
- if (fmt.background_color.has_value())
- m_evaluated_formats.background_color = fmt.background_color;
- if (fmt.foreground_color.has_value())
- m_evaluated_formats.foreground_color = fmt.foreground_color;
- }
- }
- }
- }
- }
-}
-
-void Cell::update()
-{
- m_sheet->update(*this);
-}
-
-JS::Value Cell::js_data()
-{
- if (m_dirty)
- update();
-
- if (m_kind == Formula)
- return m_evaluated_data;
-
- return JS::js_string(m_sheet->interpreter().heap(), m_data);
-}
-
-String Cell::source() const
-{
- StringBuilder builder;
- if (m_kind == Formula)
- builder.append('=');
- builder.append(m_data);
- return builder.to_string();
-}
-
-// FIXME: Find a better way to figure out dependencies
-void Cell::reference_from(Cell* other)
-{
- if (!other || other == this)
- return;
-
- if (!m_referencing_cells.find_if([other](const auto& ptr) { return ptr.ptr() == other; }).is_end())
- return;
-
- m_referencing_cells.append(other->make_weak_ptr());
-}
-
-void Cell::copy_from(const Cell& other)
-{
- m_dirty = true;
- m_evaluated_externally = other.m_evaluated_externally;
- m_data = other.m_data;
- m_evaluated_data = other.m_evaluated_data;
- m_kind = other.m_kind;
- m_type = other.m_type;
- m_type_metadata = other.m_type_metadata;
- m_conditional_formats = other.m_conditional_formats;
- m_evaluated_formats = other.m_evaluated_formats;
- if (!other.m_js_exception)
- m_js_exception = other.m_js_exception;
-}
-
-}
diff --git a/Applications/Spreadsheet/Cell.h b/Applications/Spreadsheet/Cell.h
deleted file mode 100644
index fef9031d5e..0000000000
--- a/Applications/Spreadsheet/Cell.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "CellType/Type.h"
-#include "ConditionalFormatting.h"
-#include "Forward.h"
-#include "JSIntegration.h"
-#include "Position.h"
-#include <AK/String.h>
-#include <AK/Types.h>
-#include <AK/WeakPtr.h>
-
-namespace Spreadsheet {
-
-struct Cell : public Weakable<Cell> {
- enum Kind {
- LiteralString,
- Formula,
- };
-
- Cell(String data, Position position, WeakPtr<Sheet> sheet)
- : m_dirty(false)
- , m_data(move(data))
- , m_kind(LiteralString)
- , m_sheet(sheet)
- , m_position(move(position))
- {
- }
-
- Cell(String source, JS::Value&& cell_value, Position position, WeakPtr<Sheet> sheet)
- : m_dirty(false)
- , m_data(move(source))
- , m_evaluated_data(move(cell_value))
- , m_kind(Formula)
- , m_sheet(sheet)
- , m_position(move(position))
- {
- }
-
- void reference_from(Cell*);
-
- void set_data(String new_data);
- void set_data(JS::Value new_data);
- bool dirty() const { return m_dirty; }
- void clear_dirty() { m_dirty = false; }
-
- void set_exception(JS::Exception* exc) { m_js_exception = exc; }
- JS::Exception* exception() const { return m_js_exception; }
-
- const String& data() const { return m_data; }
- const JS::Value& evaluated_data() const { return m_evaluated_data; }
- Kind kind() const { return m_kind; }
- const Vector<WeakPtr<Cell>>& referencing_cells() const { return m_referencing_cells; }
-
- void set_type(const StringView& name);
- void set_type(const CellType*);
- void set_type_metadata(CellTypeMetadata&&);
-
- const Position& position() const { return m_position; }
- void set_position(Position position, Badge<Sheet>)
- {
- if (position != m_position) {
- m_dirty = true;
- m_position = move(position);
- }
- }
-
- const Format& evaluated_formats() const { return m_evaluated_formats; }
- Format& evaluated_formats() { return m_evaluated_formats; }
- const Vector<ConditionalFormat>& conditional_formats() const { return m_conditional_formats; }
- void set_conditional_formats(Vector<ConditionalFormat>&& fmts)
- {
- m_dirty = true;
- m_conditional_formats = move(fmts);
- }
-
- String typed_display() const;
- JS::Value typed_js_data() const;
-
- const CellType& type() const;
- const CellTypeMetadata& type_metadata() const { return m_type_metadata; }
- CellTypeMetadata& type_metadata() { return m_type_metadata; }
-
- String source() const;
-
- JS::Value js_data();
-
- void update();
- void update_data(Badge<Sheet>);
-
- const Sheet& sheet() const { return *m_sheet; }
- Sheet& sheet() { return *m_sheet; }
-
- void copy_from(const Cell&);
-
-private:
- bool m_dirty { false };
- bool m_evaluated_externally { false };
- String m_data;
- JS::Value m_evaluated_data;
- JS::Exception* m_js_exception { nullptr };
- Kind m_kind { LiteralString };
- WeakPtr<Sheet> m_sheet;
- Vector<WeakPtr<Cell>> m_referencing_cells;
- const CellType* m_type { nullptr };
- CellTypeMetadata m_type_metadata;
- Position m_position;
-
- Vector<ConditionalFormat> m_conditional_formats;
- Format m_evaluated_formats;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellSyntaxHighlighter.cpp b/Applications/Spreadsheet/CellSyntaxHighlighter.cpp
deleted file mode 100644
index c26d2aa238..0000000000
--- a/Applications/Spreadsheet/CellSyntaxHighlighter.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CellSyntaxHighlighter.h"
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGfx/Palette.h>
-#include <LibJS/Lexer.h>
-
-namespace Spreadsheet {
-
-void CellSyntaxHighlighter::rehighlight(Gfx::Palette palette)
-{
- ASSERT(m_editor);
- auto text = m_editor->text();
- m_editor->document().spans().clear();
- if (!text.starts_with('=')) {
- m_editor->update();
- return;
- }
-
- JSSyntaxHighlighter::rehighlight(palette);
-
- // Highlight the '='
- m_editor->document().spans().empend(
- GUI::TextRange { { 0, 0 }, { 0, 1 } },
- Gfx::TextAttributes {
- palette.syntax_keyword(),
- Optional<Color> {},
- false,
- false,
- },
- nullptr,
- false);
-
- if (m_cell && m_cell->exception()) {
- auto range = m_cell->exception()->source_ranges().first();
- GUI::TextRange text_range { { range.start.line - 1, range.start.column }, { range.end.line - 1, range.end.column - 1 } };
- m_editor->document().spans().prepend(
- GUI::TextDocumentSpan {
- text_range,
- Gfx::TextAttributes {
- Color::Black,
- Color::Red,
- false,
- false,
- },
- nullptr,
- false });
- }
- m_editor->update();
-}
-
-CellSyntaxHighlighter::~CellSyntaxHighlighter()
-{
-}
-
-}
diff --git a/Applications/Spreadsheet/CellSyntaxHighlighter.h b/Applications/Spreadsheet/CellSyntaxHighlighter.h
deleted file mode 100644
index f02f7e2bbb..0000000000
--- a/Applications/Spreadsheet/CellSyntaxHighlighter.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Cell.h"
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/SyntaxHighlighter.h>
-
-namespace Spreadsheet {
-
-class CellSyntaxHighlighter final : public GUI::JSSyntaxHighlighter {
-public:
- CellSyntaxHighlighter() { }
- virtual ~CellSyntaxHighlighter() override;
-
- virtual void rehighlight(Gfx::Palette) override;
- void set_cell(const Cell* cell) { m_cell = cell; }
-
-private:
- const Cell* m_cell { nullptr };
-};
-
-}
diff --git a/Applications/Spreadsheet/CellType/Date.cpp b/Applications/Spreadsheet/CellType/Date.cpp
deleted file mode 100644
index 005620006f..0000000000
--- a/Applications/Spreadsheet/CellType/Date.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Date.h"
-#include "../Cell.h"
-#include "../Spreadsheet.h"
-#include <AK/ScopeGuard.h>
-#include <LibCore/DateTime.h>
-
-namespace Spreadsheet {
-
-DateCell::DateCell()
- : CellType("Date")
-{
-}
-
-DateCell::~DateCell()
-{
-}
-
-String DateCell::display(Cell& cell, const CellTypeMetadata& metadata) const
-{
- ScopeGuard propagate_exception { [&cell] {
- if (auto exc = cell.sheet().interpreter().exception()) {
- cell.sheet().interpreter().vm().clear_exception();
- cell.set_exception(exc);
- }
- } };
- auto timestamp = js_value(cell, metadata);
- auto string = Core::DateTime::from_timestamp(timestamp.to_i32(cell.sheet().global_object())).to_string(metadata.format.is_empty() ? "%Y-%m-%d %H:%M:%S" : metadata.format.characters());
-
- if (metadata.length >= 0)
- return string.substring(0, metadata.length);
-
- return string;
-}
-
-JS::Value DateCell::js_value(Cell& cell, const CellTypeMetadata&) const
-{
- auto js_data = cell.js_data();
- auto value = js_data.to_double(cell.sheet().global_object());
- return JS::Value(value / 1000); // Turn it to seconds
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/Date.h b/Applications/Spreadsheet/CellType/Date.h
deleted file mode 100644
index 3221fad0f1..0000000000
--- a/Applications/Spreadsheet/CellType/Date.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Type.h"
-
-namespace Spreadsheet {
-
-class DateCell : public CellType {
-
-public:
- DateCell();
- virtual ~DateCell() override;
- virtual String display(Cell&, const CellTypeMetadata&) const override;
- virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellType/Format.cpp b/Applications/Spreadsheet/CellType/Format.cpp
deleted file mode 100644
index d7c590a550..0000000000
--- a/Applications/Spreadsheet/CellType/Format.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Format.h"
-#include <AK/PrintfImplementation.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-
-namespace Spreadsheet {
-
-template<typename T, typename V>
-struct SingleEntryListNext {
- ALWAYS_INLINE T operator()(V value) const
- {
- return (T)value;
- }
-};
-
-template<typename PutChFunc, typename ArgumentListRefT, template<typename T, typename U = ArgumentListRefT> typename NextArgument>
-struct PrintfImpl : public PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument> {
- ALWAYS_INLINE PrintfImpl(PutChFunc& putch, char*& bufptr, const int& nwritten)
- : PrintfImplementation::PrintfImpl<PutChFunc, ArgumentListRefT, NextArgument>(putch, bufptr, nwritten)
- {
- }
-
- // Disallow pointer formats.
- ALWAYS_INLINE int format_n(const PrintfImplementation::ModifierState&, ArgumentListRefT&) const
- {
- return 0;
- }
- ALWAYS_INLINE int format_s(const PrintfImplementation::ModifierState&, ArgumentListRefT&) const
- {
- return 0;
- }
-};
-
-String format_double(const char* format, double value)
-{
- StringBuilder builder;
- auto putch = [&](auto, auto ch) { builder.append(ch); };
- printf_internal<decltype(putch), PrintfImpl, double, SingleEntryListNext>(putch, nullptr, format, value);
-
- return builder.build();
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/Format.h b/Applications/Spreadsheet/CellType/Format.h
deleted file mode 100644
index 98f3cdc741..0000000000
--- a/Applications/Spreadsheet/CellType/Format.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Forward.h>
-
-namespace Spreadsheet {
-
-String format_double(const char* format, double value);
-
-}
diff --git a/Applications/Spreadsheet/CellType/Identity.cpp b/Applications/Spreadsheet/CellType/Identity.cpp
deleted file mode 100644
index eed7cb190c..0000000000
--- a/Applications/Spreadsheet/CellType/Identity.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Identity.h"
-#include "../Cell.h"
-#include "../Spreadsheet.h"
-
-namespace Spreadsheet {
-
-IdentityCell::IdentityCell()
- : CellType("Identity")
-{
-}
-
-IdentityCell::~IdentityCell()
-{
-}
-
-String IdentityCell::display(Cell& cell, const CellTypeMetadata&) const
-{
- return cell.js_data().to_string_without_side_effects();
-}
-
-JS::Value IdentityCell::js_value(Cell& cell, const CellTypeMetadata&) const
-{
- return cell.js_data();
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/Identity.h b/Applications/Spreadsheet/CellType/Identity.h
deleted file mode 100644
index 09089153ec..0000000000
--- a/Applications/Spreadsheet/CellType/Identity.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Type.h"
-
-namespace Spreadsheet {
-
-class IdentityCell : public CellType {
-
-public:
- IdentityCell();
- virtual ~IdentityCell() override;
- virtual String display(Cell&, const CellTypeMetadata&) const override;
- virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellType/Numeric.cpp b/Applications/Spreadsheet/CellType/Numeric.cpp
deleted file mode 100644
index d58d48cd85..0000000000
--- a/Applications/Spreadsheet/CellType/Numeric.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Numeric.h"
-#include "../Cell.h"
-#include "../Spreadsheet.h"
-#include "Format.h"
-#include <AK/ScopeGuard.h>
-
-namespace Spreadsheet {
-
-NumericCell::NumericCell()
- : CellType("Numeric")
-{
-}
-
-NumericCell::~NumericCell()
-{
-}
-
-String NumericCell::display(Cell& cell, const CellTypeMetadata& metadata) const
-{
- ScopeGuard propagate_exception { [&cell] {
- if (auto exc = cell.sheet().interpreter().exception()) {
- cell.sheet().interpreter().vm().clear_exception();
- cell.set_exception(exc);
- }
- } };
- auto value = js_value(cell, metadata);
- String string;
- if (metadata.format.is_empty())
- string = value.to_string_without_side_effects();
- else
- string = format_double(metadata.format.characters(), value.to_double(cell.sheet().global_object()));
-
- if (metadata.length >= 0)
- return string.substring(0, metadata.length);
-
- return string;
-}
-
-JS::Value NumericCell::js_value(Cell& cell, const CellTypeMetadata&) const
-{
- ScopeGuard propagate_exception { [&cell] {
- if (auto exc = cell.sheet().interpreter().exception()) {
- cell.sheet().interpreter().vm().clear_exception();
- cell.set_exception(exc);
- }
- } };
- return cell.js_data().to_number(cell.sheet().global_object());
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/Numeric.h b/Applications/Spreadsheet/CellType/Numeric.h
deleted file mode 100644
index e0cd4a295a..0000000000
--- a/Applications/Spreadsheet/CellType/Numeric.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Type.h"
-
-namespace Spreadsheet {
-
-class NumericCell : public CellType {
-
-public:
- NumericCell();
- virtual ~NumericCell() override;
- virtual String display(Cell&, const CellTypeMetadata&) const override;
- virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellType/String.cpp b/Applications/Spreadsheet/CellType/String.cpp
deleted file mode 100644
index ccda9947fe..0000000000
--- a/Applications/Spreadsheet/CellType/String.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "String.h"
-#include "../Cell.h"
-#include "../Spreadsheet.h"
-
-namespace Spreadsheet {
-
-StringCell::StringCell()
- : CellType("String")
-{
-}
-
-StringCell::~StringCell()
-{
-}
-
-String StringCell::display(Cell& cell, const CellTypeMetadata& metadata) const
-{
- auto string = cell.js_data().to_string_without_side_effects();
- if (metadata.length >= 0)
- return string.substring(0, metadata.length);
-
- return string;
-}
-
-JS::Value StringCell::js_value(Cell& cell, const CellTypeMetadata& metadata) const
-{
- auto string = display(cell, metadata);
- return JS::js_string(cell.sheet().interpreter().heap(), string);
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/String.h b/Applications/Spreadsheet/CellType/String.h
deleted file mode 100644
index e4ba28eb24..0000000000
--- a/Applications/Spreadsheet/CellType/String.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Type.h"
-
-namespace Spreadsheet {
-
-class StringCell : public CellType {
-
-public:
- StringCell();
- virtual ~StringCell() override;
- virtual String display(Cell&, const CellTypeMetadata&) const override;
- virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const override;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellType/Type.cpp b/Applications/Spreadsheet/CellType/Type.cpp
deleted file mode 100644
index cd64e8f239..0000000000
--- a/Applications/Spreadsheet/CellType/Type.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Type.h"
-#include "Date.h"
-#include "Identity.h"
-#include "Numeric.h"
-#include "String.h"
-#include <AK/HashMap.h>
-#include <AK/OwnPtr.h>
-
-static HashMap<String, Spreadsheet::CellType*> s_cell_types;
-static Spreadsheet::StringCell s_string_cell;
-static Spreadsheet::NumericCell s_numeric_cell;
-static Spreadsheet::IdentityCell s_identity_cell;
-static Spreadsheet::DateCell s_date_cell;
-
-namespace Spreadsheet {
-
-const CellType* CellType::get_by_name(const StringView& name)
-{
- return s_cell_types.get(name).value_or(nullptr);
-}
-
-Vector<StringView> CellType::names()
-{
- Vector<StringView> names;
- for (auto& it : s_cell_types)
- names.append(it.key);
- return names;
-}
-
-CellType::CellType(const StringView& name)
- : m_name(name)
-{
- ASSERT(!s_cell_types.contains(name));
- s_cell_types.set(name, this);
-}
-
-}
diff --git a/Applications/Spreadsheet/CellType/Type.h b/Applications/Spreadsheet/CellType/Type.h
deleted file mode 100644
index 0145a8fa8d..0000000000
--- a/Applications/Spreadsheet/CellType/Type.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "../ConditionalFormatting.h"
-#include "../Forward.h"
-#include <AK/Forward.h>
-#include <AK/String.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/TextAlignment.h>
-#include <LibJS/Forward.h>
-
-namespace Spreadsheet {
-
-struct CellTypeMetadata {
- int length { -1 };
- String format;
- Gfx::TextAlignment alignment { Gfx::TextAlignment::CenterRight };
- Format static_format;
-};
-
-class CellType {
-public:
- static const CellType* get_by_name(const StringView&);
- static Vector<StringView> names();
-
- virtual String display(Cell&, const CellTypeMetadata&) const = 0;
- virtual JS::Value js_value(Cell&, const CellTypeMetadata&) const = 0;
- virtual ~CellType() { }
-
- const String& name() const { return m_name; }
-
-protected:
- CellType(const StringView& name);
-
-private:
- String m_name;
-};
-
-}
diff --git a/Applications/Spreadsheet/CellTypeDialog.cpp b/Applications/Spreadsheet/CellTypeDialog.cpp
deleted file mode 100644
index b94feab5e5..0000000000
--- a/Applications/Spreadsheet/CellTypeDialog.cpp
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "CellTypeDialog.h"
-#include "Cell.h"
-#include "Spreadsheet.h"
-#include <AK/StringBuilder.h>
-#include <Applications/Spreadsheet/CondFormattingGML.h>
-#include <Applications/Spreadsheet/CondFormattingViewGML.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/ColorInput.h>
-#include <LibGUI/ComboBox.h>
-#include <LibGUI/ItemListModel.h>
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/ListView.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Widget.h>
-#include <LibGfx/FontDatabase.h>
-
-REGISTER_WIDGET(Spreadsheet, ConditionsView);
-
-namespace Spreadsheet {
-
-CellTypeDialog::CellTypeDialog(const Vector<Position>& positions, Sheet& sheet, GUI::Window* parent)
- : GUI::Dialog(parent)
-{
- ASSERT(!positions.is_empty());
-
- StringBuilder builder;
-
- if (positions.size() == 1)
- builder.appendff("Format cell {}{}", positions.first().column, positions.first().row);
- else
- builder.appendff("Format {} cells", positions.size());
-
- set_title(builder.string_view());
- set_icon(parent->icon());
- resize(285, 360);
-
- auto& main_widget = set_main_widget<GUI::Widget>();
- main_widget.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
- main_widget.set_fill_with_background_color(true);
-
- auto& tab_widget = main_widget.add<GUI::TabWidget>();
- setup_tabs(tab_widget, positions, sheet);
-
- auto& buttonbox = main_widget.add<GUI::Widget>();
- buttonbox.set_shrink_to_fit(true);
- auto& button_layout = buttonbox.set_layout<GUI::HorizontalBoxLayout>();
- button_layout.set_spacing(10);
- button_layout.add_spacer();
- auto& ok_button = buttonbox.add<GUI::Button>("OK");
- ok_button.set_fixed_width(80);
- ok_button.on_click = [&](auto) { done(ExecOK); };
-}
-
-const Vector<String> g_horizontal_alignments { "Left", "Center", "Right" };
-const Vector<String> g_vertical_alignments { "Top", "Center", "Bottom" };
-Vector<String> g_types;
-
-constexpr static CellTypeDialog::VerticalAlignment vertical_alignment_from(Gfx::TextAlignment alignment)
-{
- switch (alignment) {
- case Gfx::TextAlignment::CenterRight:
- case Gfx::TextAlignment::CenterLeft:
- case Gfx::TextAlignment::Center:
- return CellTypeDialog::VerticalAlignment::Center;
-
- case Gfx::TextAlignment::TopRight:
- case Gfx::TextAlignment::TopLeft:
- return CellTypeDialog::VerticalAlignment::Top;
-
- case Gfx::TextAlignment::BottomRight:
- return CellTypeDialog::VerticalAlignment::Bottom;
- }
-
- return CellTypeDialog::VerticalAlignment::Center;
-}
-
-constexpr static CellTypeDialog::HorizontalAlignment horizontal_alignment_from(Gfx::TextAlignment alignment)
-{
- switch (alignment) {
- case Gfx::TextAlignment::Center:
- return CellTypeDialog::HorizontalAlignment::Center;
-
- case Gfx::TextAlignment::CenterRight:
- case Gfx::TextAlignment::TopRight:
- case Gfx::TextAlignment::BottomRight:
- return CellTypeDialog::HorizontalAlignment::Right;
-
- case Gfx::TextAlignment::TopLeft:
- case Gfx::TextAlignment::CenterLeft:
- return CellTypeDialog::HorizontalAlignment::Left;
- }
-
- return CellTypeDialog::HorizontalAlignment::Right;
-}
-
-void CellTypeDialog::setup_tabs(GUI::TabWidget& tabs, const Vector<Position>& positions, Sheet& sheet)
-{
- g_types.clear();
- for (auto& type_name : CellType::names())
- g_types.append(type_name);
-
- Vector<Cell*> cells;
- for (auto& position : positions) {
- if (auto cell = sheet.at(position))
- cells.append(cell);
- }
-
- if (cells.size() == 1) {
- auto& cell = *cells.first();
- m_format = cell.type_metadata().format;
- m_length = cell.type_metadata().length;
- m_type = &cell.type();
- m_vertical_alignment = vertical_alignment_from(cell.type_metadata().alignment);
- m_horizontal_alignment = horizontal_alignment_from(cell.type_metadata().alignment);
- m_static_format = cell.type_metadata().static_format;
- m_conditional_formats = cell.conditional_formats();
- }
-
- auto& type_tab = tabs.add_tab<GUI::Widget>("Type");
- type_tab.set_layout<GUI::HorizontalBoxLayout>().set_margins({ 4, 4, 4, 4 });
- {
- auto& left_side = type_tab.add<GUI::Widget>();
- left_side.set_layout<GUI::VerticalBoxLayout>();
- auto& right_side = type_tab.add<GUI::Widget>();
- right_side.set_layout<GUI::VerticalBoxLayout>();
- right_side.set_fixed_width(170);
-
- auto& type_list = left_side.add<GUI::ListView>();
- type_list.set_model(*GUI::ItemListModel<String>::create(g_types));
- type_list.set_should_hide_unnecessary_scrollbars(true);
- type_list.on_selection = [&](auto& index) {
- if (!index.is_valid()) {
- m_type = nullptr;
- return;
- }
-
- m_type = CellType::get_by_name(g_types.at(index.row()));
- };
-
- {
- auto& checkbox = right_side.add<GUI::CheckBox>("Override max length");
- auto& spinbox = right_side.add<GUI::SpinBox>();
- checkbox.set_checked(m_length != -1);
- spinbox.set_min(0);
- spinbox.set_enabled(m_length != -1);
- if (m_length > -1)
- spinbox.set_value(m_length);
-
- checkbox.on_checked = [&](auto checked) {
- spinbox.set_enabled(checked);
- if (!checked) {
- m_length = -1;
- spinbox.set_value(0);
- }
- };
- spinbox.on_change = [&](auto value) {
- m_length = value;
- };
- }
- {
- auto& checkbox = right_side.add<GUI::CheckBox>("Override display format");
- auto& editor = right_side.add<GUI::TextEditor>();
- checkbox.set_checked(!m_format.is_empty());
- editor.set_should_hide_unnecessary_scrollbars(true);
- editor.set_enabled(!m_format.is_empty());
- editor.set_text(m_format);
-
- checkbox.on_checked = [&](auto checked) {
- editor.set_enabled(checked);
- if (!checked)
- m_format = String::empty();
- editor.set_text(m_format);
- };
- editor.on_change = [&] {
- m_format = editor.text();
- };
- }
- }
-
- auto& alignment_tab = tabs.add_tab<GUI::Widget>("Alignment");
- alignment_tab.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
- {
- // FIXME: Frame?
- // Horizontal alignment
- {
- auto& horizontal_alignment_selection_container = alignment_tab.add<GUI::Widget>();
- horizontal_alignment_selection_container.set_layout<GUI::HorizontalBoxLayout>();
- horizontal_alignment_selection_container.layout()->set_margins({ 0, 4, 0, 0 });
- horizontal_alignment_selection_container.set_fixed_height(22);
-
- auto& horizontal_alignment_label = horizontal_alignment_selection_container.add<GUI::Label>();
- horizontal_alignment_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- horizontal_alignment_label.set_text("Horizontal text alignment");
-
- auto& horizontal_combobox = alignment_tab.add<GUI::ComboBox>();
- horizontal_combobox.set_only_allow_values_from_model(true);
- horizontal_combobox.set_model(*GUI::ItemListModel<String>::create(g_horizontal_alignments));
- horizontal_combobox.set_selected_index((int)m_horizontal_alignment);
- horizontal_combobox.on_change = [&](auto&, const GUI::ModelIndex& index) {
- switch (index.row()) {
- case 0:
- m_horizontal_alignment = HorizontalAlignment::Left;
- break;
- case 1:
- m_horizontal_alignment = HorizontalAlignment::Center;
- break;
- case 2:
- m_horizontal_alignment = HorizontalAlignment::Right;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- };
- }
-
- // Vertical alignment
- {
- auto& vertical_alignment_container = alignment_tab.add<GUI::Widget>();
- vertical_alignment_container.set_layout<GUI::HorizontalBoxLayout>();
- vertical_alignment_container.layout()->set_margins({ 0, 4, 0, 0 });
- vertical_alignment_container.set_fixed_height(22);
-
- auto& vertical_alignment_label = vertical_alignment_container.add<GUI::Label>();
- vertical_alignment_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- vertical_alignment_label.set_text("Vertical text alignment");
-
- auto& vertical_combobox = alignment_tab.add<GUI::ComboBox>();
- vertical_combobox.set_only_allow_values_from_model(true);
- vertical_combobox.set_model(*GUI::ItemListModel<String>::create(g_vertical_alignments));
- vertical_combobox.set_selected_index((int)m_vertical_alignment);
- vertical_combobox.on_change = [&](auto&, const GUI::ModelIndex& index) {
- switch (index.row()) {
- case 0:
- m_vertical_alignment = VerticalAlignment::Top;
- break;
- case 1:
- m_vertical_alignment = VerticalAlignment::Center;
- break;
- case 2:
- m_vertical_alignment = VerticalAlignment::Bottom;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
- };
- }
- }
-
- auto& colors_tab = tabs.add_tab<GUI::Widget>("Color");
- colors_tab.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
- {
- // Static formatting
- {
- auto& static_formatting_container = colors_tab.add<GUI::Widget>();
- static_formatting_container.set_layout<GUI::VerticalBoxLayout>();
- static_formatting_container.set_shrink_to_fit(true);
-
- // Foreground
- {
- // FIXME: Somehow allow unsetting these.
- auto& foreground_container = static_formatting_container.add<GUI::Widget>();
- foreground_container.set_layout<GUI::HorizontalBoxLayout>();
- foreground_container.layout()->set_margins({ 0, 4, 0, 0 });
- foreground_container.set_fixed_height(22);
-
- auto& foreground_label = foreground_container.add<GUI::Label>();
- foreground_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- foreground_label.set_text("Static foreground color");
-
- auto& foreground_selector = foreground_container.add<GUI::ColorInput>();
- if (m_static_format.foreground_color.has_value())
- foreground_selector.set_color(m_static_format.foreground_color.value());
- foreground_selector.on_change = [&]() {
- m_static_format.foreground_color = foreground_selector.color();
- };
- }
-
- // Background
- {
- // FIXME: Somehow allow unsetting these.
- auto& background_container = static_formatting_container.add<GUI::Widget>();
- background_container.set_layout<GUI::HorizontalBoxLayout>();
- background_container.layout()->set_margins({ 0, 4, 0, 0 });
- background_container.set_fixed_height(22);
-
- auto& background_label = background_container.add<GUI::Label>();
- background_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- background_label.set_text("Static background color");
-
- auto& background_selector = background_container.add<GUI::ColorInput>();
- if (m_static_format.background_color.has_value())
- background_selector.set_color(m_static_format.background_color.value());
- background_selector.on_change = [&]() {
- m_static_format.background_color = background_selector.color();
- };
- }
- }
- }
-
- auto& conditional_fmt_tab = tabs.add_tab<GUI::Widget>("Conditional format");
- conditional_fmt_tab.load_from_gml(cond_fmt_gml);
- {
- auto& view = *conditional_fmt_tab.find_descendant_of_type_named<Spreadsheet::ConditionsView>("conditions_view");
- view.set_formats(&m_conditional_formats);
-
- auto& add_button = *conditional_fmt_tab.find_descendant_of_type_named<GUI::Button>("add_button");
- add_button.on_click = [&](auto) {
- view.add_format();
- };
-
- // FIXME: Disable this when empty.
- auto& remove_button = *conditional_fmt_tab.find_descendant_of_type_named<GUI::Button>("remove_button");
- remove_button.on_click = [&](auto) {
- view.remove_top();
- };
- }
-}
-
-CellTypeMetadata CellTypeDialog::metadata() const
-{
- CellTypeMetadata metadata;
- metadata.format = m_format;
- metadata.length = m_length;
- metadata.static_format = m_static_format;
-
- switch (m_vertical_alignment) {
- case VerticalAlignment::Top:
- switch (m_horizontal_alignment) {
- case HorizontalAlignment::Left:
- metadata.alignment = Gfx::TextAlignment::TopLeft;
- break;
- case HorizontalAlignment::Center:
- metadata.alignment = Gfx::TextAlignment::Center; // TopCenter?
- break;
- case HorizontalAlignment::Right:
- metadata.alignment = Gfx::TextAlignment::TopRight;
- break;
- }
- break;
- case VerticalAlignment::Center:
- switch (m_horizontal_alignment) {
- case HorizontalAlignment::Left:
- metadata.alignment = Gfx::TextAlignment::CenterLeft;
- break;
- case HorizontalAlignment::Center:
- metadata.alignment = Gfx::TextAlignment::Center;
- break;
- case HorizontalAlignment::Right:
- metadata.alignment = Gfx::TextAlignment::CenterRight;
- break;
- }
- break;
- case VerticalAlignment::Bottom:
- switch (m_horizontal_alignment) {
- case HorizontalAlignment::Left:
- metadata.alignment = Gfx::TextAlignment::CenterLeft; // BottomLeft?
- break;
- case HorizontalAlignment::Center:
- metadata.alignment = Gfx::TextAlignment::Center;
- break;
- case HorizontalAlignment::Right:
- metadata.alignment = Gfx::TextAlignment::BottomRight;
- break;
- }
- break;
- }
-
- return metadata;
-}
-
-ConditionView::ConditionView(ConditionalFormat& fmt)
- : m_format(fmt)
-{
- load_from_gml(cond_fmt_view_gml);
-
- auto& fg_input = *find_descendant_of_type_named<GUI::ColorInput>("foreground_input");
- auto& bg_input = *find_descendant_of_type_named<GUI::ColorInput>("background_input");
- auto& formula_editor = *find_descendant_of_type_named<GUI::TextEditor>("formula_editor");
-
- if (m_format.foreground_color.has_value())
- fg_input.set_color(m_format.foreground_color.value());
-
- if (m_format.background_color.has_value())
- bg_input.set_color(m_format.background_color.value());
-
- formula_editor.set_text(m_format.condition);
-
- // FIXME: Allow unsetting these.
- fg_input.on_change = [&] {
- m_format.foreground_color = fg_input.color();
- };
-
- bg_input.on_change = [&] {
- m_format.background_color = bg_input.color();
- };
-
- formula_editor.set_syntax_highlighter(make<GUI::JSSyntaxHighlighter>());
- formula_editor.set_should_hide_unnecessary_scrollbars(true);
- formula_editor.set_font(&Gfx::FontDatabase::default_fixed_width_font());
- formula_editor.on_change = [&] {
- m_format.condition = formula_editor.text();
- };
-}
-
-ConditionView::~ConditionView()
-{
-}
-
-ConditionsView::ConditionsView()
-{
- set_layout<GUI::VerticalBoxLayout>().set_spacing(2);
-}
-
-void ConditionsView::set_formats(Vector<ConditionalFormat>* formats)
-{
- ASSERT(!m_formats);
-
- m_formats = formats;
-
- for (auto& entry : *m_formats)
- m_widgets.append(add<ConditionView>(entry));
-}
-
-void ConditionsView::add_format()
-{
- ASSERT(m_formats);
-
- m_formats->empend();
- auto& last = m_formats->last();
-
- m_widgets.append(add<ConditionView>(last));
-
- update();
-}
-
-void ConditionsView::remove_top()
-{
- ASSERT(m_formats);
-
- if (m_formats->is_empty())
- return;
-
- m_formats->take_last();
- m_widgets.take_last()->remove_from_parent();
- update();
-}
-
-ConditionsView::~ConditionsView()
-{
-}
-
-}
diff --git a/Applications/Spreadsheet/CellTypeDialog.h b/Applications/Spreadsheet/CellTypeDialog.h
deleted file mode 100644
index ede19ebd51..0000000000
--- a/Applications/Spreadsheet/CellTypeDialog.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "CellType/Type.h"
-#include "ConditionalFormatting.h"
-#include "Forward.h"
-#include <LibGUI/Dialog.h>
-
-namespace Spreadsheet {
-
-class CellTypeDialog : public GUI::Dialog {
- C_OBJECT(CellTypeDialog);
-
-public:
- CellTypeMetadata metadata() const;
- const CellType* type() const { return m_type; }
- Vector<ConditionalFormat> conditional_formats() { return m_conditional_formats; }
-
- enum class HorizontalAlignment : int {
- Left = 0,
- Center,
- Right,
- };
- enum class VerticalAlignment : int {
- Top = 0,
- Center,
- Bottom,
- };
-
-private:
- CellTypeDialog(const Vector<Position>&, Sheet&, GUI::Window* parent = nullptr);
- void setup_tabs(GUI::TabWidget&, const Vector<Position>&, Sheet&);
-
- const CellType* m_type { nullptr };
-
- int m_length { -1 };
- String m_format;
- HorizontalAlignment m_horizontal_alignment { HorizontalAlignment::Right };
- VerticalAlignment m_vertical_alignment { VerticalAlignment::Center };
- Format m_static_format;
- Vector<ConditionalFormat> m_conditional_formats;
-};
-
-}
diff --git a/Applications/Spreadsheet/CondFormatting.gml b/Applications/Spreadsheet/CondFormatting.gml
deleted file mode 100644
index 437b5a1c3d..0000000000
--- a/Applications/Spreadsheet/CondFormatting.gml
+++ /dev/null
@@ -1,40 +0,0 @@
-@GUI::Widget {
- name: "main"
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [4, 4, 4, 4]
- spacing: 4
- }
-
- @Spreadsheet::ConditionsView {
- name: "conditions_view"
- }
-
- @GUI::Widget {
- shrink_to_fit: true
-
- layout: @GUI::HorizontalBoxLayout {
- spacing: 10
- }
-
- @GUI::Widget {
- }
-
- @GUI::Button {
- name: "add_button"
- text: "Add"
- fixed_width: 70
- }
-
- @GUI::Button {
- name: "remove_button"
- text: "Remove"
- fixed_width: 70
- }
-
- @GUI::Widget {
- }
-
- }
-}
diff --git a/Applications/Spreadsheet/CondView.gml b/Applications/Spreadsheet/CondView.gml
deleted file mode 100644
index d2161da89f..0000000000
--- a/Applications/Spreadsheet/CondView.gml
+++ /dev/null
@@ -1,54 +0,0 @@
-@GUI::Widget {
- layout: @GUI::VerticalBoxLayout {
- }
-
- @GUI::Widget {
- shrink_to_fit: true
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "if..."
- fixed_width: 40
- }
-
- @GUI::TextEditor {
- name: "formula_editor"
- fixed_height: 25
- tooltip: "Use 'value' to refer to the current cell's value"
- }
- }
-
- @GUI::Widget {
- shrink_to_fit: true
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Foreground..."
- fixed_width: 150
- }
-
- @GUI::ColorInput {
- name: "foreground_input"
- }
- }
-
- @GUI::Widget {
- shrink_to_fit: true
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Label {
- text: "Background..."
- fixed_width: 150
- }
-
- @GUI::ColorInput {
- name: "background_input"
- }
- }
-}
diff --git a/Applications/Spreadsheet/ConditionalFormatting.h b/Applications/Spreadsheet/ConditionalFormatting.h
deleted file mode 100644
index 8e32bc8046..0000000000
--- a/Applications/Spreadsheet/ConditionalFormatting.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Forward.h"
-#include <AK/String.h>
-#include <LibGUI/ScrollableWidget.h>
-#include <LibGfx/Color.h>
-
-namespace Spreadsheet {
-
-struct Format {
- Optional<Color> foreground_color;
- Optional<Color> background_color;
-};
-
-struct ConditionalFormat : public Format {
- String condition;
-};
-
-class ConditionView : public GUI::Widget {
- C_OBJECT(ConditionView)
-public:
- virtual ~ConditionView() override;
-
-private:
- ConditionView(ConditionalFormat&);
-
- ConditionalFormat& m_format;
-};
-
-class ConditionsView : public GUI::Widget {
- C_OBJECT(ConditionsView)
-public:
- virtual ~ConditionsView() override;
-
- void set_formats(Vector<ConditionalFormat>*);
-
- void add_format();
- void remove_top();
-
-private:
- ConditionsView();
-
- Vector<ConditionalFormat>* m_formats { nullptr };
- NonnullRefPtrVector<GUI::Widget> m_widgets;
-};
-
-}
diff --git a/Applications/Spreadsheet/Forward.h b/Applications/Spreadsheet/Forward.h
deleted file mode 100644
index 183c684972..0000000000
--- a/Applications/Spreadsheet/Forward.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-namespace Spreadsheet {
-
-class ConditionView;
-class Sheet;
-class SheetGlobalObject;
-class Workbook;
-class WorkbookObject;
-struct Cell;
-struct ConditionalFormat;
-struct Format;
-struct Position;
-
-}
diff --git a/Applications/Spreadsheet/HelpWindow.cpp b/Applications/Spreadsheet/HelpWindow.cpp
deleted file mode 100644
index eecd0bbb45..0000000000
--- a/Applications/Spreadsheet/HelpWindow.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "HelpWindow.h"
-#include "SpreadsheetWidget.h"
-#include <AK/LexicalPath.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Frame.h>
-#include <LibGUI/ListView.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Model.h>
-#include <LibGUI/Splitter.h>
-#include <LibMarkdown/Document.h>
-#include <LibWeb/Layout/Node.h>
-#include <LibWeb/OutOfProcessWebView.h>
-
-namespace Spreadsheet {
-
-class HelpListModel final : public GUI::Model {
-public:
- static NonnullRefPtr<HelpListModel> create() { return adopt(*new HelpListModel); }
-
- virtual ~HelpListModel() override { }
-
- virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_keys.size(); }
- virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return 1; }
- virtual void update() override { }
-
- virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role = GUI::ModelRole::Display) const override
- {
- if (role == GUI::ModelRole::Display) {
- return key(index);
- }
-
- return {};
- }
-
- String key(const GUI::ModelIndex& index) const { return m_keys[index.row()]; }
-
- void set_from(const JsonObject& object)
- {
- m_keys.clear();
- object.for_each_member([this](auto& name, auto&) {
- m_keys.append(name);
- });
- did_update();
- }
-
-private:
- HelpListModel()
- {
- }
-
- Vector<String> m_keys;
-};
-
-RefPtr<HelpWindow> HelpWindow::s_the { nullptr };
-
-HelpWindow::HelpWindow(GUI::Window* parent)
- : GUI::Window(parent)
-{
- resize(530, 365);
- set_title("Spreadsheet Functions Help");
- set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-help.png"));
-
- auto& widget = set_main_widget<GUI::Widget>();
- widget.set_layout<GUI::VerticalBoxLayout>();
- widget.set_fill_with_background_color(true);
-
- auto& splitter = widget.add<GUI::HorizontalSplitter>();
- auto& left_frame = splitter.add<GUI::Frame>();
- left_frame.set_layout<GUI::VerticalBoxLayout>();
- left_frame.set_fixed_width(100);
- m_listview = left_frame.add<GUI::ListView>();
- m_listview->set_activates_on_selection(true);
- m_listview->set_model(HelpListModel::create());
-
- m_webview = splitter.add<Web::OutOfProcessWebView>();
- m_webview->on_link_click = [this](auto& url, auto&, auto&&) {
- ASSERT(url.protocol() == "spreadsheet");
- if (url.host() == "example") {
- auto entry = LexicalPath(url.path()).basename();
- auto doc_option = m_docs.get(entry);
- if (!doc_option.is_object()) {
- GUI::MessageBox::show_error(this, String::formatted("No documentation entry found for '{}'", url.path()));
- return;
- }
- auto& doc = doc_option.as_object();
- const auto& name = url.fragment();
-
- auto example_data_value = doc.get_or("example_data", JsonObject {});
- if (!example_data_value.is_object()) {
- GUI::MessageBox::show_error(this, String::formatted("No example data found for '{}'", url.path()));
- return;
- }
-
- auto& example_data = example_data_value.as_object();
- auto value = example_data.get(name);
- if (!value.is_object()) {
- GUI::MessageBox::show_error(this, String::formatted("Example '{}' not found for '{}'", name, url.path()));
- return;
- }
-
- auto window = GUI::Window::construct(this);
- window->resize(size());
- window->set_icon(icon());
- window->set_title(String::formatted("Spreadsheet Help - Example {} for {}", name, entry));
- window->on_close = [window = window.ptr()] { window->remove_from_parent(); };
-
- auto& widget = window->set_main_widget<SpreadsheetWidget>(NonnullRefPtrVector<Sheet> {}, false);
- auto sheet = Sheet::from_json(value.as_object(), widget.workbook());
- if (!sheet) {
- GUI::MessageBox::show_error(this, String::formatted("Corrupted example '{}' in '{}'", name, url.path()));
- return;
- }
-
- widget.add_sheet(sheet.release_nonnull());
- window->show();
- } else if (url.host() == "doc") {
- auto entry = LexicalPath(url.path()).basename();
- m_webview->load(URL::create_with_data("text/html", render(entry)));
- } else {
- dbgln("Invalid spreadsheet action domain '{}'", url.host());
- }
- };
-
- m_listview->on_activation = [this](auto& index) {
- if (!m_webview)
- return;
-
- auto key = static_cast<HelpListModel*>(m_listview->model())->key(index);
- m_webview->load(URL::create_with_data("text/html", render(key)));
- };
-}
-
-String HelpWindow::render(const StringView& key)
-{
- auto doc_option = m_docs.get(key);
- ASSERT(doc_option.is_object());
-
- auto& doc = doc_option.as_object();
-
- auto name = doc.get("name").to_string();
- auto argc = doc.get("argc").to_u32(0);
- auto argnames_value = doc.get("argnames");
- ASSERT(argnames_value.is_array());
- auto& argnames = argnames_value.as_array();
-
- auto docstring = doc.get("doc").to_string();
- auto examples_value = doc.get_or("examples", JsonObject {});
- ASSERT(examples_value.is_object());
- auto& examples = examples_value.as_object();
-
- StringBuilder markdown_builder;
-
- markdown_builder.append("# NAME\n`");
- markdown_builder.append(name);
- markdown_builder.append("`\n\n");
-
- markdown_builder.append("# ARGUMENTS\n");
- if (argc > 0)
- markdown_builder.appendff("{} required argument(s):\n", argc);
- else
- markdown_builder.appendf("No required arguments.\n");
-
- for (size_t i = 0; i < argc; ++i)
- markdown_builder.appendff("- `{}`\n", argnames.at(i).to_string());
-
- if (argc > 0)
- markdown_builder.append("\n");
-
- if ((size_t)argnames.size() > argc) {
- auto opt_count = argnames.size() - argc;
- markdown_builder.appendff("{} optional argument(s):\n", opt_count);
- for (size_t i = argc; i < (size_t)argnames.size(); ++i)
- markdown_builder.appendff("- `{}`\n", argnames.at(i).to_string());
- markdown_builder.append("\n");
- }
-
- markdown_builder.append("# DESCRIPTION\n");
- markdown_builder.append(docstring);
- markdown_builder.append("\n\n");
-
- if (!examples.is_empty()) {
- markdown_builder.append("# EXAMPLES\n");
- examples.for_each_member([&](auto& text, auto& description_value) {
- dbgln("- {}\n\n```js\n{}\n```\n", description_value.to_string(), text);
- markdown_builder.appendff("- {}\n\n```js\n{}\n```\n", description_value.to_string(), text);
- });
- }
-
- auto document = Markdown::Document::parse(markdown_builder.string_view());
- return document->render_to_html();
-}
-
-void HelpWindow::set_docs(JsonObject&& docs)
-{
- m_docs = move(docs);
- static_cast<HelpListModel*>(m_listview->model())->set_from(m_docs);
- m_listview->update();
-}
-
-HelpWindow::~HelpWindow()
-{
-}
-}
diff --git a/Applications/Spreadsheet/HelpWindow.h b/Applications/Spreadsheet/HelpWindow.h
deleted file mode 100644
index 1c02d90eed..0000000000
--- a/Applications/Spreadsheet/HelpWindow.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/JsonObject.h>
-#include <LibGUI/Dialog.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibWeb/OutOfProcessWebView.h>
-
-namespace Spreadsheet {
-
-class HelpWindow : public GUI::Window {
- C_OBJECT(HelpWindow);
-
-public:
- static NonnullRefPtr<HelpWindow> the(GUI::Window* window)
- {
- if (s_the)
- return *s_the;
-
- return *(s_the = adopt(*new HelpWindow(window)));
- }
-
- virtual ~HelpWindow() override;
-
- void set_docs(JsonObject&& docs);
-
-private:
- static RefPtr<HelpWindow> s_the;
- String render(const StringView& key);
- HelpWindow(GUI::Window* parent = nullptr);
-
- JsonObject m_docs;
- RefPtr<Web::OutOfProcessWebView> m_webview;
- RefPtr<GUI::ListView> m_listview;
-};
-
-}
diff --git a/Applications/Spreadsheet/JSIntegration.cpp b/Applications/Spreadsheet/JSIntegration.cpp
deleted file mode 100644
index 12a249593e..0000000000
--- a/Applications/Spreadsheet/JSIntegration.cpp
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "JSIntegration.h"
-#include "Spreadsheet.h"
-#include "Workbook.h"
-#include <LibJS/Lexer.h>
-#include <LibJS/Runtime/Error.h>
-#include <LibJS/Runtime/GlobalObject.h>
-#include <LibJS/Runtime/Object.h>
-#include <LibJS/Runtime/Value.h>
-
-namespace Spreadsheet {
-
-Optional<FunctionAndArgumentIndex> get_function_and_argument_index(StringView source)
-{
- JS::Lexer lexer { source };
- // Track <identifier> <OpenParen>'s, and how many complete expressions are inside the parenthesised expression.
- Vector<size_t> state;
- StringView last_name;
- Vector<StringView> names;
- size_t open_parens_since_last_commit = 0;
- size_t open_curlies_and_brackets_since_last_commit = 0;
- bool previous_was_identifier = false;
- auto token = lexer.next();
- while (token.type() != JS::TokenType::Eof) {
- switch (token.type()) {
- case JS::TokenType::Identifier:
- previous_was_identifier = true;
- last_name = token.value();
- break;
- case JS::TokenType::ParenOpen:
- if (!previous_was_identifier) {
- open_parens_since_last_commit++;
- break;
- }
- previous_was_identifier = false;
- state.append(0);
- names.append(last_name);
- break;
- case JS::TokenType::ParenClose:
- previous_was_identifier = false;
- if (open_parens_since_last_commit == 0) {
- state.take_last();
- names.take_last();
- break;
- }
- --open_parens_since_last_commit;
- break;
- case JS::TokenType::Comma:
- previous_was_identifier = false;
- if (open_parens_since_last_commit == 0 && open_curlies_and_brackets_since_last_commit == 0) {
- state.last()++;
- break;
- }
- break;
- case JS::TokenType::BracketOpen:
- previous_was_identifier = false;
- open_curlies_and_brackets_since_last_commit++;
- break;
- case JS::TokenType::BracketClose:
- previous_was_identifier = false;
- if (open_curlies_and_brackets_since_last_commit > 0)
- open_curlies_and_brackets_since_last_commit--;
- break;
- case JS::TokenType::CurlyOpen:
- previous_was_identifier = false;
- open_curlies_and_brackets_since_last_commit++;
- break;
- case JS::TokenType::CurlyClose:
- previous_was_identifier = false;
- if (open_curlies_and_brackets_since_last_commit > 0)
- open_curlies_and_brackets_since_last_commit--;
- break;
- default:
- previous_was_identifier = false;
- break;
- }
-
- token = lexer.next();
- }
- if (!names.is_empty() && !state.is_empty())
- return FunctionAndArgumentIndex { names.last(), state.last() };
- return {};
-}
-
-SheetGlobalObject::SheetGlobalObject(Sheet& sheet)
- : m_sheet(sheet)
-{
-}
-
-SheetGlobalObject::~SheetGlobalObject()
-{
-}
-
-JS::Value SheetGlobalObject::get(const JS::PropertyName& name, JS::Value receiver) const
-{
- if (name.is_string()) {
- if (name.as_string() == "value") {
- if (auto cell = m_sheet.current_evaluated_cell())
- return cell->js_data();
-
- return JS::js_undefined();
- }
- if (auto pos = Sheet::parse_cell_name(name.as_string()); pos.has_value()) {
- auto& cell = m_sheet.ensure(pos.value());
- cell.reference_from(m_sheet.current_evaluated_cell());
- return cell.typed_js_data();
- }
- }
-
- return GlobalObject::get(name, receiver);
-}
-
-bool SheetGlobalObject::put(const JS::PropertyName& name, JS::Value value, JS::Value receiver)
-{
- if (name.is_string()) {
- if (auto pos = Sheet::parse_cell_name(name.as_string()); pos.has_value()) {
- auto& cell = m_sheet.ensure(pos.value());
- if (auto current = m_sheet.current_evaluated_cell())
- current->reference_from(&cell);
-
- cell.set_data(value); // FIXME: This produces un-savable state!
- return true;
- }
- }
-
- return GlobalObject::put(name, value, receiver);
-}
-
-void SheetGlobalObject::initialize()
-{
- GlobalObject::initialize();
- define_native_function("get_real_cell_contents", get_real_cell_contents, 1);
- define_native_function("set_real_cell_contents", set_real_cell_contents, 2);
- define_native_function("parse_cell_name", parse_cell_name, 1);
- define_native_function("current_cell_position", current_cell_position, 0);
- define_native_function("column_arithmetic", column_arithmetic, 2);
- define_native_function("column_index", column_index, 1);
-}
-
-void SheetGlobalObject::visit_edges(Visitor& visitor)
-{
- GlobalObject::visit_edges(visitor);
- for (auto& it : m_sheet.cells()) {
- if (it.value->exception())
- visitor.visit(it.value->exception());
- visitor.visit(it.value->evaluated_data());
- }
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::get_real_cell_contents)
-{
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return JS::js_null();
-
- if (StringView("SheetGlobalObject") != this_object->class_name()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "SheetGlobalObject");
- return {};
- }
-
- auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
-
- if (vm.argument_count() != 1) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to get_real_cell_contents()");
- return {};
- }
-
- auto name_value = vm.argument(0);
- if (!name_value.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected a String argument to get_real_cell_contents()");
- return {};
- }
- auto position = Sheet::parse_cell_name(name_value.as_string().string());
- if (!position.has_value()) {
- vm.throw_exception<JS::TypeError>(global_object, "Invalid cell name");
- return {};
- }
-
- const auto* cell = sheet_object->m_sheet.at(position.value());
- if (!cell)
- return JS::js_undefined();
-
- if (cell->kind() == Spreadsheet::Cell::Kind::Formula)
- return JS::js_string(vm.heap(), String::formatted("={}", cell->data()));
-
- return JS::js_string(vm.heap(), cell->data());
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::set_real_cell_contents)
-{
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return JS::js_null();
-
- if (StringView("SheetGlobalObject") != this_object->class_name()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "SheetGlobalObject");
- return {};
- }
-
- auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
-
- if (vm.argument_count() != 2) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly two arguments to set_real_cell_contents()");
- return {};
- }
-
- auto name_value = vm.argument(0);
- if (!name_value.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected the first argument of set_real_cell_contents() to be a String");
- return {};
- }
- auto position = Sheet::parse_cell_name(name_value.as_string().string());
- if (!position.has_value()) {
- vm.throw_exception<JS::TypeError>(global_object, "Invalid cell name");
- return {};
- }
-
- auto new_contents_value = vm.argument(1);
- if (!new_contents_value.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected the second argument of set_real_cell_contents() to be a String");
- return {};
- }
-
- auto& cell = sheet_object->m_sheet.ensure(position.value());
- auto& new_contents = new_contents_value.as_string().string();
- cell.set_data(new_contents);
- return JS::js_null();
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name)
-{
- if (vm.argument_count() != 1) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to parse_cell_name()");
- return {};
- }
- auto name_value = vm.argument(0);
- if (!name_value.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected a String argument to parse_cell_name()");
- return {};
- }
- auto position = Sheet::parse_cell_name(name_value.as_string().string());
- if (!position.has_value())
- return JS::js_undefined();
-
- auto object = JS::Object::create_empty(global_object);
- object->put("column", JS::js_string(vm, position.value().column));
- object->put("row", JS::Value((unsigned)position.value().row));
-
- return object;
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::current_cell_position)
-{
- if (vm.argument_count() != 0) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected no arguments to current_cell_position()");
- return {};
- }
-
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return JS::js_null();
-
- if (StringView("SheetGlobalObject") != this_object->class_name()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "SheetGlobalObject");
- return {};
- }
-
- auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
- auto* current_cell = sheet_object->m_sheet.current_evaluated_cell();
- if (!current_cell)
- return JS::js_null();
-
- auto position = current_cell->position();
-
- auto object = JS::Object::create_empty(global_object);
- object->put("column", JS::js_string(vm, position.column));
- object->put("row", JS::Value((unsigned)position.row));
-
- return object;
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_index)
-{
- if (vm.argument_count() != 1) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to column_index()");
- return {};
- }
-
- auto column_name = vm.argument(0);
- if (!column_name.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "String");
- return {};
- }
-
- auto& column_name_str = column_name.as_string().string();
-
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return JS::js_null();
-
- if (StringView("SheetGlobalObject") != this_object->class_name()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "SheetGlobalObject");
- return {};
- }
-
- auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
- auto& sheet = sheet_object->m_sheet;
- auto column_index = sheet.column_index(column_name_str);
- if (!column_index.has_value()) {
- vm.throw_exception(global_object, JS::TypeError::create(global_object, String::formatted("'{}' is not a valid column", column_name_str)));
- return {};
- }
-
- return JS::Value((i32)column_index.value());
-}
-
-JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_arithmetic)
-{
- if (vm.argument_count() != 2) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly two arguments to column_arithmetic()");
- return {};
- }
-
- auto column_name = vm.argument(0);
- if (!column_name.is_string()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "String");
- return {};
- }
-
- auto& column_name_str = column_name.as_string().string();
-
- auto offset = vm.argument(1).to_number(global_object);
- if (!offset.is_number())
- return {};
-
- auto offset_number = offset.as_i32();
-
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return JS::js_null();
-
- if (StringView("SheetGlobalObject") != this_object->class_name()) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "SheetGlobalObject");
- return {};
- }
-
- auto sheet_object = static_cast<SheetGlobalObject*>(this_object);
- auto& sheet = sheet_object->m_sheet;
- auto new_column = sheet.column_arithmetic(column_name_str, offset_number);
- if (!new_column.has_value()) {
- vm.throw_exception(global_object, JS::TypeError::create(global_object, String::formatted("'{}' is not a valid column", column_name_str)));
- return {};
- }
-
- return JS::js_string(vm, new_column.release_value());
-}
-
-WorkbookObject::WorkbookObject(Workbook& workbook)
- : JS::Object(*JS::Object::create_empty(workbook.global_object()))
- , m_workbook(workbook)
-{
-}
-
-WorkbookObject::~WorkbookObject()
-{
-}
-
-void WorkbookObject::initialize(JS::GlobalObject& global_object)
-{
- Object::initialize(global_object);
- define_native_function("sheet", sheet, 1);
-}
-
-void WorkbookObject::visit_edges(Visitor& visitor)
-{
- Base::visit_edges(visitor);
- for (auto& sheet : m_workbook.sheets())
- visitor.visit(&sheet.global_object());
-}
-
-JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
-{
- if (vm.argument_count() != 1) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected exactly one argument to sheet()");
- return {};
- }
- auto name_value = vm.argument(0);
- if (!name_value.is_string() && !name_value.is_number()) {
- vm.throw_exception<JS::TypeError>(global_object, "Expected a String or Number argument to sheet()");
- return {};
- }
-
- auto* this_object = vm.this_value(global_object).to_object(global_object);
- if (!this_object)
- return {};
-
- if (!is<WorkbookObject>(this_object)) {
- vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotA, "WorkbookObject");
- return {};
- }
-
- auto& workbook = static_cast<WorkbookObject*>(this_object)->m_workbook;
-
- if (name_value.is_string()) {
- auto& name = name_value.as_string().string();
- for (auto& sheet : workbook.sheets()) {
- if (sheet.name() == name)
- return JS::Value(&sheet.global_object());
- }
- } else {
- auto index = name_value.as_size_t();
- if (index < workbook.sheets().size())
- return JS::Value(&workbook.sheets()[index].global_object());
- }
-
- return JS::js_undefined();
-}
-
-}
diff --git a/Applications/Spreadsheet/JSIntegration.h b/Applications/Spreadsheet/JSIntegration.h
deleted file mode 100644
index 88f46d929d..0000000000
--- a/Applications/Spreadsheet/JSIntegration.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Forward.h"
-#include <LibJS/Forward.h>
-#include <LibJS/Runtime/GlobalObject.h>
-
-namespace Spreadsheet {
-
-struct FunctionAndArgumentIndex {
- String function_name;
- size_t argument_index { 0 };
-};
-Optional<FunctionAndArgumentIndex> get_function_and_argument_index(StringView source);
-
-class SheetGlobalObject final : public JS::GlobalObject {
- JS_OBJECT(SheetGlobalObject, JS::GlobalObject);
-
-public:
- SheetGlobalObject(Sheet&);
-
- virtual ~SheetGlobalObject() override;
-
- virtual JS::Value get(const JS::PropertyName&, JS::Value receiver = {}) const override;
- virtual bool put(const JS::PropertyName&, JS::Value value, JS::Value receiver = {}) override;
- virtual void initialize() override;
-
- JS_DECLARE_NATIVE_FUNCTION(get_real_cell_contents);
- JS_DECLARE_NATIVE_FUNCTION(set_real_cell_contents);
- JS_DECLARE_NATIVE_FUNCTION(parse_cell_name);
- JS_DECLARE_NATIVE_FUNCTION(current_cell_position);
- JS_DECLARE_NATIVE_FUNCTION(column_index);
- JS_DECLARE_NATIVE_FUNCTION(column_arithmetic);
-
-private:
- virtual void visit_edges(Visitor&) override;
- Sheet& m_sheet;
-};
-
-class WorkbookObject final : public JS::Object {
- JS_OBJECT(WorkbookObject, JS::Object);
-
-public:
- WorkbookObject(Workbook&);
-
- virtual ~WorkbookObject() override;
-
- virtual void initialize(JS::GlobalObject&) override;
-
- JS_DECLARE_NATIVE_FUNCTION(sheet);
-
-private:
- virtual void visit_edges(Visitor&) override;
- Workbook& m_workbook;
-};
-
-}
diff --git a/Applications/Spreadsheet/Position.h b/Applications/Spreadsheet/Position.h
deleted file mode 100644
index af7d7f70a9..0000000000
--- a/Applications/Spreadsheet/Position.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Types.h>
-#include <AK/URL.h>
-
-namespace Spreadsheet {
-
-struct Position {
- String column;
- size_t row { 0 };
-
- bool operator==(const Position& other) const
- {
- return row == other.row && column == other.column;
- }
-
- bool operator!=(const Position& other) const
- {
- return !(other == *this);
- }
-
- URL to_url() const
- {
- URL url;
- url.set_protocol("spreadsheet");
- url.set_host("cell");
- url.set_path(String::formatted("/{}", getpid()));
- url.set_fragment(String::formatted("{}{}", column, row));
- return url;
- }
-};
-
-}
diff --git a/Applications/Spreadsheet/Readers/CSV.h b/Applications/Spreadsheet/Readers/CSV.h
deleted file mode 100644
index 866ae67141..0000000000
--- a/Applications/Spreadsheet/Readers/CSV.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "XSV.h"
-#include <AK/Forward.h>
-#include <AK/StringView.h>
-
-namespace Reader {
-
-class CSV : public XSV {
-public:
- CSV(StringView source, ParserBehaviour behaviours = default_behaviours())
- : XSV(source, { ",", "\"", ParserTraits::Repeat }, behaviours)
- {
- }
-};
-
-}
diff --git a/Applications/Spreadsheet/Readers/Test/TestXSV.cpp b/Applications/Spreadsheet/Readers/Test/TestXSV.cpp
deleted file mode 100644
index b80093d556..0000000000
--- a/Applications/Spreadsheet/Readers/Test/TestXSV.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <AK/TestSuite.h>
-
-#include "../CSV.h"
-#include "../XSV.h"
-#include <LibCore/File.h>
-
-TEST_CASE(should_parse_valid_data)
-{
- {
- auto data = R"~~~(Foo, Bar, Baz
- 1, 2, 3
- 4, 5, 6
- """x", y"z, 9)~~~";
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders | Reader::ParserBehaviour::TrimLeadingFieldSpaces };
- EXPECT(!csv.has_error());
-
- EXPECT_EQ(csv[0]["Foo"], "1");
- EXPECT_EQ(csv[2]["Foo"], "\"x");
- EXPECT_EQ(csv[2]["Bar"], "y\"z");
- }
-
- {
- auto data = R"~~~(Foo, Bar, Baz
- 1 , 2, 3
- 4, "5 " , 6
- """x", y"z, 9 )~~~";
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders | Reader::ParserBehaviour::TrimLeadingFieldSpaces | Reader::ParserBehaviour::TrimTrailingFieldSpaces };
- EXPECT(!csv.has_error());
-
- EXPECT_EQ(csv[0]["Foo"], "1");
- EXPECT_EQ(csv[1]["Bar"], "5 ");
- EXPECT_EQ(csv[2]["Foo"], "\"x");
- EXPECT_EQ(csv[2]["Baz"], "9");
- }
-}
-
-TEST_CASE(should_fail_nicely)
-{
- {
- auto data = R"~~~(Foo, Bar, Baz
- x, y)~~~";
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders | Reader::ParserBehaviour::TrimLeadingFieldSpaces };
- EXPECT(csv.has_error());
- EXPECT_EQ(csv.error(), Reader::ReadError::NonConformingColumnCount);
- }
-
- {
- auto data = R"~~~(Foo, Bar, Baz
- x, y, "z)~~~";
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders | Reader::ParserBehaviour::TrimLeadingFieldSpaces };
- EXPECT(csv.has_error());
- EXPECT_EQ(csv.error(), Reader::ReadError::QuoteFailure);
- }
-}
-
-TEST_CASE(should_iterate_rows)
-{
- auto data = R"~~~(Foo, Bar, Baz
- 1, 2, 3
- 4, 5, 6
- """x", y"z, 9)~~~";
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders | Reader::ParserBehaviour::TrimLeadingFieldSpaces };
- EXPECT(!csv.has_error());
-
- bool ran = false;
- for (auto row : csv)
- ran = !row[0].is_empty();
-
- EXPECT(ran);
-}
-
-BENCHMARK_CASE(fairly_big_data)
-{
- auto file_or_error = Core::File::open(__FILE__ ".data", Core::IODevice::OpenMode::ReadOnly);
- EXPECT_EQ_FORCE(file_or_error.is_error(), false);
-
- auto data = file_or_error.value()->read_all();
- auto csv = Reader::CSV { data, Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders };
-
- EXPECT(!csv.has_error());
- EXPECT_EQ(csv.size(), 100000u);
-}
-
-TEST_MAIN(XSV)
diff --git a/Applications/Spreadsheet/Readers/XSV.cpp b/Applications/Spreadsheet/Readers/XSV.cpp
deleted file mode 100644
index 99a61b0abc..0000000000
--- a/Applications/Spreadsheet/Readers/XSV.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "XSV.h"
-#include <AK/StringBuilder.h>
-
-namespace Reader {
-
-ParserBehaviour operator&(ParserBehaviour left, ParserBehaviour right)
-{
- return static_cast<ParserBehaviour>(static_cast<u32>(left) & static_cast<u32>(right));
-}
-
-ParserBehaviour operator|(ParserBehaviour left, ParserBehaviour right)
-{
- return static_cast<ParserBehaviour>(static_cast<u32>(left) | static_cast<u32>(right));
-}
-
-void XSV::set_error(ReadError error)
-{
- if (m_error == ReadError::None)
- m_error = error;
-}
-
-Vector<String> XSV::headers() const
-{
- Vector<String> headers;
- for (auto& field : m_names)
- headers.append(field.is_string_view ? field.as_string_view : field.as_string.view());
-
- return headers;
-}
-
-void XSV::parse()
-{
- if ((m_behaviours & ParserBehaviour::ReadHeaders) != ParserBehaviour::None)
- read_headers();
-
- while (!has_error() && !m_lexer.is_eof())
- m_rows.append(read_row());
-
- if (!m_lexer.is_eof())
- set_error(ReadError::DataPastLogicalEnd);
-}
-
-void XSV::read_headers()
-{
- if (!m_names.is_empty()) {
- set_error(ReadError::InternalError);
- m_names.clear();
- }
-
- m_names = read_row(true);
-}
-
-Vector<XSV::Field> XSV::read_row(bool header_row)
-{
- Vector<Field> row;
- bool first = true;
- while (!(m_lexer.is_eof() || m_lexer.next_is('\n') || m_lexer.next_is("\r\n")) && (first || m_lexer.consume_specific(m_traits.separator))) {
- first = false;
- row.append(read_one_field());
- }
-
- if (!m_lexer.is_eof()) {
- auto crlf_ok = m_lexer.consume_specific("\r\n");
- if (!crlf_ok) {
- auto lf_ok = m_lexer.consume_specific('\n');
- if (!lf_ok)
- set_error(ReadError::DataPastLogicalEnd);
- }
- }
-
- if (!header_row && (m_behaviours & ParserBehaviour::ReadHeaders) != ParserBehaviour::None && row.size() != m_names.size())
- set_error(ReadError::NonConformingColumnCount);
-
- return row;
-}
-
-XSV::Field XSV::read_one_field()
-{
- if ((m_behaviours & ParserBehaviour::TrimLeadingFieldSpaces) != ParserBehaviour::None)
- m_lexer.consume_while(is_any_of(" \t\v"));
-
- bool is_quoted = false;
- Field field;
- if (m_lexer.next_is(m_traits.quote.view())) {
- is_quoted = true;
- field = read_one_quoted_field();
- } else {
- field = read_one_unquoted_field();
- }
-
- if ((m_behaviours & ParserBehaviour::TrimTrailingFieldSpaces) != ParserBehaviour::None) {
- m_lexer.consume_while(is_any_of(" \t\v"));
-
- if (!is_quoted) {
- // Also have to trim trailing spaces from unquoted fields.
- StringView view;
- if (field.is_string_view)
- view = field.as_string_view;
- else
- view = field.as_string;
-
- if (!view.is_empty()) {
- ssize_t i = view.length() - 1;
- for (; i >= 0; --i) {
- if (!view.substring_view(i, 1).is_one_of(" ", "\t", "\v"))
- break;
- }
- view = view.substring_view(0, i + 1);
- }
-
- if (field.is_string_view)
- field.as_string_view = view;
- else
- field.as_string = field.as_string.substring(0, view.length());
- }
- }
-
- return field;
-}
-
-XSV::Field XSV::read_one_quoted_field()
-{
- if (!m_lexer.consume_specific(m_traits.quote))
- set_error(ReadError::InternalError);
-
- size_t start = m_lexer.tell(), end = start;
- bool is_copy = false;
- StringBuilder builder;
- auto allow_newlines = (m_behaviours & ParserBehaviour::AllowNewlinesInFields) != ParserBehaviour::None;
-
- for (; !m_lexer.is_eof();) {
- char ch;
- switch (m_traits.quote_escape) {
- case ParserTraits::Backslash:
- if (m_lexer.consume_specific('\\') && m_lexer.consume_specific(m_traits.quote)) {
- // If there is an escaped quote, we have no choice but to make a copy.
- if (!is_copy) {
- is_copy = true;
- builder.append(m_source.substring_view(start, end - start));
- }
- builder.append(m_traits.quote);
- end = m_lexer.tell();
- continue;
- }
- break;
- case ParserTraits::Repeat:
- if (m_lexer.consume_specific(m_traits.quote)) {
- if (m_lexer.consume_specific(m_traits.quote)) {
- // If there is an escaped quote, we have no choice but to make a copy.
- if (!is_copy) {
- is_copy = true;
- builder.append(m_source.substring_view(start, end - start));
- }
- builder.append(m_traits.quote);
- end = m_lexer.tell();
- continue;
- }
- for (size_t i = 0; i < m_traits.quote.length(); ++i)
- m_lexer.retreat();
- goto end;
- }
- break;
- }
-
- if (m_lexer.next_is(m_traits.quote.view()))
- goto end;
-
- if (!allow_newlines) {
- if (m_lexer.next_is('\n') || m_lexer.next_is("\r\n"))
- goto end;
- }
-
- ch = m_lexer.consume();
- if (is_copy)
- builder.append(ch);
- end = m_lexer.tell();
- continue;
-
- end:
- break;
- }
-
- if (!m_lexer.consume_specific(m_traits.quote))
- set_error(ReadError::QuoteFailure);
-
- if (is_copy)
- return { {}, builder.to_string(), false };
-
- return { m_source.substring_view(start, end - start), {}, true };
-}
-
-XSV::Field XSV::read_one_unquoted_field()
-{
- size_t start = m_lexer.tell(), end = start;
- bool allow_quote_in_field = (m_behaviours & ParserBehaviour::QuoteOnlyInFieldStart) != ParserBehaviour::None;
-
- for (; !m_lexer.is_eof();) {
- if (m_lexer.next_is(m_traits.separator.view()))
- break;
-
- if (m_lexer.next_is("\r\n") || m_lexer.next_is("\n"))
- break;
-
- if (m_lexer.consume_specific(m_traits.quote)) {
- if (!allow_quote_in_field)
- set_error(ReadError::QuoteFailure);
- end = m_lexer.tell();
- continue;
- }
-
- m_lexer.consume();
- end = m_lexer.tell();
- }
-
- return { m_source.substring_view(start, end - start), {}, true };
-}
-
-StringView XSV::Row::operator[](StringView name) const
-{
- ASSERT(!m_xsv.m_names.is_empty());
- auto it = m_xsv.m_names.find_if([&](const auto& entry) { return name == entry; });
- ASSERT(!it.is_end());
-
- return (*this)[it.index()];
-}
-
-StringView XSV::Row::operator[](size_t column) const
-{
- auto& field = m_xsv.m_rows[m_index][column];
- if (field.is_string_view)
- return field.as_string_view;
- return field.as_string;
-}
-
-const XSV::Row XSV::operator[](size_t index) const
-{
- return const_cast<XSV&>(*this)[index];
-}
-
-XSV::Row XSV::operator[](size_t index)
-{
- ASSERT(m_rows.size() > index);
- return Row { *this, index };
-}
-
-}
diff --git a/Applications/Spreadsheet/Readers/XSV.h b/Applications/Spreadsheet/Readers/XSV.h
deleted file mode 100644
index 0b32ca767d..0000000000
--- a/Applications/Spreadsheet/Readers/XSV.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/GenericLexer.h>
-#include <AK/String.h>
-#include <AK/StringView.h>
-#include <AK/Types.h>
-#include <AK/Vector.h>
-
-namespace Reader {
-
-enum class ParserBehaviour : u32 {
- None = 0,
- ReadHeaders = 1,
- AllowNewlinesInFields = ReadHeaders << 1,
- TrimLeadingFieldSpaces = ReadHeaders << 2,
- TrimTrailingFieldSpaces = ReadHeaders << 3,
- QuoteOnlyInFieldStart = ReadHeaders << 4,
-};
-
-ParserBehaviour operator&(ParserBehaviour left, ParserBehaviour right);
-ParserBehaviour operator|(ParserBehaviour left, ParserBehaviour right);
-
-struct ParserTraits {
- String separator;
- String quote { "\"" };
- enum {
- Repeat,
- Backslash,
- } quote_escape { Repeat };
-};
-
-#define ENUMERATE_READ_ERRORS() \
- E(None, "No errors") \
- E(NonConformingColumnCount, "Header count does not match given column count") \
- E(QuoteFailure, "Quoting failure") \
- E(InternalError, "Internal error") \
- E(DataPastLogicalEnd, "Exrta data past the logical end of the rows")
-
-enum class ReadError {
-#define E(name, _) name,
- ENUMERATE_READ_ERRORS()
-#undef E
-};
-
-inline constexpr ParserBehaviour default_behaviours()
-{
- return ParserBehaviour::QuoteOnlyInFieldStart;
-}
-
-class XSV {
-public:
- XSV(StringView source, const ParserTraits& traits, ParserBehaviour behaviours = default_behaviours())
- : m_source(source)
- , m_lexer(m_source)
- , m_traits(traits)
- , m_behaviours(behaviours)
- {
- parse();
- }
-
- virtual ~XSV() { }
-
- bool has_error() const { return m_error != ReadError::None; }
- ReadError error() const { return m_error; }
- String error_string() const
- {
- switch (m_error) {
-#define E(x, y) \
- case ReadError::x: \
- return y;
-
- ENUMERATE_READ_ERRORS();
-#undef E
- }
- ASSERT_NOT_REACHED();
- }
-
- size_t size() const { return m_rows.size(); }
- Vector<String> headers() const;
-
- class Row {
- public:
- explicit Row(XSV& xsv, size_t index)
- : m_xsv(xsv)
- , m_index(index)
- {
- }
-
- StringView operator[](StringView name) const;
- StringView operator[](size_t column) const;
-
- size_t index() const { return m_index; }
-
- // FIXME: Implement begin() and end(), keeping `Field' out of the API.
-
- private:
- XSV& m_xsv;
- size_t m_index { 0 };
- };
-
- template<bool const_>
- class RowIterator {
- public:
- explicit RowIterator(const XSV& xsv, size_t init_index = 0) requires(const_)
- : m_xsv(const_cast<XSV&>(xsv))
- , m_index(init_index)
- {
- }
-
- explicit RowIterator(XSV& xsv, size_t init_index = 0) requires(!const_)
- : m_xsv(xsv)
- , m_index(init_index)
- {
- }
-
- Row operator*() const { return Row { m_xsv, m_index }; }
- Row operator*() requires(!const_) { return Row { m_xsv, m_index }; }
-
- RowIterator& operator++()
- {
- ++m_index;
- return *this;
- }
-
- bool is_end() const { return m_index == m_xsv.m_rows.size(); }
- bool operator==(const RowIterator& other) const
- {
- return m_index == other.m_index && &m_xsv == &other.m_xsv;
- }
- bool operator==(const RowIterator<!const_>& other) const
- {
- return m_index == other.m_index && &m_xsv == &other.m_xsv;
- }
-
- private:
- XSV& m_xsv;
- size_t m_index { 0 };
- };
-
- const Row operator[](size_t index) const;
- Row operator[](size_t index);
-
- auto begin() { return RowIterator<false>(*this); }
- auto end() { return RowIterator<false>(*this, m_rows.size()); }
-
- auto begin() const { return RowIterator<true>(*this); }
- auto end() const { return RowIterator<true>(*this, m_rows.size()); }
-
- using ConstIterator = RowIterator<true>;
- using Iterator = RowIterator<false>;
-
-private:
- struct Field {
- StringView as_string_view;
- String as_string; // This member only used if the parser couldn't use the original source verbatim.
- bool is_string_view { true };
-
- bool operator==(StringView other) const
- {
- if (is_string_view)
- return other == as_string_view;
- return as_string == other;
- }
- };
- void set_error(ReadError error);
- void parse();
- void read_headers();
- Vector<Field> read_row(bool header_row = false);
- Field read_one_field();
- Field read_one_quoted_field();
- Field read_one_unquoted_field();
-
- StringView m_source;
- GenericLexer m_lexer;
- const ParserTraits& m_traits;
- ParserBehaviour m_behaviours;
- Vector<Field> m_names;
- Vector<Vector<Field>> m_rows;
- ReadError m_error { ReadError::None };
-};
-
-}
diff --git a/Applications/Spreadsheet/Spreadsheet.cpp b/Applications/Spreadsheet/Spreadsheet.cpp
deleted file mode 100644
index 0d20b22fdd..0000000000
--- a/Applications/Spreadsheet/Spreadsheet.cpp
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Spreadsheet.h"
-#include "JSIntegration.h"
-#include "Workbook.h"
-#include <AK/ByteBuffer.h>
-#include <AK/GenericLexer.h>
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonParser.h>
-#include <AK/ScopeGuard.h>
-#include <AK/TemporaryChange.h>
-#include <AK/URL.h>
-#include <LibCore/File.h>
-#include <LibJS/Parser.h>
-#include <LibJS/Runtime/Function.h>
-#include <ctype.h>
-
-//#define COPY_DEBUG
-
-namespace Spreadsheet {
-
-Sheet::Sheet(const StringView& name, Workbook& workbook)
- : Sheet(workbook)
-{
- m_name = name;
-
- for (size_t i = 0; i < default_row_count; ++i)
- add_row();
-
- for (size_t i = 0; i < default_column_count; ++i)
- add_column();
-}
-
-Sheet::Sheet(Workbook& workbook)
- : m_workbook(workbook)
-{
- JS::DeferGC defer_gc(m_workbook.interpreter().heap());
- m_global_object = m_workbook.interpreter().heap().allocate_without_global_object<SheetGlobalObject>(*this);
- global_object().initialize();
- global_object().put("workbook", m_workbook.workbook_object());
- global_object().put("thisSheet", &global_object()); // Self-reference is unfortunate, but required.
-
- // Sadly, these have to be evaluated once per sheet.
- auto file_or_error = Core::File::open("/res/js/Spreadsheet/runtime.js", Core::IODevice::OpenMode::ReadOnly);
- if (!file_or_error.is_error()) {
- auto buffer = file_or_error.value()->read_all();
- JS::Parser parser { JS::Lexer(buffer) };
- if (parser.has_errors()) {
- warnln("Spreadsheet: Failed to parse runtime code");
- parser.print_errors();
- } else {
- interpreter().run(global_object(), parser.parse_program());
- if (auto exc = interpreter().exception()) {
- warnln("Spreadsheet: Failed to run runtime code: ");
- for (auto& t : exc->trace())
- warnln("{}", t);
- interpreter().vm().clear_exception();
- }
- }
- }
-}
-
-Sheet::~Sheet()
-{
-}
-
-JS::Interpreter& Sheet::interpreter() const
-{
- return m_workbook.interpreter();
-}
-
-size_t Sheet::add_row()
-{
- return m_rows++;
-}
-
-static String convert_to_string(size_t value, unsigned base = 26, StringView map = {})
-{
- if (map.is_null())
- map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- ASSERT(base >= 2 && base <= map.length());
-
- // The '8 bits per byte' assumption may need to go?
- Array<char, round_up_to_power_of_two(sizeof(size_t) * 8 + 1, 2)> buffer;
- size_t i = 0;
- do {
- buffer[i++] = map[value % base];
- value /= base;
- } while (value > 0);
-
- // NOTE: Weird as this may seem, the thing that comes after 'A' is 'AA', which as a number would be '00'
- // to make this work, only the most significant digit has to be in a range of (1..25) as opposed to (0..25),
- // but only if it's not the only digit in the string.
- if (i > 1)
- --buffer[i - 1];
-
- for (size_t j = 0; j < i / 2; ++j)
- swap(buffer[j], buffer[i - j - 1]);
-
- return String { ReadonlyBytes(buffer.data(), i) };
-}
-
-static size_t convert_from_string(StringView str, unsigned base = 26, StringView map = {})
-{
- if (map.is_null())
- map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- ASSERT(base >= 2 && base <= map.length());
-
- size_t value = 0;
- for (size_t i = str.length(); i > 0; --i) {
- auto digit_value = map.find_first_of(str[i - 1]).value_or(0);
- // NOTE: Refer to the note in `convert_to_string()'.
- if (i == str.length() && str.length() > 1)
- ++digit_value;
- value = value * base + digit_value;
- }
-
- return value;
-}
-
-String Sheet::add_column()
-{
- auto next_column = convert_to_string(m_columns.size());
- m_columns.append(next_column);
- return next_column;
-}
-
-void Sheet::update()
-{
- if (m_should_ignore_updates) {
- m_update_requested = true;
- return;
- }
- m_visited_cells_in_update.clear();
- Vector<Cell*> cells_copy;
-
- // Grab a copy as updates might insert cells into the table.
- for (auto& it : m_cells) {
- if (it.value->dirty()) {
- cells_copy.append(it.value);
- m_workbook.set_dirty(true);
- }
- }
-
- for (auto& cell : cells_copy)
- update(*cell);
-
- m_visited_cells_in_update.clear();
-}
-
-void Sheet::update(Cell& cell)
-{
- if (m_should_ignore_updates) {
- m_update_requested = true;
- return;
- }
- if (cell.dirty()) {
- if (has_been_visited(&cell)) {
- // This may be part of an cyclic reference chain,
- // so just ignore it.
- cell.clear_dirty();
- return;
- }
- m_visited_cells_in_update.set(&cell);
- cell.update_data({});
- }
-}
-
-Sheet::ValueAndException Sheet::evaluate(const StringView& source, Cell* on_behalf_of)
-{
- TemporaryChange cell_change { m_current_cell_being_evaluated, on_behalf_of };
- ScopeGuard clear_exception { [&] { interpreter().vm().clear_exception(); } };
-
- auto parser = JS::Parser(JS::Lexer(source));
- if (parser.has_errors() || interpreter().exception())
- return { JS::js_undefined(), interpreter().exception() };
-
- auto program = parser.parse_program();
- interpreter().run(global_object(), program);
- if (interpreter().exception()) {
- auto exc = interpreter().exception();
- return { JS::js_undefined(), exc };
- }
-
- auto value = interpreter().vm().last_value();
- if (value.is_empty())
- return { JS::js_undefined(), {} };
- return { value, {} };
-}
-
-Cell* Sheet::at(const StringView& name)
-{
- auto pos = parse_cell_name(name);
- if (pos.has_value())
- return at(pos.value());
-
- return nullptr;
-}
-
-Cell* Sheet::at(const Position& position)
-{
- auto it = m_cells.find(position);
-
- if (it == m_cells.end())
- return nullptr;
-
- return it->value;
-}
-
-Optional<Position> Sheet::parse_cell_name(const StringView& name)
-{
- GenericLexer lexer(name);
- auto col = lexer.consume_while(isalpha);
- auto row = lexer.consume_while(isdigit);
-
- if (!lexer.is_eof() || row.is_empty() || col.is_empty())
- return {};
-
- return Position { col, row.to_uint().value() };
-}
-
-Optional<size_t> Sheet::column_index(const StringView& column_name) const
-{
- auto index = convert_from_string(column_name);
- if (m_columns.size() <= index || m_columns[index] != column_name)
- return {};
-
- return index;
-}
-
-Optional<String> Sheet::column_arithmetic(const StringView& column_name, int offset)
-{
- auto maybe_index = column_index(column_name);
- if (!maybe_index.has_value())
- return {};
-
- if (offset < 0 && maybe_index.value() < (size_t)(0 - offset))
- return m_columns.first();
-
- auto index = maybe_index.value() + offset;
- if (m_columns.size() > index)
- return m_columns[index];
-
- for (size_t i = m_columns.size(); i <= index; ++i)
- add_column();
-
- return m_columns.last();
-}
-
-Cell* Sheet::from_url(const URL& url)
-{
- auto maybe_position = position_from_url(url);
- if (!maybe_position.has_value())
- return nullptr;
-
- return at(maybe_position.value());
-}
-
-Optional<Position> Sheet::position_from_url(const URL& url) const
-{
- if (!url.is_valid()) {
- dbgln("Invalid url: {}", url.to_string());
- return {};
- }
-
- if (url.protocol() != "spreadsheet" || url.host() != "cell") {
- dbgln("Bad url: {}", url.to_string());
- return {};
- }
-
- // FIXME: Figure out a way to do this cross-process.
- ASSERT(url.path() == String::formatted("/{}", getpid()));
-
- return parse_cell_name(url.fragment());
-}
-
-Position Sheet::offset_relative_to(const Position& base, const Position& offset, const Position& offset_base) const
-{
- auto offset_column_it = m_columns.find(offset.column);
- auto offset_base_column_it = m_columns.find(offset_base.column);
- auto base_column_it = m_columns.find(base.column);
-
- if (offset_column_it.is_end()) {
- dbgln("Column '{}' does not exist!", offset.column);
- return base;
- }
- if (offset_base_column_it.is_end()) {
- dbgln("Column '{}' does not exist!", offset.column);
- return base;
- }
- if (base_column_it.is_end()) {
- dbgln("Column '{}' does not exist!", offset.column);
- return offset;
- }
-
- auto new_column = column(offset_column_it.index() + base_column_it.index() - offset_base_column_it.index());
- auto new_row = offset.row + base.row - offset_base.row;
-
- return { move(new_column), new_row };
-}
-
-void Sheet::copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to)
-{
- auto copy_to = [&](auto& source_position, Position target_position) {
- auto& target_cell = ensure(target_position);
- auto* source_cell = at(source_position);
-
- if (!source_cell) {
- target_cell.set_data("");
- return;
- }
-
- target_cell.copy_from(*source_cell);
- };
-
- if (from.size() == to.size()) {
- auto from_it = from.begin();
- // FIXME: Ordering.
- for (auto& position : to)
- copy_to(*from_it++, position);
-
- return;
- }
-
- if (to.size() == 1) {
- // Resolve each index as relative to the first index offset from the selection.
- auto& target = to.first();
-
- for (auto& position : from) {
-#ifdef COPY_DEBUG
- dbg() << "Paste from '" << position.to_url() << "' to '" << target.to_url() << "'";
-#endif
- copy_to(position, resolve_relative_to.has_value() ? offset_relative_to(target, position, resolve_relative_to.value()) : target);
- }
-
- return;
- }
-
- if (from.size() == 1) {
- // Fill the target selection with the single cell.
- auto& source = from.first();
- for (auto& position : to) {
-#ifdef COPY_DEBUG
- dbg() << "Paste from '" << source.to_url() << "' to '" << position.to_url() << "'";
-#endif
- copy_to(source, resolve_relative_to.has_value() ? offset_relative_to(position, source, resolve_relative_to.value()) : position);
- }
- return;
- }
-
- // Just disallow misaligned copies.
- dbgln("Cannot copy {} cells to {} cells", from.size(), to.size());
-}
-
-RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)
-{
- auto sheet = adopt(*new Sheet(workbook));
- auto rows = object.get("rows").to_u32(default_row_count);
- auto columns = object.get("columns");
- auto name = object.get("name").as_string_or("Sheet");
-
- sheet->set_name(name);
-
- for (size_t i = 0; i < max(rows, (unsigned)Sheet::default_row_count); ++i)
- sheet->add_row();
-
- // FIXME: Better error checking.
- if (columns.is_array()) {
- columns.as_array().for_each([&](auto& value) {
- sheet->m_columns.append(value.as_string());
- return IterationDecision::Continue;
- });
- }
-
- if (sheet->m_columns.size() < default_column_count && sheet->columns_are_standard()) {
- for (size_t i = sheet->m_columns.size(); i < default_column_count; ++i)
- sheet->add_column();
- }
-
- auto cells = object.get("cells").as_object();
- auto json = sheet->interpreter().global_object().get("JSON");
- auto& parse_function = json.as_object().get("parse").as_function();
-
- auto read_format = [](auto& format, const auto& obj) {
- if (auto value = obj.get("foreground_color"); value.is_string())
- format.foreground_color = Color::from_string(value.as_string());
- if (auto value = obj.get("background_color"); value.is_string())
- format.background_color = Color::from_string(value.as_string());
- };
-
- cells.for_each_member([&](auto& name, JsonValue& value) {
- auto position_option = parse_cell_name(name);
- if (!position_option.has_value())
- return IterationDecision::Continue;
-
- auto position = position_option.value();
- auto& obj = value.as_object();
- auto kind = obj.get("kind").as_string_or("LiteralString") == "LiteralString" ? Cell::LiteralString : Cell::Formula;
-
- OwnPtr<Cell> cell;
- switch (kind) {
- case Cell::LiteralString:
- cell = make<Cell>(obj.get("value").to_string(), position, *sheet);
- break;
- case Cell::Formula: {
- auto& interpreter = sheet->interpreter();
- auto value = interpreter.vm().call(parse_function, json, JS::js_string(interpreter.heap(), obj.get("value").as_string()));
- cell = make<Cell>(obj.get("source").to_string(), move(value), position, *sheet);
- break;
- }
- }
-
- auto type_name = obj.get_or("type", "Numeric").to_string();
- cell->set_type(type_name);
-
- auto type_meta = obj.get("type_metadata");
- if (type_meta.is_object()) {
- auto& meta_obj = type_meta.as_object();
- auto meta = cell->type_metadata();
- if (auto value = meta_obj.get("length"); value.is_number())
- meta.length = value.to_i32();
- if (auto value = meta_obj.get("format"); value.is_string())
- meta.format = value.as_string();
- read_format(meta.static_format, meta_obj);
-
- cell->set_type_metadata(move(meta));
- }
-
- auto conditional_formats = obj.get("conditional_formats");
- auto cformats = cell->conditional_formats();
- if (conditional_formats.is_array()) {
- conditional_formats.as_array().for_each([&](const auto& fmt_val) {
- if (!fmt_val.is_object())
- return IterationDecision::Continue;
-
- auto& fmt_obj = fmt_val.as_object();
- auto fmt_cond = fmt_obj.get("condition").to_string();
- if (fmt_cond.is_empty())
- return IterationDecision::Continue;
-
- ConditionalFormat fmt;
- fmt.condition = move(fmt_cond);
- read_format(fmt, fmt_obj);
- cformats.append(move(fmt));
-
- return IterationDecision::Continue;
- });
- cell->set_conditional_formats(move(cformats));
- }
-
- auto evaluated_format = obj.get("evaluated_formats");
- if (evaluated_format.is_object()) {
- auto& evaluated_format_obj = evaluated_format.as_object();
- auto& evaluated_fmts = cell->evaluated_formats();
-
- read_format(evaluated_fmts, evaluated_format_obj);
- }
-
- sheet->m_cells.set(position, cell.release_nonnull());
- return IterationDecision::Continue;
- });
-
- return sheet;
-}
-
-Position Sheet::written_data_bounds() const
-{
- Position bound;
- for (auto& entry : m_cells) {
- if (entry.key.row >= bound.row)
- bound.row = entry.key.row;
- if (entry.key.column >= bound.column)
- bound.column = entry.key.column;
- }
-
- return bound;
-}
-
-/// The sheet is allowed to have nonstandard column names
-/// this checks whether all existing columns are 'standard'
-/// (i.e. as generated by 'convert_to_string()'
-bool Sheet::columns_are_standard() const
-{
- for (size_t i = 0; i < m_columns.size(); ++i) {
- if (m_columns[i] != convert_to_string(i))
- return false;
- }
-
- return true;
-}
-
-JsonObject Sheet::to_json() const
-{
- JsonObject object;
- object.set("name", m_name);
-
- auto save_format = [](const auto& format, auto& obj) {
- if (format.foreground_color.has_value())
- obj.set("foreground_color", format.foreground_color.value().to_string());
- if (format.background_color.has_value())
- obj.set("background_color", format.background_color.value().to_string());
- };
-
- auto bottom_right = written_data_bounds();
-
- if (!columns_are_standard()) {
- auto columns = JsonArray();
- for (auto& column : m_columns)
- columns.append(column);
- object.set("columns", move(columns));
- }
- object.set("rows", bottom_right.row + 1);
-
- JsonObject cells;
- for (auto& it : m_cells) {
- StringBuilder builder;
- builder.append(it.key.column);
- builder.appendff("{}", it.key.row);
- auto key = builder.to_string();
-
- JsonObject data;
- data.set("kind", it.value->kind() == Cell::Kind::Formula ? "Formula" : "LiteralString");
- if (it.value->kind() == Cell::Formula) {
- data.set("source", it.value->data());
- auto json = interpreter().global_object().get("JSON");
- auto stringified = interpreter().vm().call(json.as_object().get("stringify").as_function(), json, it.value->evaluated_data());
- data.set("value", stringified.to_string_without_side_effects());
- } else {
- data.set("value", it.value->data());
- }
-
- // Set type & meta
- auto& type = it.value->type();
- auto& meta = it.value->type_metadata();
- data.set("type", type.name());
-
- JsonObject metadata_object;
- metadata_object.set("length", meta.length);
- metadata_object.set("format", meta.format);
-#if 0
- metadata_object.set("alignment", alignment_to_string(meta.alignment));
-#endif
- save_format(meta.static_format, metadata_object);
-
- data.set("type_metadata", move(metadata_object));
-
- // Set conditional formats
- JsonArray conditional_formats;
- for (auto& fmt : it.value->conditional_formats()) {
- JsonObject fmt_object;
- fmt_object.set("condition", fmt.condition);
- save_format(fmt, fmt_object);
-
- conditional_formats.append(move(fmt_object));
- }
-
- data.set("conditional_formats", move(conditional_formats));
-
- auto& evaluated_formats = it.value->evaluated_formats();
- JsonObject evaluated_formats_obj;
-
- save_format(evaluated_formats, evaluated_formats_obj);
- data.set("evaluated_formats", move(evaluated_formats_obj));
-
- cells.set(key, move(data));
- }
- object.set("cells", move(cells));
-
- return object;
-}
-
-Vector<Vector<String>> Sheet::to_xsv() const
-{
- Vector<Vector<String>> data;
-
- auto bottom_right = written_data_bounds();
-
- // First row = headers.
- size_t column_count = m_columns.size();
- if (columns_are_standard()) {
- column_count = convert_from_string(bottom_right.column) + 1;
- Vector<String> cols;
- for (size_t i = 0; i < column_count; ++i)
- cols.append(m_columns[i]);
- data.append(move(cols));
- } else {
- data.append(m_columns);
- }
-
- for (size_t i = 0; i <= bottom_right.row; ++i) {
- Vector<String> row;
- row.resize(column_count);
- for (size_t j = 0; j < column_count; ++j) {
- auto cell = at({ m_columns[j], i });
- if (cell)
- row[j] = cell->typed_display();
- }
-
- data.append(move(row));
- }
-
- return data;
-}
-
-RefPtr<Sheet> Sheet::from_xsv(const Reader::XSV& xsv, Workbook& workbook)
-{
- auto cols = xsv.headers();
- auto rows = xsv.size();
-
- auto sheet = adopt(*new Sheet(workbook));
- sheet->m_columns = cols;
- for (size_t i = 0; i < max(rows, Sheet::default_row_count); ++i)
- sheet->add_row();
- if (sheet->columns_are_standard()) {
- for (size_t i = sheet->m_columns.size(); i < Sheet::default_column_count; ++i)
- sheet->add_column();
- }
-
- for (auto row : xsv) {
- for (size_t i = 0; i < cols.size(); ++i) {
- auto str = row[i];
- if (str.is_empty())
- continue;
- Position position { cols[i], row.index() };
- auto cell = make<Cell>(str, position, *sheet);
- sheet->m_cells.set(position, move(cell));
- }
- }
-
- return sheet;
-}
-
-JsonObject Sheet::gather_documentation() const
-{
- JsonObject object;
- const JS::PropertyName doc_name { "__documentation" };
-
- auto add_docs_from = [&](auto& it, auto& global_object) {
- auto value = global_object.get(it.key);
- if (!value.is_function() && !value.is_object())
- return;
-
- auto& value_object = value.is_object() ? value.as_object() : value.as_function();
- if (!value_object.has_own_property(doc_name))
- return;
-
- dbgln("Found '{}'", it.key.to_display_string());
- auto doc = value_object.get(doc_name);
- if (!doc.is_string())
- return;
-
- JsonParser parser(doc.to_string_without_side_effects());
- auto doc_object = parser.parse();
-
- if (doc_object.has_value())
- object.set(it.key.to_display_string(), doc_object.value());
- else
- dbgln("Sheet::gather_documentation(): Failed to parse the documentation for '{}'!", it.key.to_display_string());
- };
-
- for (auto& it : interpreter().global_object().shape().property_table())
- add_docs_from(it, interpreter().global_object());
-
- for (auto& it : global_object().shape().property_table())
- add_docs_from(it, global_object());
-
- m_cached_documentation = move(object);
- return m_cached_documentation.value();
-}
-
-String Sheet::generate_inline_documentation_for(StringView function, size_t argument_index)
-{
- if (!m_cached_documentation.has_value())
- gather_documentation();
-
- auto& docs = m_cached_documentation.value();
- auto entry = docs.get(function);
- if (entry.is_null() || !entry.is_object())
- return String::formatted("{}(...???{})", function, argument_index);
-
- auto& entry_object = entry.as_object();
- size_t argc = entry_object.get("argc").to_int(0);
- auto argnames_value = entry_object.get("argnames");
- if (!argnames_value.is_array())
- return String::formatted("{}(...{}???{})", function, argc, argument_index);
- auto& argnames = argnames_value.as_array();
- StringBuilder builder;
- builder.appendff("{}(", function);
- for (size_t i = 0; i < (size_t)argnames.size(); ++i) {
- if (i != 0 && i < (size_t)argnames.size())
- builder.append(", ");
- if (i == argument_index)
- builder.append('<');
- else if (i >= argc)
- builder.append('[');
- builder.append(argnames[i].to_string());
- if (i == argument_index)
- builder.append('>');
- else if (i >= argc)
- builder.append(']');
- }
-
- builder.append(')');
- return builder.build();
-}
-
-}
diff --git a/Applications/Spreadsheet/Spreadsheet.h b/Applications/Spreadsheet/Spreadsheet.h
deleted file mode 100644
index bbef6c8116..0000000000
--- a/Applications/Spreadsheet/Spreadsheet.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Cell.h"
-#include "Forward.h"
-#include "Readers/XSV.h"
-#include <AK/HashMap.h>
-#include <AK/HashTable.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/Traits.h>
-#include <AK/Types.h>
-#include <AK/WeakPtr.h>
-#include <AK/Weakable.h>
-#include <LibCore/Object.h>
-#include <LibJS/Interpreter.h>
-
-namespace Spreadsheet {
-
-class Sheet : public Core::Object {
- C_OBJECT(Sheet);
-
-public:
- constexpr static size_t default_row_count = 100;
- constexpr static size_t default_column_count = 26;
-
- ~Sheet();
-
- static Optional<Position> parse_cell_name(const StringView&);
- Optional<size_t> column_index(const StringView& column_name) const;
- Optional<String> column_arithmetic(const StringView& column_name, int offset);
-
- Cell* from_url(const URL&);
- const Cell* from_url(const URL& url) const { return const_cast<Sheet*>(this)->from_url(url); }
- Optional<Position> position_from_url(const URL& url) const;
-
- /// Resolve 'offset' to an absolute position assuming 'base' is at 'offset_base'.
- /// Effectively, "Walk the distance between 'offset' and 'offset_base' away from 'base'".
- Position offset_relative_to(const Position& base, const Position& offset, const Position& offset_base) const;
-
- JsonObject to_json() const;
- static RefPtr<Sheet> from_json(const JsonObject&, Workbook&);
-
- Vector<Vector<String>> to_xsv() const;
- static RefPtr<Sheet> from_xsv(const Reader::XSV&, Workbook&);
-
- const String& name() const { return m_name; }
- void set_name(const StringView& name) { m_name = name; }
-
- JsonObject gather_documentation() const;
-
- const HashTable<Position>& selected_cells() const { return m_selected_cells; }
- HashTable<Position>& selected_cells() { return m_selected_cells; }
- const HashMap<Position, NonnullOwnPtr<Cell>>& cells() const { return m_cells; }
- HashMap<Position, NonnullOwnPtr<Cell>>& cells() { return m_cells; }
-
- Cell* at(const Position& position);
- const Cell* at(const Position& position) const { return const_cast<Sheet*>(this)->at(position); }
-
- const Cell* at(const StringView& name) const { return const_cast<Sheet*>(this)->at(name); }
- Cell* at(const StringView&);
-
- const Cell& ensure(const Position& position) const { return const_cast<Sheet*>(this)->ensure(position); }
- Cell& ensure(const Position& position)
- {
- if (auto cell = at(position))
- return *cell;
-
- m_cells.set(position, make<Cell>(String::empty(), position, *this));
- return *at(position);
- }
-
- size_t add_row();
- String add_column();
-
- size_t row_count() const { return m_rows; }
- size_t column_count() const { return m_columns.size(); }
- const Vector<String>& columns() const { return m_columns; }
- const String& column(size_t index)
- {
- for (size_t i = column_count(); i < index; ++i)
- add_column();
-
- ASSERT(column_count() > index);
- return m_columns[index];
- }
- const String& column(size_t index) const
- {
- ASSERT(column_count() > index);
- return m_columns[index];
- }
-
- void update();
- void update(Cell&);
- void disable_updates() { m_should_ignore_updates = true; }
- void enable_updates()
- {
- m_should_ignore_updates = false;
- if (m_update_requested) {
- m_update_requested = false;
- update();
- }
- }
-
- struct ValueAndException {
- JS::Value value;
- JS::Exception* exception { nullptr };
- };
- ValueAndException evaluate(const StringView&, Cell* = nullptr);
- JS::Interpreter& interpreter() const;
- SheetGlobalObject& global_object() const { return *m_global_object; }
-
- Cell*& current_evaluated_cell() { return m_current_cell_being_evaluated; }
- bool has_been_visited(Cell* cell) const { return m_visited_cells_in_update.contains(cell); }
-
- const Workbook& workbook() const { return m_workbook; }
-
- void copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to = {});
-
- /// Gives the bottom-right corner of the smallest bounding box containing all the written data.
- Position written_data_bounds() const;
-
- bool columns_are_standard() const;
-
- String generate_inline_documentation_for(StringView function, size_t argument_index);
-
-private:
- explicit Sheet(Workbook&);
- explicit Sheet(const StringView& name, Workbook&);
-
- String m_name;
- Vector<String> m_columns;
- size_t m_rows { 0 };
- HashMap<Position, NonnullOwnPtr<Cell>> m_cells;
- HashTable<Position> m_selected_cells;
-
- Workbook& m_workbook;
- mutable SheetGlobalObject* m_global_object;
-
- Cell* m_current_cell_being_evaluated { nullptr };
-
- HashTable<Cell*> m_visited_cells_in_update;
- bool m_should_ignore_updates { false };
- bool m_update_requested { false };
- mutable Optional<JsonObject> m_cached_documentation;
-};
-
-}
-
-namespace AK {
-
-template<>
-struct Traits<Spreadsheet::Position> : public GenericTraits<Spreadsheet::Position> {
- static constexpr bool is_trivial() { return false; }
- static unsigned hash(const Spreadsheet::Position& p)
- {
- return pair_int_hash(
- string_hash(p.column.characters(), p.column.length()),
- u64_hash(p.row));
- }
-};
-
-}
diff --git a/Applications/Spreadsheet/SpreadsheetModel.cpp b/Applications/Spreadsheet/SpreadsheetModel.cpp
deleted file mode 100644
index 70193e4b63..0000000000
--- a/Applications/Spreadsheet/SpreadsheetModel.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SpreadsheetModel.h"
-#include "ConditionalFormatting.h"
-#include <AK/URL.h>
-#include <LibGUI/AbstractView.h>
-#include <LibJS/Runtime/Error.h>
-#include <LibJS/Runtime/Object.h>
-
-namespace Spreadsheet {
-
-SheetModel::~SheetModel()
-{
-}
-
-GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- if (!index.is_valid())
- return {};
-
- if (role == GUI::ModelRole::Display) {
- const auto* cell = m_sheet->at({ m_sheet->column(index.column()), (size_t)index.row() });
- if (!cell)
- return String::empty();
-
- if (cell->kind() == Spreadsheet::Cell::Formula) {
- if (auto exception = cell->exception()) {
- StringBuilder builder;
- builder.append("Error: ");
- auto value = exception->value();
- if (value.is_object()) {
- auto& object = value.as_object();
- if (is<JS::Error>(object)) {
- auto error = object.get("message").to_string_without_side_effects();
- builder.append(error);
- return builder.to_string();
- }
- }
- auto error = value.to_string(cell->sheet().global_object());
- // This is annoying, but whatever.
- cell->sheet().interpreter().vm().clear_exception();
-
- builder.append(error);
- return builder.to_string();
- }
- }
-
- return cell->typed_display();
- }
-
- if (role == GUI::ModelRole::MimeData)
- return Position { m_sheet->column(index.column()), (size_t)index.row() }.to_url().to_string();
-
- if (role == GUI::ModelRole::TextAlignment) {
- const auto* cell = m_sheet->at({ m_sheet->column(index.column()), (size_t)index.row() });
- if (!cell)
- return {};
-
- return cell->type_metadata().alignment;
- }
-
- if (role == GUI::ModelRole::ForegroundColor) {
- const auto* cell = m_sheet->at({ m_sheet->column(index.column()), (size_t)index.row() });
- if (!cell)
- return {};
-
- if (cell->kind() == Spreadsheet::Cell::Formula) {
- if (cell->exception())
- return Color(Color::Red);
- }
-
- if (cell->evaluated_formats().foreground_color.has_value())
- return cell->evaluated_formats().foreground_color.value();
-
- if (auto color = cell->type_metadata().static_format.foreground_color; color.has_value())
- return color.value();
-
- return {};
- }
-
- if (role == GUI::ModelRole::BackgroundColor) {
- const auto* cell = m_sheet->at({ m_sheet->column(index.column()), (size_t)index.row() });
- if (!cell)
- return {};
-
- if (cell->evaluated_formats().background_color.has_value())
- return cell->evaluated_formats().background_color.value();
-
- if (auto color = cell->type_metadata().static_format.background_color; color.has_value())
- return color.value();
-
- return {};
- }
-
- return {};
-}
-
-RefPtr<Core::MimeData> SheetModel::mime_data(const GUI::ModelSelection& selection) const
-{
- auto mime_data = GUI::Model::mime_data(selection);
-
- bool first = true;
- const GUI::ModelIndex* cursor = nullptr;
- const_cast<SheetModel*>(this)->for_each_view([&](const GUI::AbstractView& view) {
- if (!first)
- return;
- cursor = &view.cursor_index();
- first = false;
- });
-
- ASSERT(cursor);
-
- Position cursor_position { m_sheet->column(cursor->column()), (size_t)cursor->row() };
- auto new_data = String::formatted("{}\n{}",
- cursor_position.to_url().to_string(),
- StringView(mime_data->data("text/x-spreadsheet-data")));
- mime_data->set_data("text/x-spreadsheet-data", new_data.to_byte_buffer());
-
- return mime_data;
-}
-
-String SheetModel::column_name(int index) const
-{
- if (index < 0)
- return {};
-
- return m_sheet->column(index);
-}
-
-bool SheetModel::is_editable(const GUI::ModelIndex& index) const
-{
- if (!index.is_valid())
- return false;
-
- return true;
-}
-
-void SheetModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& value)
-{
- if (!index.is_valid())
- return;
-
- auto& cell = m_sheet->ensure({ m_sheet->column(index.column()), (size_t)index.row() });
- cell.set_data(value.to_string());
- update();
-}
-
-void SheetModel::update()
-{
- m_sheet->update();
- did_update(UpdateFlag::DontInvalidateIndexes);
-}
-
-}
diff --git a/Applications/Spreadsheet/SpreadsheetModel.h b/Applications/Spreadsheet/SpreadsheetModel.h
deleted file mode 100644
index 14527d4c37..0000000000
--- a/Applications/Spreadsheet/SpreadsheetModel.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Spreadsheet.h"
-#include <LibGUI/Model.h>
-
-namespace Spreadsheet {
-
-class SheetModel final : public GUI::Model {
-public:
- static NonnullRefPtr<SheetModel> create(Sheet& sheet) { return adopt(*new SheetModel(sheet)); }
- virtual ~SheetModel() override;
-
- virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_sheet->row_count(); }
- virtual int column_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_sheet->column_count(); }
- virtual String column_name(int) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual RefPtr<Core::MimeData> mime_data(const GUI::ModelSelection&) const override;
- virtual bool is_editable(const GUI::ModelIndex&) const override;
- virtual void set_data(const GUI::ModelIndex&, const GUI::Variant&) override;
- virtual void update() override;
- virtual bool is_column_sortable(int) const override { return false; }
- virtual StringView drag_data_type() const override { return "text/x-spreadsheet-data"; }
- Sheet& sheet() { return *m_sheet; }
-
-private:
- explicit SheetModel(Sheet& sheet)
- : m_sheet(sheet)
- {
- }
-
- NonnullRefPtr<Sheet> m_sheet;
-};
-
-}
diff --git a/Applications/Spreadsheet/SpreadsheetView.cpp b/Applications/Spreadsheet/SpreadsheetView.cpp
deleted file mode 100644
index 9762f77578..0000000000
--- a/Applications/Spreadsheet/SpreadsheetView.cpp
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SpreadsheetView.h"
-#include "CellTypeDialog.h"
-#include "SpreadsheetModel.h"
-#include <AK/ScopeGuard.h>
-#include <AK/URL.h>
-#include <LibCore/MimeData.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/HeaderView.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/ModelEditingDelegate.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/ScrollBar.h>
-#include <LibGUI/TableView.h>
-#include <LibGfx/Palette.h>
-
-namespace Spreadsheet {
-
-SpreadsheetView::~SpreadsheetView()
-{
-}
-
-void SpreadsheetView::EditingDelegate::set_value(const GUI::Variant& value)
-{
- if (value.as_string().is_null()) {
- StringModelEditingDelegate::set_value("");
- commit();
- return;
- }
-
- if (m_has_set_initial_value)
- return StringModelEditingDelegate::set_value(value);
-
- m_has_set_initial_value = true;
- const auto option = m_sheet.at({ m_sheet.column(index().column()), (size_t)index().row() });
- if (option)
- return StringModelEditingDelegate::set_value(option->source());
-
- StringModelEditingDelegate::set_value("");
-}
-
-void InfinitelyScrollableTableView::did_scroll()
-{
- TableView::did_scroll();
- auto& vscrollbar = vertical_scrollbar();
- auto& hscrollbar = horizontal_scrollbar();
- if (vscrollbar.is_visible() && vscrollbar.value() == vscrollbar.max()) {
- if (on_reaching_vertical_end)
- on_reaching_vertical_end();
- }
- if (hscrollbar.is_visible() && hscrollbar.value() == hscrollbar.max()) {
- if (on_reaching_horizontal_end)
- on_reaching_horizontal_end();
- }
-}
-
-void InfinitelyScrollableTableView::mousemove_event(GUI::MouseEvent& event)
-{
- if (auto model = this->model()) {
- auto index = index_at_event_position(event.position());
- if (!index.is_valid())
- return TableView::mousemove_event(event);
-
- auto& sheet = static_cast<SheetModel&>(*model).sheet();
- sheet.disable_updates();
- ScopeGuard sheet_update_enabler { [&] { sheet.enable_updates(); } };
-
- auto holding_left_button = !!(event.buttons() & GUI::MouseButton::Left);
- auto rect = content_rect(index);
- auto distance = rect.center().absolute_relative_distance_to(event.position());
- if (distance.x() >= rect.width() / 2 - 5 && distance.y() >= rect.height() / 2 - 5) {
- set_override_cursor(Gfx::StandardCursor::Crosshair);
- m_should_intercept_drag = false;
- if (holding_left_button) {
- m_has_committed_to_dragging = true;
- // Force a drag to happen by moving the mousedown position to the center of the cell.
- m_left_mousedown_position = rect.center();
- }
- } else if (!m_should_intercept_drag) {
- set_override_cursor(Gfx::StandardCursor::Arrow);
- if (!holding_left_button) {
- m_starting_selection_index = index;
- } else {
- m_should_intercept_drag = true;
- m_might_drag = false;
- }
- }
-
- if (holding_left_button && m_should_intercept_drag && !m_has_committed_to_dragging) {
- if (!m_starting_selection_index.is_valid())
- m_starting_selection_index = index;
-
- Vector<GUI::ModelIndex> new_selection;
- for (auto i = min(m_starting_selection_index.row(), index.row()), imax = max(m_starting_selection_index.row(), index.row()); i <= imax; ++i) {
- for (auto j = min(m_starting_selection_index.column(), index.column()), jmax = max(m_starting_selection_index.column(), index.column()); j <= jmax; ++j) {
- auto index = model->index(i, j);
- if (index.is_valid())
- new_selection.append(move(index));
- }
- }
-
- if (!event.ctrl())
- selection().clear();
- selection().add_all(new_selection);
- }
- }
-
- TableView::mousemove_event(event);
-}
-
-void InfinitelyScrollableTableView::mouseup_event(GUI::MouseEvent& event)
-{
- m_should_intercept_drag = false;
- m_has_committed_to_dragging = false;
- TableView::mouseup_event(event);
-}
-
-void SpreadsheetView::update_with_model()
-{
- m_table_view->model()->update();
- m_table_view->update();
-}
-
-SpreadsheetView::SpreadsheetView(Sheet& sheet)
- : m_sheet(sheet)
-{
- set_layout<GUI::VerticalBoxLayout>().set_margins({ 2, 2, 2, 2 });
- m_table_view = add<InfinitelyScrollableTableView>();
- m_table_view->set_grid_style(GUI::TableView::GridStyle::Both);
- m_table_view->set_selection_behavior(GUI::AbstractView::SelectionBehavior::SelectItems);
- m_table_view->set_edit_triggers(GUI::AbstractView::EditTrigger::EditKeyPressed | GUI::AbstractView::AnyKeyPressed | GUI::AbstractView::DoubleClicked);
- m_table_view->set_tab_key_navigation_enabled(true);
- m_table_view->row_header().set_visible(true);
- m_table_view->set_model(SheetModel::create(*m_sheet));
- m_table_view->on_reaching_vertical_end = [&]() {
- for (size_t i = 0; i < 100; ++i) {
- auto index = m_sheet->add_row();
- m_table_view->set_column_painting_delegate(index, make<TableCellPainter>(*m_table_view));
- };
- update_with_model();
- };
- m_table_view->on_reaching_horizontal_end = [&]() {
- for (size_t i = 0; i < 10; ++i) {
- m_sheet->add_column();
- auto last_column_index = m_sheet->column_count() - 1;
- m_table_view->set_column_width(last_column_index, 50);
- m_table_view->set_column_header_alignment(last_column_index, Gfx::TextAlignment::Center);
- }
- update_with_model();
- };
-
- set_focus_proxy(m_table_view);
-
- // FIXME: This is dumb.
- for (size_t i = 0; i < m_sheet->column_count(); ++i) {
- m_table_view->set_column_painting_delegate(i, make<TableCellPainter>(*m_table_view));
- m_table_view->set_column_width(i, 50);
- m_table_view->set_column_header_alignment(i, Gfx::TextAlignment::Center);
- }
-
- m_table_view->set_alternating_row_colors(false);
- m_table_view->set_highlight_selected_rows(false);
- m_table_view->set_editable(true);
- m_table_view->aid_create_editing_delegate = [this](auto&) {
- auto delegate = make<EditingDelegate>(*m_sheet);
- delegate->on_cursor_key_pressed = [this](auto& event) {
- m_table_view->stop_editing();
- m_table_view->event(event);
- };
- return delegate;
- };
-
- m_table_view->on_selection_change = [&] {
- m_sheet->selected_cells().clear();
- for (auto& index : m_table_view->selection().indexes()) {
- Position position { m_sheet->column(index.column()), (size_t)index.row() };
- m_sheet->selected_cells().set(position);
- }
-
- if (m_table_view->selection().is_empty() && on_selection_dropped)
- return on_selection_dropped();
-
- Vector<Position> selected_positions;
- selected_positions.ensure_capacity(m_table_view->selection().size());
- for (auto& selection : m_table_view->selection().indexes())
- selected_positions.empend(m_sheet->column(selection.column()), (size_t)selection.row());
-
- if (on_selection_changed) {
- on_selection_changed(move(selected_positions));
- update_with_model();
- };
- };
-
- m_table_view->on_activation = [this](auto&) {
- m_table_view->move_cursor(GUI::AbstractView::CursorMovement::Down, GUI::AbstractView::SelectionUpdate::Set);
- };
-
- m_table_view->on_context_menu_request = [&](const GUI::ModelIndex&, const GUI::ContextMenuEvent& event) {
- // NOTE: We ignore the specific cell for now.
- m_cell_range_context_menu->popup(event.screen_position());
- };
-
- m_cell_range_context_menu = GUI::Menu::construct();
- m_cell_range_context_menu->add_action(GUI::Action::create("Type and Formatting...", [this](auto&) {
- Vector<Position> positions;
- for (auto& index : m_table_view->selection().indexes()) {
- Position position { m_sheet->column(index.column()), (size_t)index.row() };
- positions.append(move(position));
- }
-
- if (positions.is_empty()) {
- auto& index = m_table_view->cursor_index();
- Position position { m_sheet->column(index.column()), (size_t)index.row() };
- positions.append(move(position));
- }
-
- auto dialog = CellTypeDialog::construct(positions, *m_sheet, window());
- if (dialog->exec() == GUI::Dialog::ExecOK) {
- for (auto& position : positions) {
- auto& cell = m_sheet->ensure(position);
- cell.set_type(dialog->type());
- cell.set_type_metadata(dialog->metadata());
- cell.set_conditional_formats(dialog->conditional_formats());
- }
-
- m_table_view->update();
- }
- }));
-
- m_table_view->on_drop = [&](const GUI::ModelIndex& index, const GUI::DropEvent& event) {
- if (!index.is_valid())
- return;
-
- ScopeGuard update_after_drop { [this] { update(); } };
-
- if (event.mime_data().has_format("text/x-spreadsheet-data")) {
- auto data = event.mime_data().data("text/x-spreadsheet-data");
- StringView urls { data.data(), data.size() };
- Vector<Position> source_positions, target_positions;
-
- for (auto& line : urls.lines(false)) {
- auto position = m_sheet->position_from_url(line);
- if (position.has_value())
- source_positions.append(position.release_value());
- }
-
- // Drop always has a single target.
- Position target { m_sheet->column(index.column()), (size_t)index.row() };
- target_positions.append(move(target));
-
- if (source_positions.is_empty())
- return;
-
- auto first_position = source_positions.take_first();
- m_sheet->copy_cells(move(source_positions), move(target_positions), first_position);
-
- return;
- }
-
- if (event.mime_data().has_text()) {
- auto* target_cell = m_sheet->at({ m_sheet->column(index.column()), (size_t)index.row() });
- ASSERT(target_cell);
-
- target_cell->set_data(event.text());
- return;
- }
- };
-}
-
-void SpreadsheetView::hide_event(GUI::HideEvent&)
-{
- if (on_selection_dropped)
- on_selection_dropped();
-}
-
-void SpreadsheetView::show_event(GUI::ShowEvent&)
-{
- if (on_selection_changed && !m_table_view->selection().is_empty()) {
- Vector<Position> selected_positions;
- selected_positions.ensure_capacity(m_table_view->selection().size());
- for (auto& selection : m_table_view->selection().indexes())
- selected_positions.empend(m_sheet->column(selection.column()), (size_t)selection.row());
-
- on_selection_changed(move(selected_positions));
- }
-}
-
-void SpreadsheetView::TableCellPainter::paint(GUI::Painter& painter, const Gfx::IntRect& rect, const Gfx::Palette& palette, const GUI::ModelIndex& index)
-{
- // Draw a border.
- // Undo the horizontal padding done by the table view...
- auto cell_rect = rect.inflated(m_table_view.horizontal_padding() * 2, 0);
-
- if (auto bg = index.data(GUI::ModelRole::BackgroundColor); bg.is_color())
- painter.fill_rect(cell_rect, bg.as_color());
-
- if (m_table_view.selection().contains(index)) {
- Color fill_color = palette.selection();
- fill_color.set_alpha(80);
- painter.fill_rect(cell_rect, fill_color);
- }
-
- auto text_color = index.data(GUI::ModelRole::ForegroundColor).to_color(palette.color(m_table_view.foreground_role()));
- auto data = index.data();
- auto text_alignment = index.data(GUI::ModelRole::TextAlignment).to_text_alignment(Gfx::TextAlignment::CenterRight);
- painter.draw_text(rect, data.to_string(), m_table_view.font_for_index(index), text_alignment, text_color, Gfx::TextElision::Right);
-}
-
-}
diff --git a/Applications/Spreadsheet/SpreadsheetView.h b/Applications/Spreadsheet/SpreadsheetView.h
deleted file mode 100644
index bc07d31bc3..0000000000
--- a/Applications/Spreadsheet/SpreadsheetView.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Spreadsheet.h"
-#include <LibGUI/AbstractTableView.h>
-#include <LibGUI/ModelEditingDelegate.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/Widget.h>
-#include <string.h>
-
-namespace Spreadsheet {
-
-class CellEditor final : public GUI::TextEditor {
- C_OBJECT(CellEditor);
-
-public:
- virtual ~CellEditor() { }
-
- Function<void(GUI::KeyEvent&)> on_cursor_key_pressed;
-
-private:
- CellEditor()
- : TextEditor(TextEditor::Type::SingleLine)
- {
- }
-
- static bool is_navigation(const GUI::KeyEvent& event)
- {
- if (event.modifiers() == KeyModifier::Mod_Shift && event.key() == KeyCode::Key_Tab)
- return true;
-
- if (event.modifiers())
- return false;
-
- switch (event.key()) {
- case KeyCode::Key_Tab:
- case KeyCode::Key_Left:
- case KeyCode::Key_Right:
- case KeyCode::Key_Up:
- case KeyCode::Key_Down:
- case KeyCode::Key_Return:
- return true;
- default:
- return false;
- }
- }
-
- virtual void keydown_event(GUI::KeyEvent& event) override
- {
- if (is_navigation(event))
- on_cursor_key_pressed(event);
- else
- TextEditor::keydown_event(event);
- }
-};
-
-class InfinitelyScrollableTableView : public GUI::TableView {
- C_OBJECT(InfinitelyScrollableTableView)
-public:
- Function<void()> on_reaching_vertical_end;
- Function<void()> on_reaching_horizontal_end;
-
-private:
- virtual void did_scroll() override;
- virtual void mousemove_event(GUI::MouseEvent&) override;
- virtual void mouseup_event(GUI::MouseEvent&) override;
-
- bool m_should_intercept_drag { false };
- bool m_has_committed_to_dragging { false };
- GUI::ModelIndex m_starting_selection_index;
-};
-
-class SpreadsheetView final : public GUI::Widget {
- C_OBJECT(SpreadsheetView);
-
-public:
- ~SpreadsheetView();
-
- const Sheet& sheet() const { return *m_sheet; }
- Sheet& sheet() { return *m_sheet; }
-
- const GUI::ModelIndex* cursor() const
- {
- return &m_table_view->cursor_index();
- }
-
- Function<void(Vector<Position>&&)> on_selection_changed;
- Function<void()> on_selection_dropped;
-
-private:
- virtual void hide_event(GUI::HideEvent&) override;
- virtual void show_event(GUI::ShowEvent&) override;
-
- void update_with_model();
-
- SpreadsheetView(Sheet&);
-
- class EditingDelegate final : public GUI::StringModelEditingDelegate {
- public:
- EditingDelegate(const Sheet& sheet)
- : m_sheet(sheet)
- {
- }
- virtual void set_value(const GUI::Variant& value) override;
-
- virtual RefPtr<Widget> create_widget() override
- {
- auto textbox = CellEditor::construct();
- textbox->on_escape_pressed = [this] {
- rollback();
- };
- textbox->on_cursor_key_pressed = [this](auto& event) {
- commit();
- on_cursor_key_pressed(event);
- };
- return textbox;
- }
-
- Function<void(GUI::KeyEvent&)> on_cursor_key_pressed;
-
- private:
- bool m_has_set_initial_value { false };
- const Sheet& m_sheet;
- };
-
- class TableCellPainter final : public GUI::TableCellPaintingDelegate {
- public:
- TableCellPainter(const GUI::TableView& view)
- : m_table_view(view)
- {
- }
- void paint(GUI::Painter&, const Gfx::IntRect&, const Gfx::Palette&, const GUI::ModelIndex&) override;
-
- private:
- const GUI::TableView& m_table_view;
- };
-
- NonnullRefPtr<Sheet> m_sheet;
- RefPtr<InfinitelyScrollableTableView> m_table_view;
- RefPtr<GUI::Menu> m_cell_range_context_menu;
-};
-
-}
diff --git a/Applications/Spreadsheet/SpreadsheetWidget.cpp b/Applications/Spreadsheet/SpreadsheetWidget.cpp
deleted file mode 100644
index 65e48e3f12..0000000000
--- a/Applications/Spreadsheet/SpreadsheetWidget.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "SpreadsheetWidget.h"
-#include "CellSyntaxHighlighter.h"
-#include "HelpWindow.h"
-#include "LibGUI/InputBox.h"
-#include <LibCore/File.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGfx/FontDatabase.h>
-#include <string.h>
-
-namespace Spreadsheet {
-
-SpreadsheetWidget::SpreadsheetWidget(NonnullRefPtrVector<Sheet>&& sheets, bool should_add_sheet_if_empty)
- : m_workbook(make<Workbook>(move(sheets)))
-{
- set_fill_with_background_color(true);
- set_layout<GUI::VerticalBoxLayout>().set_margins({ 2, 2, 2, 2 });
- auto& container = add<GUI::VerticalSplitter>();
-
- auto& top_bar = container.add<GUI::Frame>();
- top_bar.set_layout<GUI::HorizontalBoxLayout>().set_spacing(1);
- top_bar.set_fixed_height(26);
- auto& current_cell_label = top_bar.add<GUI::Label>("");
- current_cell_label.set_fixed_width(50);
-
- auto& help_button = top_bar.add<GUI::Button>("🛈");
- help_button.set_fixed_size(20, 20);
- help_button.on_click = [&](auto) {
- auto docs = m_selected_view->sheet().gather_documentation();
- auto help_window = HelpWindow::the(window());
- help_window->set_docs(move(docs));
- help_window->show();
- };
-
- auto& cell_value_editor = top_bar.add<GUI::TextEditor>(GUI::TextEditor::Type::SingleLine);
- cell_value_editor.set_font(Gfx::FontDatabase::default_fixed_width_font());
- cell_value_editor.set_scrollbars_enabled(false);
-
- cell_value_editor.set_syntax_highlighter(make<CellSyntaxHighlighter>());
- cell_value_editor.set_enabled(false);
- current_cell_label.set_enabled(false);
-
- m_tab_widget = container.add<GUI::TabWidget>();
- m_tab_widget->set_tab_position(GUI::TabWidget::TabPosition::Bottom);
-
- m_cell_value_editor = cell_value_editor;
- m_current_cell_label = current_cell_label;
- m_inline_documentation_window = GUI::Window::construct(window());
- m_inline_documentation_window->set_rect(m_cell_value_editor->rect().translated(0, m_cell_value_editor->height() + 7).inflated(6, 6));
- m_inline_documentation_window->set_window_type(GUI::WindowType::Tooltip);
- m_inline_documentation_window->set_resizable(false);
- auto& inline_widget = m_inline_documentation_window->set_main_widget<GUI::Frame>();
- inline_widget.set_fill_with_background_color(true);
- inline_widget.set_layout<GUI::VerticalBoxLayout>().set_margins({ 4, 4, 4, 4 });
- inline_widget.set_frame_shape(Gfx::FrameShape::Box);
- m_inline_documentation_label = inline_widget.add<GUI::Label>();
- m_inline_documentation_label->set_fill_with_background_color(true);
- m_inline_documentation_label->set_autosize(false);
- m_inline_documentation_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- if (!m_workbook->has_sheets() && should_add_sheet_if_empty)
- m_workbook->add_sheet("Sheet 1");
-
- m_tab_context_menu = GUI::Menu::construct();
- auto rename_action = GUI::Action::create("Rename...", [this](auto&) {
- ASSERT(m_tab_context_menu_sheet_view);
-
- auto& sheet = m_tab_context_menu_sheet_view->sheet();
- String new_name;
- if (GUI::InputBox::show(new_name, window(), String::formatted("New name for '{}'", sheet.name()), "Rename sheet") == GUI::Dialog::ExecOK) {
- sheet.set_name(new_name);
- sheet.update();
- m_tab_widget->set_tab_title(static_cast<GUI::Widget&>(*m_tab_context_menu_sheet_view), new_name);
- }
- });
- m_tab_context_menu->add_action(rename_action);
- m_tab_context_menu->add_action(GUI::Action::create("Add new sheet...", [this](auto&) {
- String name;
- if (GUI::InputBox::show(name, window(), "Name for new sheet", "Create sheet") == GUI::Dialog::ExecOK) {
- NonnullRefPtrVector<Sheet> new_sheets;
- new_sheets.append(m_workbook->add_sheet(name));
- setup_tabs(move(new_sheets));
- }
- }));
-
- setup_tabs(m_workbook->sheets());
-}
-
-void SpreadsheetWidget::resize_event(GUI::ResizeEvent& event)
-{
- GUI::Widget::resize_event(event);
- if (m_inline_documentation_window && m_cell_value_editor && window())
- m_inline_documentation_window->set_rect(m_cell_value_editor->screen_relative_rect().translated(0, m_cell_value_editor->height() + 7).inflated(6, 6));
-}
-
-void SpreadsheetWidget::setup_tabs(NonnullRefPtrVector<Sheet> new_sheets)
-{
- RefPtr<GUI::Widget> first_tab_widget;
- for (auto& sheet : new_sheets) {
- auto& tab = m_tab_widget->add_tab<SpreadsheetView>(sheet.name(), sheet);
- if (!first_tab_widget)
- first_tab_widget = &tab;
- }
-
- auto change = [&](auto& selected_widget) {
- if (m_selected_view) {
- m_selected_view->on_selection_changed = nullptr;
- m_selected_view->on_selection_dropped = nullptr;
- };
- m_selected_view = &static_cast<SpreadsheetView&>(selected_widget);
- m_selected_view->on_selection_changed = [&](Vector<Position>&& selection) {
- if (selection.is_empty()) {
- m_current_cell_label->set_enabled(false);
- m_current_cell_label->set_text({});
- m_cell_value_editor->on_change = nullptr;
- m_cell_value_editor->on_focusin = nullptr;
- m_cell_value_editor->on_focusout = nullptr;
- m_cell_value_editor->set_text("");
- m_cell_value_editor->set_enabled(false);
- return;
- }
-
- if (selection.size() == 1) {
- auto& position = selection.first();
- StringBuilder builder;
- builder.append(position.column);
- builder.appendff("{}", position.row);
- m_current_cell_label->set_enabled(true);
- m_current_cell_label->set_text(builder.string_view());
-
- auto& cell = m_selected_view->sheet().ensure(position);
- m_cell_value_editor->on_change = nullptr;
- m_cell_value_editor->set_text(cell.source());
- m_cell_value_editor->on_change = [&] {
- auto text = m_cell_value_editor->text();
- // FIXME: Lines?
- auto offset = m_cell_value_editor->cursor().column();
- try_generate_tip_for_input_expression(text, offset);
- cell.set_data(move(text));
- m_selected_view->sheet().update();
- update();
- };
- m_cell_value_editor->set_enabled(true);
- static_cast<CellSyntaxHighlighter*>(const_cast<GUI::SyntaxHighlighter*>(m_cell_value_editor->syntax_highlighter()))->set_cell(&cell);
- return;
- }
-
- // There are many cells selected, change all of them.
- StringBuilder builder;
- builder.appendff("<{}>", selection.size());
- m_current_cell_label->set_enabled(true);
- m_current_cell_label->set_text(builder.string_view());
-
- Vector<Cell*> cells;
- for (auto& position : selection)
- cells.append(&m_selected_view->sheet().ensure(position));
-
- auto first_cell = cells.first();
- m_cell_value_editor->on_change = nullptr;
- m_cell_value_editor->set_text("");
- m_should_change_selected_cells = false;
- m_cell_value_editor->on_focusin = [this] { m_should_change_selected_cells = true; };
- m_cell_value_editor->on_focusout = [this] { m_should_change_selected_cells = false; };
- m_cell_value_editor->on_change = [cells = move(cells), this] {
- if (m_should_change_selected_cells) {
- auto text = m_cell_value_editor->text();
- // FIXME: Lines?
- auto offset = m_cell_value_editor->cursor().column();
- try_generate_tip_for_input_expression(text, offset);
- for (auto* cell : cells)
- cell->set_data(text);
- m_selected_view->sheet().update();
- update();
- }
- };
- m_cell_value_editor->set_enabled(true);
- static_cast<CellSyntaxHighlighter*>(const_cast<GUI::SyntaxHighlighter*>(m_cell_value_editor->syntax_highlighter()))->set_cell(first_cell);
- };
- m_selected_view->on_selection_dropped = [&]() {
- m_cell_value_editor->set_enabled(false);
- static_cast<CellSyntaxHighlighter*>(const_cast<GUI::SyntaxHighlighter*>(m_cell_value_editor->syntax_highlighter()))->set_cell(nullptr);
- m_cell_value_editor->set_text("");
- m_current_cell_label->set_enabled(false);
- m_current_cell_label->set_text("");
- };
- };
-
- if (first_tab_widget)
- change(*first_tab_widget);
-
- m_tab_widget->on_change = [change = move(change)](auto& selected_widget) {
- change(selected_widget);
- };
-
- m_tab_widget->on_context_menu_request = [&](auto& widget, auto& event) {
- m_tab_context_menu_sheet_view = widget;
- m_tab_context_menu->popup(event.screen_position());
- };
-}
-
-void SpreadsheetWidget::try_generate_tip_for_input_expression(StringView source, size_t cursor_offset)
-{
- m_inline_documentation_window->set_rect(m_cell_value_editor->screen_relative_rect().translated(0, m_cell_value_editor->height() + 7).inflated(6, 6));
- if (!m_selected_view || !source.starts_with('=')) {
- m_inline_documentation_window->hide();
- return;
- }
- auto maybe_function_and_argument = get_function_and_argument_index(source.substring_view(0, cursor_offset));
- if (!maybe_function_and_argument.has_value()) {
- m_inline_documentation_window->hide();
- return;
- }
-
- auto& [name, index] = maybe_function_and_argument.value();
- auto& sheet = m_selected_view->sheet();
- auto text = sheet.generate_inline_documentation_for(name, index);
- if (text.is_empty()) {
- m_inline_documentation_window->hide();
- } else {
- m_inline_documentation_label->set_text(move(text));
- m_inline_documentation_window->show();
- }
-}
-
-void SpreadsheetWidget::save(const StringView& filename)
-{
- auto result = m_workbook->save(filename);
- if (result.is_error())
- GUI::MessageBox::show_error(window(), result.error());
-}
-
-void SpreadsheetWidget::load(const StringView& filename)
-{
- auto result = m_workbook->load(filename);
- if (result.is_error()) {
- GUI::MessageBox::show_error(window(), result.error());
- return;
- }
-
- m_tab_widget->on_change = nullptr;
- m_cell_value_editor->on_change = nullptr;
- m_current_cell_label->set_text("");
- m_should_change_selected_cells = false;
- while (auto* widget = m_tab_widget->active_widget()) {
- m_tab_widget->remove_tab(*widget);
- }
-
- setup_tabs(m_workbook->sheets());
-}
-
-bool SpreadsheetWidget::request_close()
-{
- if (!m_workbook->dirty())
- return true;
-
- auto result = GUI::MessageBox::show(window(), "The spreadsheet has been modified. Would you like to save?", "Unsaved changes", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNoCancel);
-
- if (result == GUI::MessageBox::ExecYes) {
- if (current_filename().is_empty()) {
- String name = "workbook";
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window(), name, "sheets");
- if (!save_path.has_value())
- return false;
-
- save(save_path.value());
- } else {
- save(current_filename());
- }
- return true;
- }
-
- if (result == GUI::MessageBox::ExecNo)
- return true;
-
- return false;
-}
-
-void SpreadsheetWidget::add_sheet()
-{
- StringBuilder name;
- name.append("Sheet");
- name.appendff(" {}", m_workbook->sheets().size() + 1);
-
- NonnullRefPtrVector<Sheet> new_sheets;
- new_sheets.append(m_workbook->add_sheet(name.string_view()));
- setup_tabs(move(new_sheets));
-}
-
-void SpreadsheetWidget::add_sheet(NonnullRefPtr<Sheet>&& sheet)
-{
- ASSERT(m_workbook == &sheet->workbook());
-
- NonnullRefPtrVector<Sheet> new_sheets;
- new_sheets.append(move(sheet));
- m_workbook->sheets().append(new_sheets);
- setup_tabs(new_sheets);
-}
-
-void SpreadsheetWidget::set_filename(const String& filename)
-{
- if (m_workbook->set_filename(filename)) {
- StringBuilder builder;
- builder.append("Spreadsheet - ");
- builder.append(current_filename());
-
- window()->set_title(builder.string_view());
- window()->update();
- }
-}
-
-SpreadsheetWidget::~SpreadsheetWidget()
-{
-}
-}
diff --git a/Applications/Spreadsheet/SpreadsheetWidget.h b/Applications/Spreadsheet/SpreadsheetWidget.h
deleted file mode 100644
index b29fc557d6..0000000000
--- a/Applications/Spreadsheet/SpreadsheetWidget.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "SpreadsheetView.h"
-#include "Workbook.h"
-#include <AK/NonnullRefPtrVector.h>
-#include <LibGUI/Widget.h>
-
-namespace Spreadsheet {
-
-class SpreadsheetWidget final : public GUI::Widget {
- C_OBJECT(SpreadsheetWidget);
-
-public:
- ~SpreadsheetWidget();
-
- void save(const StringView& filename);
- void load(const StringView& filename);
- bool request_close();
- void add_sheet();
- void add_sheet(NonnullRefPtr<Sheet>&&);
-
- const String& current_filename() const { return m_workbook->current_filename(); }
- const Sheet& current_worksheet() const { return m_selected_view->sheet(); }
- Sheet& current_worksheet() { return m_selected_view->sheet(); }
- void set_filename(const String& filename);
-
- Workbook& workbook() { return *m_workbook; }
- const Workbook& workbook() const { return *m_workbook; }
-
- const GUI::ModelIndex* current_selection_cursor() const
- {
- if (!m_selected_view)
- return nullptr;
-
- return m_selected_view->cursor();
- }
-
-private:
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- explicit SpreadsheetWidget(NonnullRefPtrVector<Sheet>&& sheets = {}, bool should_add_sheet_if_empty = true);
-
- void setup_tabs(NonnullRefPtrVector<Sheet> new_sheets);
-
- void try_generate_tip_for_input_expression(StringView source, size_t offset);
-
- SpreadsheetView* m_selected_view { nullptr };
- RefPtr<GUI::Label> m_current_cell_label;
- RefPtr<GUI::TextEditor> m_cell_value_editor;
- RefPtr<GUI::Window> m_inline_documentation_window;
- RefPtr<GUI::Label> m_inline_documentation_label;
- RefPtr<GUI::TabWidget> m_tab_widget;
- RefPtr<GUI::Menu> m_tab_context_menu;
- RefPtr<SpreadsheetView> m_tab_context_menu_sheet_view;
- bool m_should_change_selected_cells { false };
-
- OwnPtr<Workbook> m_workbook;
-};
-
-}
diff --git a/Applications/Spreadsheet/Workbook.cpp b/Applications/Spreadsheet/Workbook.cpp
deleted file mode 100644
index db5bf16cb5..0000000000
--- a/Applications/Spreadsheet/Workbook.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "Workbook.h"
-#include "JSIntegration.h"
-#include "Readers/CSV.h"
-#include "Writers/CSV.h"
-#include <AK/ByteBuffer.h>
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonObjectSerializer.h>
-#include <AK/JsonParser.h>
-#include <AK/Stream.h>
-#include <LibCore/File.h>
-#include <LibCore/FileStream.h>
-#include <LibCore/MimeData.h>
-#include <LibJS/Parser.h>
-#include <LibJS/Runtime/GlobalObject.h>
-#include <string.h>
-
-namespace Spreadsheet {
-
-static JS::VM& global_vm()
-{
- static RefPtr<JS::VM> vm;
- if (!vm)
- vm = JS::VM::create();
- return *vm;
-}
-
-Workbook::Workbook(NonnullRefPtrVector<Sheet>&& sheets)
- : m_sheets(move(sheets))
- , m_interpreter(JS::Interpreter::create<JS::GlobalObject>(global_vm()))
- , m_interpreter_scope(JS::VM::InterpreterExecutionScope(interpreter()))
-{
- m_workbook_object = interpreter().heap().allocate<WorkbookObject>(global_object(), *this);
- global_object().put("workbook", workbook_object());
-}
-
-bool Workbook::set_filename(const String& filename)
-{
- if (m_current_filename == filename)
- return false;
-
- m_current_filename = filename;
- return true;
-}
-
-Result<bool, String> Workbook::load(const StringView& filename)
-{
- auto file_or_error = Core::File::open(filename, Core::IODevice::OpenMode::ReadOnly);
- if (file_or_error.is_error()) {
- StringBuilder sb;
- sb.append("Failed to open ");
- sb.append(filename);
- sb.append(" for reading. Error: ");
- sb.append(file_or_error.error());
-
- return sb.to_string();
- }
-
- auto mime = Core::guess_mime_type_based_on_filename(filename);
-
- if (mime == "text/csv") {
- // FIXME: Prompt the user for settings.
- NonnullRefPtrVector<Sheet> sheets;
-
- auto sheet = Sheet::from_xsv(Reader::CSV(file_or_error.value()->read_all(), Reader::default_behaviours() | Reader::ParserBehaviour::ReadHeaders), *this);
- if (sheet)
- sheets.append(sheet.release_nonnull());
-
- m_sheets.clear();
- m_sheets = move(sheets);
- } else {
- // Assume JSON.
- auto json_value_option = JsonParser(file_or_error.value()->read_all()).parse();
- if (!json_value_option.has_value()) {
- StringBuilder sb;
- sb.append("Failed to parse ");
- sb.append(filename);
-
- return sb.to_string();
- }
-
- auto& json_value = json_value_option.value();
- if (!json_value.is_array()) {
- StringBuilder sb;
- sb.append("Did not find a spreadsheet in ");
- sb.append(filename);
-
- return sb.to_string();
- }
-
- NonnullRefPtrVector<Sheet> sheets;
-
- auto& json_array = json_value.as_array();
- json_array.for_each([&](auto& sheet_json) {
- if (!sheet_json.is_object())
- return IterationDecision::Continue;
-
- auto sheet = Sheet::from_json(sheet_json.as_object(), *this);
- if (!sheet)
- return IterationDecision::Continue;
-
- sheets.append(sheet.release_nonnull());
-
- return IterationDecision::Continue;
- });
-
- m_sheets.clear();
- m_sheets = move(sheets);
- }
-
- set_filename(filename);
-
- return true;
-}
-
-Result<bool, String> Workbook::save(const StringView& filename)
-{
- auto mime = Core::guess_mime_type_based_on_filename(filename);
- auto file = Core::File::construct(filename);
- file->open(Core::IODevice::WriteOnly);
- if (!file->is_open()) {
- StringBuilder sb;
- sb.append("Failed to open ");
- sb.append(filename);
- sb.append(" for write. Error: ");
- sb.append(file->error_string());
-
- return sb.to_string();
- }
-
- if (mime == "text/csv") {
- // FIXME: Prompt the user for settings and which sheet to export.
- Core::OutputFileStream stream { file };
- auto data = m_sheets[0].to_xsv();
- auto header_string = data.take_first();
- Vector<StringView> headers;
- for (auto& str : header_string)
- headers.append(str);
- Writer::CSV csv { stream, data, headers };
- if (csv.has_error())
- return String::formatted("Unable to save file, CSV writer error: {}", csv.error_string());
- } else {
- JsonArray array;
- for (auto& sheet : m_sheets)
- array.append(sheet.to_json());
-
- auto file_content = array.to_string();
- bool result = file->write(file_content);
- if (!result) {
- int error_number = errno;
- StringBuilder sb;
- sb.append("Unable to save file. Error: ");
- sb.append(strerror(error_number));
-
- return sb.to_string();
- }
- }
-
- set_filename(filename);
- set_dirty(false);
- return true;
-}
-
-}
diff --git a/Applications/Spreadsheet/Workbook.h b/Applications/Spreadsheet/Workbook.h
deleted file mode 100644
index 63c016d501..0000000000
--- a/Applications/Spreadsheet/Workbook.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "Forward.h"
-#include "Spreadsheet.h"
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/Result.h>
-
-namespace Spreadsheet {
-
-class Workbook {
-public:
- Workbook(NonnullRefPtrVector<Sheet>&& sheets);
-
- Result<bool, String> save(const StringView& filename);
- Result<bool, String> load(const StringView& filename);
-
- const String& current_filename() const { return m_current_filename; }
- bool set_filename(const String& filename);
- bool dirty() { return m_dirty; }
- void set_dirty(bool dirty) { m_dirty = dirty; }
-
- bool has_sheets() const { return !m_sheets.is_empty(); }
-
- const NonnullRefPtrVector<Sheet>& sheets() const { return m_sheets; }
- NonnullRefPtrVector<Sheet> sheets() { return m_sheets; }
-
- Sheet& add_sheet(const StringView& name)
- {
- auto sheet = Sheet::construct(name, *this);
- m_sheets.append(sheet);
- return *sheet;
- }
-
- JS::Interpreter& interpreter() { return *m_interpreter; }
- const JS::Interpreter& interpreter() const { return *m_interpreter; }
-
- JS::GlobalObject& global_object() { return m_interpreter->global_object(); }
- const JS::GlobalObject& global_object() const { return m_interpreter->global_object(); }
-
- WorkbookObject* workbook_object() { return m_workbook_object; }
-
-private:
- NonnullRefPtrVector<Sheet> m_sheets;
- NonnullOwnPtr<JS::Interpreter> m_interpreter;
- JS::VM::InterpreterExecutionScope m_interpreter_scope;
- WorkbookObject* m_workbook_object { nullptr };
-
- String m_current_filename;
- bool m_dirty { false };
-};
-
-}
diff --git a/Applications/Spreadsheet/Writers/CSV.h b/Applications/Spreadsheet/Writers/CSV.h
deleted file mode 100644
index 49940fbdf1..0000000000
--- a/Applications/Spreadsheet/Writers/CSV.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include "XSV.h"
-#include <AK/Forward.h>
-#include <AK/StringView.h>
-
-namespace Writer {
-
-template<typename ContainerType>
-class CSV : public XSV<ContainerType> {
-public:
- CSV(OutputStream& output, const ContainerType& data, const Vector<StringView>& headers = {}, WriterBehaviour behaviours = default_behaviours())
- : XSV<ContainerType>(output, data, { ",", "\"", WriterTraits::Repeat }, headers, behaviours)
- {
- }
-};
-
-}
diff --git a/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp b/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp
deleted file mode 100644
index 4971658431..0000000000
--- a/Applications/Spreadsheet/Writers/Test/TestXSVWriter.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <AK/TestSuite.h>
-
-#include "../CSV.h"
-#include "../XSV.h"
-#include <AK/MemoryStream.h>
-
-TEST_CASE(can_write)
-{
- Vector<Vector<int>> data = {
- { 1, 2, 3 },
- { 4, 5, 6 },
- { 7, 8, 9 },
- };
-
- auto buffer = ByteBuffer::create_uninitialized(1024);
- OutputMemoryStream stream { buffer };
-
- Writer::CSV csv(stream, data);
-
- auto expected_output = R"~(1,2,3
-4,5,6
-7,8,9
-)~";
-
- EXPECT_EQ(StringView { stream.bytes() }, expected_output);
-}
-
-TEST_CASE(can_write_with_header)
-{
- Vector<Vector<int>> data = {
- { 1, 2, 3 },
- { 4, 5, 6 },
- { 7, 8, 9 },
- };
-
- auto buffer = ByteBuffer::create_uninitialized(1024);
- OutputMemoryStream stream { buffer };
-
- Writer::CSV csv(stream, data, { "A", "B\"", "C" });
-
- auto expected_output = R"~(A,"B""",C
-1,2,3
-4,5,6
-7,8,9
-)~";
-
- EXPECT_EQ(StringView { stream.bytes() }, expected_output);
-}
-
-TEST_CASE(can_write_with_different_behaviours)
-{
- Vector<Vector<String>> data = {
- { "Well", "Hello\"", "Friends" },
- { "We\"ll", "Hello,", " Friends" },
- };
-
- auto buffer = ByteBuffer::create_uninitialized(1024);
- OutputMemoryStream stream { buffer };
-
- Writer::CSV csv(stream, data, { "A", "B\"", "C" }, Writer::WriterBehaviour::QuoteOnlyInFieldStart | Writer::WriterBehaviour::WriteHeaders);
-
- auto expected_output = R"~(A,B",C
-Well,Hello",Friends
-We"ll,"Hello,", Friends
-)~";
-
- EXPECT_EQ(StringView { stream.bytes() }, expected_output);
-}
-
-TEST_MAIN(XSV)
diff --git a/Applications/Spreadsheet/Writers/XSV.h b/Applications/Spreadsheet/Writers/XSV.h
deleted file mode 100644
index 7a065f87d1..0000000000
--- a/Applications/Spreadsheet/Writers/XSV.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/GenericLexer.h>
-#include <AK/OwnPtr.h>
-#include <AK/Stream.h>
-#include <AK/String.h>
-#include <AK/StringView.h>
-#include <AK/Types.h>
-#include <AK/Vector.h>
-
-namespace Writer {
-
-enum class WriterBehaviour : u32 {
- None = 0,
- WriteHeaders = 1,
- AllowNewlinesInFields = WriteHeaders << 1,
- QuoteOnlyInFieldStart = WriteHeaders << 2,
- QuoteAll = WriteHeaders << 3,
-};
-
-inline WriterBehaviour operator&(WriterBehaviour left, WriterBehaviour right)
-{
- return static_cast<WriterBehaviour>(static_cast<u32>(left) & static_cast<u32>(right));
-}
-
-inline WriterBehaviour operator|(WriterBehaviour left, WriterBehaviour right)
-{
- return static_cast<WriterBehaviour>(static_cast<u32>(left) | static_cast<u32>(right));
-}
-
-struct WriterTraits {
- String separator;
- String quote { "\"" };
- enum {
- Repeat,
- Backslash,
- } quote_escape { Repeat };
-};
-
-#define ENUMERATE_WRITE_ERRORS() \
- E(None, "No errors") \
- E(NonConformingColumnCount, "Header count does not match given column count") \
- E(InternalError, "Internal error")
-
-enum class WriteError {
-#define E(name, _) name,
- ENUMERATE_WRITE_ERRORS()
-#undef E
-};
-
-inline constexpr WriterBehaviour default_behaviours()
-{
- return WriterBehaviour::None;
-}
-
-template<typename ContainerType>
-class XSV {
-public:
- XSV(OutputStream& output, const ContainerType& data, const WriterTraits& traits, const Vector<StringView>& headers = {}, WriterBehaviour behaviours = default_behaviours())
- : m_data(data)
- , m_traits(traits)
- , m_behaviours(behaviours)
- , m_names(headers)
- , m_output(output)
- {
- if (!headers.is_empty())
- m_behaviours = m_behaviours | WriterBehaviour::WriteHeaders;
-
- generate();
- }
-
- virtual ~XSV() { }
-
- bool has_error() const { return m_error != WriteError::None; }
- WriteError error() const { return m_error; }
- String error_string() const
- {
- switch (m_error) {
-#define E(x, y) \
- case WriteError::x: \
- return y;
-
- ENUMERATE_WRITE_ERRORS();
-#undef E
- }
- ASSERT_NOT_REACHED();
- }
-
-private:
- void set_error(WriteError error)
- {
- if (m_error == WriteError::None)
- m_error = error;
- }
-
- void generate()
- {
- auto with_headers = (m_behaviours & WriterBehaviour::WriteHeaders) != WriterBehaviour::None;
- if (with_headers) {
- write_row(m_names);
- if (m_output.write({ "\n", 1 }) != 1)
- set_error(WriteError::InternalError);
- }
-
- for (auto&& row : m_data) {
- if (with_headers) {
- if (row.size() != m_names.size())
- set_error(WriteError::NonConformingColumnCount);
- }
-
- write_row(row);
- if (m_output.write({ "\n", 1 }) != 1)
- set_error(WriteError::InternalError);
- }
- }
-
- template<typename T>
- void write_row(T&& row)
- {
- bool first = true;
- for (auto&& entry : row) {
- if (!first) {
- if (m_output.write(m_traits.separator.bytes()) != m_traits.separator.length())
- set_error(WriteError::InternalError);
- }
- first = false;
- write_entry(entry);
- }
- }
-
- template<typename T>
- void write_entry(T&& entry)
- {
- auto string = String::formatted("{}", FormatIfSupported(entry));
-
- auto safe_to_write_normally = !string.contains("\n") && !string.contains(m_traits.separator);
- if (safe_to_write_normally) {
- if ((m_behaviours & WriterBehaviour::QuoteOnlyInFieldStart) == WriterBehaviour::None)
- safe_to_write_normally = !string.contains(m_traits.quote);
- else
- safe_to_write_normally = !string.starts_with(m_traits.quote);
- }
- if (safe_to_write_normally) {
- if (m_output.write(string.bytes()) != string.length())
- set_error(WriteError::InternalError);
- return;
- }
-
- if (m_output.write(m_traits.quote.bytes()) != m_traits.quote.length())
- set_error(WriteError::InternalError);
-
- GenericLexer lexer(string);
- while (!lexer.is_eof()) {
- if (lexer.consume_specific(m_traits.quote)) {
- switch (m_traits.quote_escape) {
- case WriterTraits::Repeat:
- if (m_output.write(m_traits.quote.bytes()) != m_traits.quote.length())
- set_error(WriteError::InternalError);
- if (m_output.write(m_traits.quote.bytes()) != m_traits.quote.length())
- set_error(WriteError::InternalError);
- break;
- case WriterTraits::Backslash:
- if (m_output.write({ "\\", 1 }) != 1)
- set_error(WriteError::InternalError);
- if (m_output.write(m_traits.quote.bytes()) != m_traits.quote.length())
- set_error(WriteError::InternalError);
- break;
- }
- continue;
- }
-
- auto ch = lexer.consume();
- if (m_output.write({ &ch, 1 }) != 1)
- set_error(WriteError::InternalError);
- }
-
- if (m_output.write(m_traits.quote.bytes()) != m_traits.quote.length())
- set_error(WriteError::InternalError);
- }
-
- const ContainerType& m_data;
- const WriterTraits& m_traits;
- WriterBehaviour m_behaviours;
- const Vector<StringView>& m_names;
- WriteError m_error { WriteError::None };
- OutputStream& m_output;
-};
-
-}
diff --git a/Applications/Spreadsheet/main.cpp b/Applications/Spreadsheet/main.cpp
deleted file mode 100644
index e13a89cdac..0000000000
--- a/Applications/Spreadsheet/main.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "HelpWindow.h"
-#include "Spreadsheet.h"
-#include "SpreadsheetWidget.h"
-#include <AK/ScopeGuard.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/File.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Clipboard.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/Forward.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Window.h>
-
-int main(int argc, char* argv[])
-{
- if (pledge("stdio shared_buffer accept rpath unix cpath wpath fattr thread", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* filename = nullptr;
-
- Core::ArgsParser args_parser;
- args_parser.add_positional_argument(filename, "File to read from", "file", Core::ArgsParser::Required::No);
-
- args_parser.parse(argc, argv);
-
- if (filename) {
- if (!Core::File::exists(filename) || Core::File::is_directory(filename)) {
- warnln("File does not exist or is a directory: {}", filename);
- return 1;
- }
- }
-
- if (unveil("/tmp/portal/webcontent", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/etc", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(Core::StandardPaths::home_directory().characters(), "rwc") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-spreadsheet");
- auto window = GUI::Window::construct();
- window->set_title("Spreadsheet");
- window->resize(640, 480);
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto& spreadsheet_widget = window->set_main_widget<Spreadsheet::SpreadsheetWidget>(NonnullRefPtrVector<Spreadsheet::Sheet> {}, filename == nullptr);
-
- if (filename)
- spreadsheet_widget.load(filename);
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Spreadsheet");
-
- app_menu.add_action(GUI::Action::create("Add New Sheet", Gfx::Bitmap::load_from_file("/res/icons/16x16/new-tab.png"), [&](auto&) {
- spreadsheet_widget.add_sheet();
- }));
-
- app_menu.add_separator();
-
- app_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) {
- if (!spreadsheet_widget.request_close())
- return;
- app->quit(0);
- }));
-
- window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
- if (spreadsheet_widget.request_close())
- return GUI::Window::CloseRequestDecision::Close;
- return GUI::Window::CloseRequestDecision::StayOpen;
- };
-
- auto& file_menu = menubar->add_menu("File");
- file_menu.add_action(GUI::CommonActions::make_open_action([&](auto&) {
- Optional<String> load_path = GUI::FilePicker::get_open_filepath(window);
- if (!load_path.has_value())
- return;
-
- spreadsheet_widget.load(load_path.value());
- }));
-
- file_menu.add_action(GUI::CommonActions::make_save_action([&](auto&) {
- if (spreadsheet_widget.current_filename().is_empty()) {
- String name = "workbook";
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, name, "sheets");
- if (!save_path.has_value())
- return;
-
- spreadsheet_widget.save(save_path.value());
- } else {
- spreadsheet_widget.save(spreadsheet_widget.current_filename());
- }
- }));
-
- file_menu.add_action(GUI::CommonActions::make_save_as_action([&](auto&) {
- auto current_filename = spreadsheet_widget.current_filename();
- String name = "workbook";
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window, name, "sheets");
- if (!save_path.has_value())
- return;
-
- spreadsheet_widget.save(save_path.value());
-
- if (!current_filename.is_empty())
- spreadsheet_widget.set_filename(current_filename);
- }));
-
- auto& edit_menu = menubar->add_menu("Edit");
- edit_menu.add_action(GUI::CommonActions::make_copy_action([&](auto&) {
- /// text/x-spreadsheet-data:
- /// - currently selected cell
- /// - selected cell+
- auto& cells = spreadsheet_widget.current_worksheet().selected_cells();
- ASSERT(!cells.is_empty());
- StringBuilder text_builder, url_builder;
- bool first = true;
- auto cursor = spreadsheet_widget.current_selection_cursor();
- if (cursor) {
- Spreadsheet::Position position { spreadsheet_widget.current_worksheet().column(cursor->column()), (size_t)cursor->row() };
- url_builder.append(position.to_url().to_string());
- url_builder.append('\n');
- }
-
- for (auto& cell : cells) {
- if (first && !cursor) {
- url_builder.append(cell.to_url().to_string());
- url_builder.append('\n');
- }
-
- url_builder.append(cell.to_url().to_string());
- url_builder.append('\n');
-
- auto cell_data = spreadsheet_widget.current_worksheet().at(cell);
- if (!first)
- text_builder.append('\t');
- if (cell_data)
- text_builder.append(cell_data->data());
- first = false;
- }
- HashMap<String, String> metadata;
- metadata.set("text/x-spreadsheet-data", url_builder.to_string());
-
- GUI::Clipboard::the().set_data(text_builder.string_view().bytes(), "text/plain", move(metadata));
- },
- window));
- edit_menu.add_action(GUI::CommonActions::make_paste_action([&](auto&) {
- ScopeGuard update_after_paste { [&] { spreadsheet_widget.update(); } };
-
- auto& cells = spreadsheet_widget.current_worksheet().selected_cells();
- ASSERT(!cells.is_empty());
- const auto& data = GUI::Clipboard::the().data_and_type();
- if (auto spreadsheet_data = data.metadata.get("text/x-spreadsheet-data"); spreadsheet_data.has_value()) {
- Vector<Spreadsheet::Position> source_positions, target_positions;
- auto& sheet = spreadsheet_widget.current_worksheet();
-
- for (auto& line : spreadsheet_data.value().split_view('\n')) {
- dbgln("Paste line '{}'", line);
- auto position = sheet.position_from_url(line);
- if (position.has_value())
- source_positions.append(position.release_value());
- }
-
- for (auto& position : spreadsheet_widget.current_worksheet().selected_cells())
- target_positions.append(position);
-
- if (source_positions.is_empty())
- return;
-
- auto first_position = source_positions.take_first();
- sheet.copy_cells(move(source_positions), move(target_positions), first_position);
- } else {
- for (auto& cell : spreadsheet_widget.current_worksheet().selected_cells())
- spreadsheet_widget.current_worksheet().ensure(cell).set_data(StringView { data.data.data(), data.data.size() });
- spreadsheet_widget.update();
- }
- },
- window));
-
- auto& help_menu = menubar->add_menu("Help");
-
- help_menu.add_action(GUI::Action::create(
- "Functions Help", [&](auto&) {
- auto docs = spreadsheet_widget.current_worksheet().gather_documentation();
- auto help_window = Spreadsheet::HelpWindow::the(window);
- help_window->set_docs(move(docs));
- help_window->show();
- },
- window));
-
- app_menu.add_separator();
-
- help_menu.add_action(GUI::CommonActions::make_about_action("Spreadsheet", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- window->show();
-
- return app->exec();
-}
diff --git a/Applications/SystemMonitor/CMakeLists.txt b/Applications/SystemMonitor/CMakeLists.txt
deleted file mode 100644
index ee2e4d2323..0000000000
--- a/Applications/SystemMonitor/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-set(SOURCES
- DevicesModel.cpp
- GraphWidget.cpp
- InterruptsWidget.cpp
- main.cpp
- MemoryStatsWidget.cpp
- NetworkStatisticsWidget.cpp
- ProcessFileDescriptorMapWidget.cpp
- ProcessMemoryMapWidget.cpp
- ProcessModel.cpp
- ProcessUnveiledPathsWidget.cpp
- ThreadStackWidget.cpp
-)
-
-serenity_app(SystemMonitor ICON app-system-monitor)
-target_link_libraries(SystemMonitor LibGUI LibPCIDB)
diff --git a/Applications/SystemMonitor/DevicesModel.cpp b/Applications/SystemMonitor/DevicesModel.cpp
deleted file mode 100644
index f0692cdd24..0000000000
--- a/Applications/SystemMonitor/DevicesModel.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DevicesModel.h"
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonValue.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <sys/stat.h>
-
-NonnullRefPtr<DevicesModel> DevicesModel::create()
-{
- return adopt(*new DevicesModel);
-}
-
-DevicesModel::DevicesModel()
-{
-}
-
-DevicesModel::~DevicesModel()
-{
-}
-
-int DevicesModel::row_count(const GUI::ModelIndex&) const
-{
- return m_devices.size();
-}
-
-int DevicesModel::column_count(const GUI::ModelIndex&) const
-{
- return Column::__Count;
-}
-
-String DevicesModel::column_name(int column) const
-{
- switch (column) {
- case Column::Device:
- return "Device";
- case Column::Major:
- return "Major";
- case Column::Minor:
- return "Minor";
- case Column::ClassName:
- return "Class";
- case Column::Type:
- return "Type";
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-GUI::Variant DevicesModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- ASSERT(is_valid(index));
-
- if (role == GUI::ModelRole::TextAlignment) {
- switch (index.column()) {
- case Column::Device:
- return Gfx::TextAlignment::CenterLeft;
- case Column::Major:
- return Gfx::TextAlignment::CenterRight;
- case Column::Minor:
- return Gfx::TextAlignment::CenterRight;
- case Column::ClassName:
- return Gfx::TextAlignment::CenterLeft;
- case Column::Type:
- return Gfx::TextAlignment::CenterLeft;
- }
- return {};
- }
-
- if (role == GUI::ModelRole::Sort) {
- const DeviceInfo& device = m_devices[index.row()];
- switch (index.column()) {
- case Column::Device:
- return device.path;
- case Column::Major:
- return device.major;
- case Column::Minor:
- return device.minor;
- case Column::ClassName:
- return device.class_name;
- case Column::Type:
- return device.type;
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- if (role == GUI::ModelRole::Display) {
- const DeviceInfo& device = m_devices[index.row()];
- switch (index.column()) {
- case Column::Device:
- return device.path;
- case Column::Major:
- return device.major;
- case Column::Minor:
- return device.minor;
- case Column::ClassName:
- return device.class_name;
- case Column::Type:
- switch (device.type) {
- case DeviceInfo::Type::Block:
- return "Block";
- case DeviceInfo::Type::Character:
- return "Character";
- default:
- ASSERT_NOT_REACHED();
- }
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- return {};
-}
-
-void DevicesModel::update()
-{
- auto proc_devices = Core::File::construct("/proc/devices");
- if (!proc_devices->open(Core::IODevice::OpenMode::ReadOnly))
- ASSERT_NOT_REACHED();
-
- auto json = JsonValue::from_string(proc_devices->read_all());
- ASSERT(json.has_value());
-
- m_devices.clear();
- json.value().as_array().for_each([this](auto& value) {
- JsonObject device = value.as_object();
- DeviceInfo device_info;
-
- device_info.major = device.get("major").to_uint();
- device_info.minor = device.get("minor").to_uint();
- device_info.class_name = device.get("class_name").to_string();
-
- String type_str = device.get("type").to_string();
- if (type_str == "block")
- device_info.type = DeviceInfo::Type::Block;
- else if (type_str == "character")
- device_info.type = DeviceInfo::Type::Character;
- else
- ASSERT_NOT_REACHED();
-
- m_devices.append(move(device_info));
- });
-
- auto fill_in_paths_from_dir = [this](const String& dir) {
- Core::DirIterator dir_iter { dir, Core::DirIterator::Flags::SkipDots };
- while (dir_iter.has_next()) {
- auto name = dir_iter.next_path();
- auto path = String::format("%s/%s", dir.characters(), name.characters());
- struct stat statbuf;
- if (lstat(path.characters(), &statbuf) != 0) {
- ASSERT_NOT_REACHED();
- }
- if (!S_ISBLK(statbuf.st_mode) && !S_ISCHR(statbuf.st_mode))
- continue;
- unsigned _major = major(statbuf.st_rdev);
- unsigned _minor = minor(statbuf.st_rdev);
-
- auto it = m_devices.find_if([_major, _minor](const auto& device_info) {
- return device_info.major == _major && device_info.minor == _minor;
- });
- if (it != m_devices.end()) {
- (*it).path = move(path);
- }
- }
- };
-
- fill_in_paths_from_dir("/dev");
- fill_in_paths_from_dir("/dev/pts");
-
- did_update();
-}
diff --git a/Applications/SystemMonitor/DevicesModel.h b/Applications/SystemMonitor/DevicesModel.h
deleted file mode 100644
index dd8cacc7e0..0000000000
--- a/Applications/SystemMonitor/DevicesModel.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <LibGUI/Model.h>
-
-class DevicesModel final : public GUI::Model {
-public:
- enum Column {
- Device = 0,
- Major,
- Minor,
- ClassName,
- Type,
- __Count
- };
-
- virtual ~DevicesModel() override;
- static NonnullRefPtr<DevicesModel> create();
-
- virtual int row_count(const GUI::ModelIndex&) const override;
- virtual int column_count(const GUI::ModelIndex&) const override;
- virtual String column_name(int column) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual void update() override;
-
-private:
- DevicesModel();
-
- struct DeviceInfo {
- String path;
- unsigned major;
- unsigned minor;
- String class_name;
- enum Type {
- Block,
- Character
- };
- Type type;
- };
-
- Vector<DeviceInfo> m_devices;
-};
diff --git a/Applications/SystemMonitor/GraphWidget.cpp b/Applications/SystemMonitor/GraphWidget.cpp
deleted file mode 100644
index 5c1d9982d4..0000000000
--- a/Applications/SystemMonitor/GraphWidget.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "GraphWidget.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Path.h>
-
-GraphWidget::GraphWidget()
-{
-}
-
-GraphWidget::~GraphWidget()
-{
-}
-
-void GraphWidget::add_value(Vector<int, 1>&& value)
-{
- m_values.enqueue(move(value));
- update();
-}
-
-void GraphWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.add_clip_rect(frame_inner_rect());
- painter.fill_rect(event.rect(), m_background_color);
-
- auto inner_rect = frame_inner_rect();
- float scale = (float)inner_rect.height() / (float)m_max;
-
- if (!m_values.is_empty()) {
- // Draw one set of values at a time
- for (size_t k = 0; k < m_value_format.size(); k++) {
- const auto& format = m_value_format[k];
- if (format.line_color == Color::Transparent && format.background_color == Color::Transparent)
- continue;
- m_calculated_points.clear_with_capacity();
- for (size_t i = 0; i < m_values.size(); i++) {
- int x = inner_rect.right() - (i * 2) + 1;
- if (x < 0)
- break;
- const auto& current_values = m_values.at(m_values.size() - i - 1);
- if (current_values.size() <= k) {
- // Don't have a data point
- m_calculated_points.append({ -1, -1 });
- continue;
- }
- float value = current_values[k];
- if (m_stack_values) {
- for (size_t l = k + 1; l < current_values.size(); l++)
- value += current_values[l];
- }
- float scaled_value = value * scale;
- Gfx::IntPoint current_point { x, inner_rect.bottom() - (int)scaled_value };
- m_calculated_points.append(current_point);
- }
- ASSERT(m_calculated_points.size() <= m_values.size());
- if (format.background_color != Color::Transparent) {
- // Fill the background for the area we have values for
- Gfx::Path path;
- size_t points_in_path = 0;
- bool started_path = false;
- const Gfx::IntPoint* current_point = nullptr;
- const Gfx::IntPoint* first_point = nullptr;
- auto check_fill_area = [&]() {
- if (!started_path)
- return;
- if (points_in_path > 1) {
- ASSERT(current_point);
- ASSERT(first_point);
- path.line_to({ current_point->x() - 1, inner_rect.bottom() + 1 });
- path.line_to({ first_point->x() + 1, inner_rect.bottom() + 1 });
- path.close();
- painter.fill_path(path, format.background_color, Gfx::Painter::WindingRule::EvenOdd);
- } else if (points_in_path == 1 && current_point) {
- // Can't fill any area, we only have one data point.
- // Just draw a vertical line as a "fill"...
- painter.draw_line(*current_point, { current_point->x(), inner_rect.bottom() }, format.background_color);
- }
- path = {};
- points_in_path = 0;
- first_point = nullptr;
- started_path = false;
- };
- for (size_t i = 0; i < m_calculated_points.size(); i++) {
- current_point = &m_calculated_points[i];
- if (current_point->x() < 0) {
- check_fill_area();
- continue;
- }
- if (!started_path) {
- path.move_to({ current_point->x() + 1, current_point->y() });
- points_in_path = 1;
- first_point = current_point;
- started_path = true;
- } else {
- path.line_to({ current_point->x(), current_point->y() });
- points_in_path++;
- }
- }
- check_fill_area();
- }
- if (format.line_color != Color::Transparent) {
- // Draw the line for the data points we have
- const Gfx::IntPoint* previous_point = nullptr;
- for (size_t i = 0; i < m_calculated_points.size(); i++) {
- const auto& current_point = m_calculated_points[i];
- if (current_point.x() < 0) {
- previous_point = nullptr;
- continue;
- }
- if (previous_point)
- painter.draw_line(*previous_point, current_point, format.line_color);
- previous_point = &current_point;
- }
- }
- }
- }
-
- if (!m_values.is_empty() && !m_value_format.is_empty()) {
- const auto& current_values = m_values.last();
- int y = 0;
- for (size_t i = 0; i < min(m_value_format.size(), current_values.size()); i++) {
- const auto& format = m_value_format[i];
- if (!format.text_formatter)
- continue;
- auto constrain_rect = inner_rect.shrunken(8, 8);
- auto text_rect = constrain_rect.translated(0, y).intersected(constrain_rect);
- text_rect.set_height(font().glyph_height());
- auto text = format.text_formatter(current_values[i]);
- if (format.text_shadow_color != Color::Transparent)
- painter.draw_text(text_rect.translated(1, 1), text.characters(), Gfx::TextAlignment::CenterRight, format.text_shadow_color);
- painter.draw_text(text_rect, text.characters(), Gfx::TextAlignment::CenterRight, format.line_color);
- y += text_rect.height() + 4;
- }
- }
-}
diff --git a/Applications/SystemMonitor/GraphWidget.h b/Applications/SystemMonitor/GraphWidget.h
deleted file mode 100644
index fc40f59bbd..0000000000
--- a/Applications/SystemMonitor/GraphWidget.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/CircularQueue.h>
-#include <LibGUI/Frame.h>
-
-class GraphWidget final : public GUI::Frame {
- C_OBJECT(GraphWidget)
-public:
- virtual ~GraphWidget() override;
-
- void set_max(int max) { m_max = max; }
- int max() const { return m_max; }
-
- void add_value(Vector<int, 1>&&);
-
- void set_background_color(Color color) { m_background_color = color; }
-
- struct ValueFormat {
- Color line_color { Color::Transparent };
- Color background_color { Color::Transparent };
- Color text_shadow_color { Color::Transparent };
- Function<String(int)> text_formatter;
- };
- void set_value_format(size_t index, ValueFormat&& format)
- {
- if (m_value_format.size() <= index)
- m_value_format.resize(index + 1);
- m_value_format[index] = move(format);
- }
- void set_stack_values(bool stack_values) { m_stack_values = stack_values; }
-
-private:
- explicit GraphWidget();
-
- virtual void paint_event(GUI::PaintEvent&) override;
-
- int m_max { 100 };
- Vector<ValueFormat, 1> m_value_format;
- CircularQueue<Vector<int, 1>, 4000> m_values;
- Color m_background_color { Color::Black };
- bool m_stack_values { false };
-
- Vector<Gfx::IntPoint, 1> m_calculated_points;
-};
diff --git a/Applications/SystemMonitor/InterruptsWidget.cpp b/Applications/SystemMonitor/InterruptsWidget.cpp
deleted file mode 100644
index 3e56f29ec4..0000000000
--- a/Applications/SystemMonitor/InterruptsWidget.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "InterruptsWidget.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/TableView.h>
-
-InterruptsWidget::InterruptsWidget()
-{
- on_first_show = [this](auto&) {
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
-
- Vector<GUI::JsonArrayModel::FieldSpec> interrupts_field;
- interrupts_field.empend("interrupt_line", "Line", Gfx::TextAlignment::CenterRight);
- interrupts_field.empend("purpose", "Purpose", Gfx::TextAlignment::CenterLeft);
- interrupts_field.empend("controller", "Controller", Gfx::TextAlignment::CenterLeft);
- interrupts_field.empend("cpu_handler", "CPU Handler", Gfx::TextAlignment::CenterRight);
- interrupts_field.empend("device_sharing", "# Devices Sharing", Gfx::TextAlignment::CenterRight);
- interrupts_field.empend("call_count", "Call Count", Gfx::TextAlignment::CenterRight);
-
- m_interrupt_table_view = add<GUI::TableView>();
- m_interrupt_model = GUI::JsonArrayModel::create("/proc/interrupts", move(interrupts_field));
- m_interrupt_table_view->set_model(GUI::SortingProxyModel::create(*m_interrupt_model));
-
- m_update_timer = add<Core::Timer>(
- 1000, [this] {
- update_model();
- });
-
- update_model();
- };
-}
-
-InterruptsWidget::~InterruptsWidget()
-{
-}
-
-void InterruptsWidget::update_model()
-{
- m_interrupt_table_view->model()->update();
-}
diff --git a/Applications/SystemMonitor/InterruptsWidget.h b/Applications/SystemMonitor/InterruptsWidget.h
deleted file mode 100644
index bc11215217..0000000000
--- a/Applications/SystemMonitor/InterruptsWidget.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibCore/Timer.h>
-#include <LibGUI/LazyWidget.h>
-
-class InterruptsWidget final : public GUI::LazyWidget {
- C_OBJECT(InterruptsWidget)
-public:
- virtual ~InterruptsWidget() override;
-
-private:
- InterruptsWidget();
- void update_model();
-
- RefPtr<GUI::TableView> m_interrupt_table_view;
- RefPtr<GUI::JsonArrayModel> m_interrupt_model;
- RefPtr<Core::Timer> m_update_timer;
-};
diff --git a/Applications/SystemMonitor/MemoryStatsWidget.cpp b/Applications/SystemMonitor/MemoryStatsWidget.cpp
deleted file mode 100644
index 6675ea8c4a..0000000000
--- a/Applications/SystemMonitor/MemoryStatsWidget.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "MemoryStatsWidget.h"
-#include "GraphWidget.h"
-#include <AK/ByteBuffer.h>
-#include <AK/JsonObject.h>
-#include <LibCore/File.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/StylePainter.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-static MemoryStatsWidget* s_the;
-
-MemoryStatsWidget* MemoryStatsWidget::the()
-{
- return s_the;
-}
-
-MemoryStatsWidget::MemoryStatsWidget(GraphWidget& graph)
- : m_graph(graph)
-{
- ASSERT(!s_the);
- s_the = this;
-
- set_fixed_height(110);
-
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 0, 8, 0, 0 });
- layout()->set_spacing(3);
-
- auto build_widgets_for_label = [this](const String& description) -> RefPtr<GUI::Label> {
- auto& container = add<GUI::Widget>();
- container.set_layout<GUI::HorizontalBoxLayout>();
- container.set_fixed_size(275, 12);
- auto& description_label = container.add<GUI::Label>(description);
- description_label.set_font(Gfx::FontDatabase::default_bold_font());
- description_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- auto& label = container.add<GUI::Label>();
- label.set_text_alignment(Gfx::TextAlignment::CenterRight);
- return label;
- };
-
- m_user_physical_pages_label = build_widgets_for_label("Physical memory:");
- m_user_physical_pages_committed_label = build_widgets_for_label("Committed memory:");
- m_supervisor_physical_pages_label = build_widgets_for_label("Supervisor physical:");
- m_kmalloc_space_label = build_widgets_for_label("Kernel heap:");
- m_kmalloc_count_label = build_widgets_for_label("Calls kmalloc:");
- m_kfree_count_label = build_widgets_for_label("Calls kfree:");
- m_kmalloc_difference_label = build_widgets_for_label("Difference:");
-
- refresh();
-}
-
-MemoryStatsWidget::~MemoryStatsWidget()
-{
-}
-
-static inline size_t page_count_to_kb(size_t kb)
-{
- return (kb * 4096) / 1024;
-}
-
-static inline size_t bytes_to_kb(size_t bytes)
-{
- return bytes / 1024;
-}
-
-void MemoryStatsWidget::refresh()
-{
- auto proc_memstat = Core::File::construct("/proc/memstat");
- if (!proc_memstat->open(Core::IODevice::OpenMode::ReadOnly))
- ASSERT_NOT_REACHED();
-
- auto file_contents = proc_memstat->read_all();
- auto json_result = JsonValue::from_string(file_contents);
- ASSERT(json_result.has_value());
- auto json = json_result.value().as_object();
-
- [[maybe_unused]] unsigned kmalloc_eternal_allocated = json.get("kmalloc_eternal_allocated").to_u32();
- unsigned kmalloc_allocated = json.get("kmalloc_allocated").to_u32();
- unsigned kmalloc_available = json.get("kmalloc_available").to_u32();
- unsigned user_physical_allocated = json.get("user_physical_allocated").to_u32();
- unsigned user_physical_available = json.get("user_physical_available").to_u32();
- unsigned user_physical_committed = json.get("user_physical_committed").to_u32();
- unsigned user_physical_uncommitted = json.get("user_physical_uncommitted").to_u32();
- unsigned super_physical_alloc = json.get("super_physical_allocated").to_u32();
- unsigned super_physical_free = json.get("super_physical_available").to_u32();
- unsigned kmalloc_call_count = json.get("kmalloc_call_count").to_u32();
- unsigned kfree_call_count = json.get("kfree_call_count").to_u32();
-
- size_t kmalloc_bytes_total = kmalloc_allocated + kmalloc_available;
- size_t user_physical_pages_total = user_physical_allocated + user_physical_available;
- size_t supervisor_pages_total = super_physical_alloc + super_physical_free;
-
- size_t physical_pages_total = user_physical_pages_total + supervisor_pages_total;
- size_t physical_pages_in_use = user_physical_allocated + super_physical_alloc;
- size_t total_userphysical_and_swappable_pages = user_physical_allocated + user_physical_committed + user_physical_uncommitted;
-
- m_kmalloc_space_label->set_text(String::formatted("{}K/{}K", bytes_to_kb(kmalloc_allocated), bytes_to_kb(kmalloc_bytes_total)));
- m_user_physical_pages_label->set_text(String::formatted("{}K/{}K", page_count_to_kb(physical_pages_in_use), page_count_to_kb(physical_pages_total)));
- m_user_physical_pages_committed_label->set_text(String::formatted("{}K", page_count_to_kb(user_physical_committed)));
- m_supervisor_physical_pages_label->set_text(String::formatted("{}K/{}K", page_count_to_kb(super_physical_alloc), page_count_to_kb(supervisor_pages_total)));
- m_kmalloc_count_label->set_text(String::formatted("{}", kmalloc_call_count));
- m_kfree_count_label->set_text(String::formatted("{}", kfree_call_count));
- m_kmalloc_difference_label->set_text(String::formatted("{:+}", kmalloc_call_count - kfree_call_count));
-
- m_graph.set_max(page_count_to_kb(total_userphysical_and_swappable_pages) + bytes_to_kb(kmalloc_bytes_total));
- m_graph.add_value({ (int)page_count_to_kb(user_physical_committed), (int)page_count_to_kb(user_physical_allocated), (int)bytes_to_kb(kmalloc_bytes_total) });
-}
diff --git a/Applications/SystemMonitor/MemoryStatsWidget.h b/Applications/SystemMonitor/MemoryStatsWidget.h
deleted file mode 100644
index e915730257..0000000000
--- a/Applications/SystemMonitor/MemoryStatsWidget.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-class GraphWidget;
-
-class MemoryStatsWidget final : public GUI::Widget {
- C_OBJECT(MemoryStatsWidget)
-public:
- static MemoryStatsWidget* the();
-
- virtual ~MemoryStatsWidget() override;
-
- void refresh();
-
-private:
- MemoryStatsWidget(GraphWidget& graph);
-
- GraphWidget& m_graph;
- RefPtr<GUI::Label> m_user_physical_pages_label;
- RefPtr<GUI::Label> m_user_physical_pages_committed_label;
- RefPtr<GUI::Label> m_supervisor_physical_pages_label;
- RefPtr<GUI::Label> m_kmalloc_space_label;
- RefPtr<GUI::Label> m_kmalloc_count_label;
- RefPtr<GUI::Label> m_kfree_count_label;
- RefPtr<GUI::Label> m_kmalloc_difference_label;
-};
diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp b/Applications/SystemMonitor/NetworkStatisticsWidget.cpp
deleted file mode 100644
index 7ee2450ee1..0000000000
--- a/Applications/SystemMonitor/NetworkStatisticsWidget.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "NetworkStatisticsWidget.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/TableView.h>
-
-NetworkStatisticsWidget::NetworkStatisticsWidget()
-{
- on_first_show = [this](auto&) {
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
- set_fill_with_background_color(true);
-
- auto& adapters_group_box = add<GUI::GroupBox>("Adapters");
- adapters_group_box.set_layout<GUI::VerticalBoxLayout>();
- adapters_group_box.layout()->set_margins({ 6, 16, 6, 6 });
- adapters_group_box.set_fixed_height(120);
-
- m_adapter_table_view = adapters_group_box.add<GUI::TableView>();
-
- Vector<GUI::JsonArrayModel::FieldSpec> net_adapters_fields;
- net_adapters_fields.empend("name", "Name", Gfx::TextAlignment::CenterLeft);
- net_adapters_fields.empend("class_name", "Class", Gfx::TextAlignment::CenterLeft);
- net_adapters_fields.empend("mac_address", "MAC", Gfx::TextAlignment::CenterLeft);
- net_adapters_fields.empend("ipv4_address", "IPv4", Gfx::TextAlignment::CenterLeft);
- net_adapters_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight);
- net_adapters_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight);
- net_adapters_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight);
- net_adapters_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight);
- m_adapter_model = GUI::JsonArrayModel::create("/proc/net/adapters", move(net_adapters_fields));
- m_adapter_table_view->set_model(GUI::SortingProxyModel::create(*m_adapter_model));
-
- auto& sockets_group_box = add<GUI::GroupBox>("Sockets");
- sockets_group_box.set_layout<GUI::VerticalBoxLayout>();
- sockets_group_box.layout()->set_margins({ 6, 16, 6, 6 });
-
- m_socket_table_view = sockets_group_box.add<GUI::TableView>();
-
- Vector<GUI::JsonArrayModel::FieldSpec> net_tcp_fields;
- net_tcp_fields.empend("peer_address", "Peer", Gfx::TextAlignment::CenterLeft);
- net_tcp_fields.empend("peer_port", "Port", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("local_address", "Local", Gfx::TextAlignment::CenterLeft);
- net_tcp_fields.empend("local_port", "Port", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("state", "State", Gfx::TextAlignment::CenterLeft);
- net_tcp_fields.empend("ack_number", "Ack#", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("sequence_number", "Seq#", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("packets_in", "Pkt In", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("packets_out", "Pkt Out", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("bytes_in", "Bytes In", Gfx::TextAlignment::CenterRight);
- net_tcp_fields.empend("bytes_out", "Bytes Out", Gfx::TextAlignment::CenterRight);
- m_socket_model = GUI::JsonArrayModel::create("/proc/net/tcp", move(net_tcp_fields));
- m_socket_table_view->set_model(GUI::SortingProxyModel::create(*m_socket_model));
-
- m_update_timer = add<Core::Timer>(
- 1000, [this] {
- update_models();
- });
-
- update_models();
- };
-}
-
-NetworkStatisticsWidget::~NetworkStatisticsWidget()
-{
-}
-
-void NetworkStatisticsWidget::update_models()
-{
- m_adapter_table_view->model()->update();
- m_socket_table_view->model()->update();
-}
diff --git a/Applications/SystemMonitor/NetworkStatisticsWidget.h b/Applications/SystemMonitor/NetworkStatisticsWidget.h
deleted file mode 100644
index d49a9641c8..0000000000
--- a/Applications/SystemMonitor/NetworkStatisticsWidget.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibCore/Timer.h>
-#include <LibGUI/LazyWidget.h>
-
-class NetworkStatisticsWidget final : public GUI::LazyWidget {
- C_OBJECT(NetworkStatisticsWidget)
-public:
- virtual ~NetworkStatisticsWidget() override;
-
-private:
- NetworkStatisticsWidget();
- void update_models();
-
- RefPtr<GUI::TableView> m_adapter_table_view;
- RefPtr<GUI::TableView> m_socket_table_view;
- RefPtr<GUI::JsonArrayModel> m_adapter_model;
- RefPtr<GUI::JsonArrayModel> m_socket_model;
- RefPtr<Core::Timer> m_update_timer;
-};
diff --git a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp b/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp
deleted file mode 100644
index 48dfae098d..0000000000
--- a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ProcessFileDescriptorMapWidget.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/TableView.h>
-
-ProcessFileDescriptorMapWidget::ProcessFileDescriptorMapWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
- m_table_view = add<GUI::TableView>();
-
- Vector<GUI::JsonArrayModel::FieldSpec> pid_fds_fields;
- pid_fds_fields.empend("fd", "FD", Gfx::TextAlignment::CenterRight);
- pid_fds_fields.empend("class", "Class", Gfx::TextAlignment::CenterLeft);
- pid_fds_fields.empend("offset", "Offset", Gfx::TextAlignment::CenterRight);
- pid_fds_fields.empend("absolute_path", "Path", Gfx::TextAlignment::CenterLeft);
- pid_fds_fields.empend("Access", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- return object.get("seekable").to_bool() ? "Seekable" : "Sequential";
- });
- pid_fds_fields.empend("Blocking", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- return object.get("blocking").to_bool() ? "Blocking" : "Nonblocking";
- });
- pid_fds_fields.empend("On exec", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- return object.get("cloexec").to_bool() ? "Close" : "Keep";
- });
- pid_fds_fields.empend("Can read", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- return object.get("can_read").to_bool() ? "Yes" : "No";
- });
- pid_fds_fields.empend("Can write", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- return object.get("can_write").to_bool() ? "Yes" : "No";
- });
-
- m_model = GUI::JsonArrayModel::create({}, move(pid_fds_fields));
- m_table_view->set_model(GUI::SortingProxyModel::create(*m_model));
-}
-
-ProcessFileDescriptorMapWidget::~ProcessFileDescriptorMapWidget()
-{
-}
-
-void ProcessFileDescriptorMapWidget::set_pid(pid_t pid)
-{
- if (m_pid == pid)
- return;
- m_pid = pid;
- m_model->set_json_path(String::formatted("/proc/{}/fds", m_pid));
-}
diff --git a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h b/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h
deleted file mode 100644
index 2c45577525..0000000000
--- a/Applications/SystemMonitor/ProcessFileDescriptorMapWidget.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-class ProcessFileDescriptorMapWidget final : public GUI::Widget {
- C_OBJECT(ProcessFileDescriptorMapWidget);
-
-public:
- virtual ~ProcessFileDescriptorMapWidget() override;
-
- void set_pid(pid_t);
-
-private:
- ProcessFileDescriptorMapWidget();
-
- RefPtr<GUI::TableView> m_table_view;
- RefPtr<GUI::JsonArrayModel> m_model;
- pid_t m_pid { -1 };
-};
diff --git a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp b/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp
deleted file mode 100644
index d36a7f57ab..0000000000
--- a/Applications/SystemMonitor/ProcessMemoryMapWidget.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ProcessMemoryMapWidget.h"
-#include <LibCore/Timer.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/TableView.h>
-#include <LibGfx/Palette.h>
-
-class PagemapPaintingDelegate final : public GUI::TableCellPaintingDelegate {
-public:
- virtual ~PagemapPaintingDelegate() override { }
-
- virtual void paint(GUI::Painter& painter, const Gfx::IntRect& a_rect, const Gfx::Palette&, const GUI::ModelIndex& index) override
- {
- auto rect = a_rect.shrunken(2, 2);
- auto pagemap = index.data(GUI::ModelRole::Custom).to_string();
-
- float scale_factor = (float)pagemap.length() / (float)rect.width();
-
- for (int i = 0; i < rect.width(); ++i) {
- int x = rect.x() + i;
- char c = pagemap[(float)i * scale_factor];
- Color color;
- if (c == 'N') // Null (no page at all, typically an inode-backed page that hasn't been paged in.)
- color = Color::White;
- else if (c == 'Z') // Zero (globally shared zero page, typically an untouched anonymous page.)
- color = Color::from_rgb(0xc0c0ff);
- else if (c == 'P') // Physical (a resident page)
- color = Color::Black;
- else
- ASSERT_NOT_REACHED();
-
- painter.draw_line({ x, rect.top() }, { x, rect.bottom() }, color);
- }
-
- painter.draw_rect(rect, Color::Black);
- }
-};
-
-ProcessMemoryMapWidget::ProcessMemoryMapWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
- m_table_view = add<GUI::TableView>();
- Vector<GUI::JsonArrayModel::FieldSpec> pid_vm_fields;
- pid_vm_fields.empend(
- "Address", Gfx::TextAlignment::CenterLeft,
- [](auto& object) { return String::formatted("{:#x}", object.get("address").to_u32()); },
- [](auto& object) { return object.get("address").to_u32(); });
- pid_vm_fields.empend("size", "Size", Gfx::TextAlignment::CenterRight);
- pid_vm_fields.empend("amount_resident", "Resident", Gfx::TextAlignment::CenterRight);
- pid_vm_fields.empend("amount_dirty", "Dirty", Gfx::TextAlignment::CenterRight);
- pid_vm_fields.empend("Access", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- StringBuilder builder;
- if (!object.get("user_accessible").to_bool())
- builder.append('K');
- if (object.get("readable").to_bool())
- builder.append('R');
- if (object.get("writable").to_bool())
- builder.append('W');
- if (object.get("executable").to_bool())
- builder.append('X');
- if (object.get("shared").to_bool())
- builder.append('S');
- if (object.get("stack").to_bool())
- builder.append('T');
- return builder.to_string();
- });
- pid_vm_fields.empend("vmobject", "VMObject type", Gfx::TextAlignment::CenterLeft);
- pid_vm_fields.empend("Purgeable", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- if (object.get("volatile").to_bool())
- return "Volatile";
- return "Non-volatile";
- });
- pid_vm_fields.empend(
- "Page map", Gfx::TextAlignment::CenterLeft,
- [](auto&) {
- return GUI::Variant();
- },
- [](auto&) {
- return GUI::Variant(0);
- },
- [](const JsonObject& object) {
- auto pagemap = object.get("pagemap").as_string_or({});
- return pagemap;
- });
- pid_vm_fields.empend("cow_pages", "# CoW", Gfx::TextAlignment::CenterRight);
- pid_vm_fields.empend("name", "Name", Gfx::TextAlignment::CenterLeft);
- m_json_model = GUI::JsonArrayModel::create({}, move(pid_vm_fields));
- m_table_view->set_model(GUI::SortingProxyModel::create(*m_json_model));
-
- m_table_view->set_column_painting_delegate(7, make<PagemapPaintingDelegate>());
-
- m_table_view->set_key_column_and_sort_order(0, GUI::SortOrder::Ascending);
- m_timer = add<Core::Timer>(1000, [this] { refresh(); });
-}
-
-ProcessMemoryMapWidget::~ProcessMemoryMapWidget()
-{
-}
-
-void ProcessMemoryMapWidget::set_pid(pid_t pid)
-{
- if (m_pid == pid)
- return;
- m_pid = pid;
- m_json_model->set_json_path(String::formatted("/proc/{}/vm", pid));
-}
-
-void ProcessMemoryMapWidget::refresh()
-{
- if (m_pid != -1)
- m_json_model->update();
-}
diff --git a/Applications/SystemMonitor/ProcessMemoryMapWidget.h b/Applications/SystemMonitor/ProcessMemoryMapWidget.h
deleted file mode 100644
index 71a554fe51..0000000000
--- a/Applications/SystemMonitor/ProcessMemoryMapWidget.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-class ProcessMemoryMapWidget final : public GUI::Widget {
- C_OBJECT(ProcessMemoryMapWidget);
-
-public:
- virtual ~ProcessMemoryMapWidget() override;
-
- void set_pid(pid_t);
- void refresh();
-
-private:
- ProcessMemoryMapWidget();
- RefPtr<GUI::TableView> m_table_view;
- RefPtr<GUI::JsonArrayModel> m_json_model;
- pid_t m_pid { -1 };
- RefPtr<Core::Timer> m_timer;
-};
diff --git a/Applications/SystemMonitor/ProcessModel.cpp b/Applications/SystemMonitor/ProcessModel.cpp
deleted file mode 100644
index c12a5503ab..0000000000
--- a/Applications/SystemMonitor/ProcessModel.cpp
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ProcessModel.h"
-#include "GraphWidget.h"
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonValue.h>
-#include <AK/SharedBuffer.h>
-#include <LibCore/File.h>
-#include <LibCore/ProcessStatisticsReader.h>
-#include <LibGUI/FileIconProvider.h>
-#include <fcntl.h>
-#include <stdio.h>
-
-static ProcessModel* s_the;
-
-ProcessModel& ProcessModel::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-ProcessModel::ProcessModel()
-{
- ASSERT(!s_the);
- s_the = this;
- m_generic_process_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/gear.png");
- m_high_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/highpriority.png");
- m_low_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/lowpriority.png");
- m_normal_priority_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/normalpriority.png");
-
- auto file = Core::File::construct("/proc/cpuinfo");
- if (file->open(Core::IODevice::ReadOnly)) {
- auto json = JsonValue::from_string({ file->read_all() });
- auto cpuinfo_array = json.value().as_array();
- cpuinfo_array.for_each([&](auto& value) {
- auto& cpu_object = value.as_object();
- auto cpu_id = cpu_object.get("processor").as_u32();
- m_cpus.append(make<CpuInfo>(cpu_id));
- });
- }
-
- if (m_cpus.is_empty())
- m_cpus.append(make<CpuInfo>(0));
-}
-
-ProcessModel::~ProcessModel()
-{
-}
-
-int ProcessModel::row_count(const GUI::ModelIndex&) const
-{
- return m_pids.size();
-}
-
-int ProcessModel::column_count(const GUI::ModelIndex&) const
-{
- return Column::__Count;
-}
-
-String ProcessModel::column_name(int column) const
-{
- switch (column) {
- case Column::Icon:
- return "";
- case Column::PID:
- return "PID";
- case Column::TID:
- return "TID";
- case Column::PPID:
- return "PPID";
- case Column::PGID:
- return "PGID";
- case Column::SID:
- return "SID";
- case Column::State:
- return "State";
- case Column::User:
- return "User";
- case Column::Priority:
- return "Pr";
- case Column::EffectivePriority:
- return "EPr";
- case Column::Virtual:
- return "Virtual";
- case Column::Physical:
- return "Physical";
- case Column::DirtyPrivate:
- return "DirtyP";
- case Column::CleanInode:
- return "CleanI";
- case Column::PurgeableVolatile:
- return "Purg:V";
- case Column::PurgeableNonvolatile:
- return "Purg:N";
- case Column::CPU:
- return "CPU";
- case Column::Processor:
- return "Processor";
- case Column::Name:
- return "Name";
- case Column::Syscalls:
- return "Syscalls";
- case Column::InodeFaults:
- return "F:Inode";
- case Column::ZeroFaults:
- return "F:Zero";
- case Column::CowFaults:
- return "F:CoW";
- case Column::IPv4SocketReadBytes:
- return "IPv4 In";
- case Column::IPv4SocketWriteBytes:
- return "IPv4 Out";
- case Column::UnixSocketReadBytes:
- return "Unix In";
- case Column::UnixSocketWriteBytes:
- return "Unix Out";
- case Column::FileReadBytes:
- return "File In";
- case Column::FileWriteBytes:
- return "File Out";
- case Column::Pledge:
- return "Pledge";
- case Column::Veil:
- return "Veil";
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-static String pretty_byte_size(size_t size)
-{
- return String::formatted("{}K", size / 1024);
-}
-
-GUI::Variant ProcessModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
-{
- ASSERT(is_valid(index));
-
- if (role == GUI::ModelRole::TextAlignment) {
- switch (index.column()) {
- case Column::Icon:
- case Column::Name:
- case Column::State:
- case Column::User:
- case Column::Pledge:
- case Column::Veil:
- return Gfx::TextAlignment::CenterLeft;
- case Column::PID:
- case Column::TID:
- case Column::PPID:
- case Column::PGID:
- case Column::SID:
- case Column::Priority:
- case Column::EffectivePriority:
- case Column::Virtual:
- case Column::Physical:
- case Column::DirtyPrivate:
- case Column::CleanInode:
- case Column::PurgeableVolatile:
- case Column::PurgeableNonvolatile:
- case Column::CPU:
- case Column::Processor:
- case Column::Syscalls:
- case Column::InodeFaults:
- case Column::ZeroFaults:
- case Column::CowFaults:
- case Column::FileReadBytes:
- case Column::FileWriteBytes:
- case Column::UnixSocketReadBytes:
- case Column::UnixSocketWriteBytes:
- case Column::IPv4SocketReadBytes:
- case Column::IPv4SocketWriteBytes:
- return Gfx::TextAlignment::CenterRight;
- default:
- ASSERT_NOT_REACHED();
- }
- }
-
- auto it = m_threads.find(m_pids[index.row()]);
- auto& thread = *(*it).value;
-
- if (role == GUI::ModelRole::Sort) {
- switch (index.column()) {
- case Column::Icon:
- return 0;
- case Column::PID:
- return thread.current_state.pid;
- case Column::TID:
- return thread.current_state.tid;
- case Column::PPID:
- return thread.current_state.ppid;
- case Column::PGID:
- return thread.current_state.pgid;
- case Column::SID:
- return thread.current_state.sid;
- case Column::State:
- return thread.current_state.state;
- case Column::User:
- return thread.current_state.user;
- case Column::Priority:
- return thread.current_state.priority;
- case Column::EffectivePriority:
- return thread.current_state.effective_priority;
- case Column::Virtual:
- return (int)thread.current_state.amount_virtual;
- case Column::Physical:
- return (int)thread.current_state.amount_resident;
- case Column::DirtyPrivate:
- return (int)thread.current_state.amount_dirty_private;
- case Column::CleanInode:
- return (int)thread.current_state.amount_clean_inode;
- case Column::PurgeableVolatile:
- return (int)thread.current_state.amount_purgeable_volatile;
- case Column::PurgeableNonvolatile:
- return (int)thread.current_state.amount_purgeable_nonvolatile;
- case Column::CPU:
- return thread.current_state.cpu_percent;
- case Column::Processor:
- return thread.current_state.cpu;
- case Column::Name:
- return thread.current_state.name;
- case Column::Syscalls:
- return thread.current_state.syscall_count;
- case Column::InodeFaults:
- return thread.current_state.inode_faults;
- case Column::ZeroFaults:
- return thread.current_state.zero_faults;
- case Column::CowFaults:
- return thread.current_state.cow_faults;
- case Column::IPv4SocketReadBytes:
- return thread.current_state.ipv4_socket_read_bytes;
- case Column::IPv4SocketWriteBytes:
- return thread.current_state.ipv4_socket_write_bytes;
- case Column::UnixSocketReadBytes:
- return thread.current_state.unix_socket_read_bytes;
- case Column::UnixSocketWriteBytes:
- return thread.current_state.unix_socket_write_bytes;
- case Column::FileReadBytes:
- return thread.current_state.file_read_bytes;
- case Column::FileWriteBytes:
- return thread.current_state.file_write_bytes;
- case Column::Pledge:
- return thread.current_state.pledge;
- case Column::Veil:
- return thread.current_state.veil;
- }
- ASSERT_NOT_REACHED();
- return {};
- }
-
- if (role == GUI::ModelRole::Display) {
- switch (index.column()) {
- case Column::Icon: {
- auto icon = GUI::FileIconProvider::icon_for_executable(thread.current_state.executable);
- if (auto* bitmap = icon.bitmap_for_size(16))
- return *bitmap;
- return *m_generic_process_icon;
- }
- case Column::PID:
- return thread.current_state.pid;
- case Column::TID:
- return thread.current_state.tid;
- case Column::PPID:
- return thread.current_state.ppid;
- case Column::PGID:
- return thread.current_state.pgid;
- case Column::SID:
- return thread.current_state.sid;
- case Column::State:
- return thread.current_state.state;
- case Column::User:
- return thread.current_state.user;
- case Column::Priority:
- return thread.current_state.priority;
- case Column::EffectivePriority:
- return thread.current_state.effective_priority;
- case Column::Virtual:
- return pretty_byte_size(thread.current_state.amount_virtual);
- case Column::Physical:
- return pretty_byte_size(thread.current_state.amount_resident);
- case Column::DirtyPrivate:
- return pretty_byte_size(thread.current_state.amount_dirty_private);
- case Column::CleanInode:
- return pretty_byte_size(thread.current_state.amount_clean_inode);
- case Column::PurgeableVolatile:
- return pretty_byte_size(thread.current_state.amount_purgeable_volatile);
- case Column::PurgeableNonvolatile:
- return pretty_byte_size(thread.current_state.amount_purgeable_nonvolatile);
- case Column::CPU:
- return thread.current_state.cpu_percent;
- case Column::Processor:
- return thread.current_state.cpu;
- case Column::Name:
- return thread.current_state.name;
- case Column::Syscalls:
- return thread.current_state.syscall_count;
- case Column::InodeFaults:
- return thread.current_state.inode_faults;
- case Column::ZeroFaults:
- return thread.current_state.zero_faults;
- case Column::CowFaults:
- return thread.current_state.cow_faults;
- case Column::IPv4SocketReadBytes:
- return thread.current_state.ipv4_socket_read_bytes;
- case Column::IPv4SocketWriteBytes:
- return thread.current_state.ipv4_socket_write_bytes;
- case Column::UnixSocketReadBytes:
- return thread.current_state.unix_socket_read_bytes;
- case Column::UnixSocketWriteBytes:
- return thread.current_state.unix_socket_write_bytes;
- case Column::FileReadBytes:
- return thread.current_state.file_read_bytes;
- case Column::FileWriteBytes:
- return thread.current_state.file_write_bytes;
- case Column::Pledge:
- return thread.current_state.pledge;
- case Column::Veil:
- return thread.current_state.veil;
- }
- }
-
- return {};
-}
-
-void ProcessModel::update()
-{
- auto previous_pid_count = m_pids.size();
- auto all_processes = Core::ProcessStatisticsReader::get_all(m_proc_all);
-
- u64 last_sum_ticks_scheduled = 0, last_sum_ticks_scheduled_kernel = 0;
- for (auto& it : m_threads) {
- auto& current_state = it.value->current_state;
- last_sum_ticks_scheduled += current_state.ticks_user + current_state.ticks_kernel;
- last_sum_ticks_scheduled_kernel += current_state.ticks_kernel;
- }
-
- HashTable<PidAndTid> live_pids;
- u64 sum_ticks_scheduled = 0, sum_ticks_scheduled_kernel = 0;
- if (all_processes.has_value()) {
- for (auto& it : all_processes.value()) {
- for (auto& thread : it.value.threads) {
- ThreadState state;
- state.pid = it.value.pid;
- state.user = it.value.username;
- state.pledge = it.value.pledge;
- state.veil = it.value.veil;
- state.syscall_count = thread.syscall_count;
- state.inode_faults = thread.inode_faults;
- state.zero_faults = thread.zero_faults;
- state.cow_faults = thread.cow_faults;
- state.unix_socket_read_bytes = thread.unix_socket_read_bytes;
- state.unix_socket_write_bytes = thread.unix_socket_write_bytes;
- state.ipv4_socket_read_bytes = thread.ipv4_socket_read_bytes;
- state.ipv4_socket_write_bytes = thread.ipv4_socket_write_bytes;
- state.file_read_bytes = thread.file_read_bytes;
- state.file_write_bytes = thread.file_write_bytes;
- state.amount_virtual = it.value.amount_virtual;
- state.amount_resident = it.value.amount_resident;
- state.amount_dirty_private = it.value.amount_dirty_private;
- state.amount_clean_inode = it.value.amount_clean_inode;
- state.amount_purgeable_volatile = it.value.amount_purgeable_volatile;
- state.amount_purgeable_nonvolatile = it.value.amount_purgeable_nonvolatile;
-
- state.name = thread.name;
- state.executable = it.value.executable;
-
- state.ppid = it.value.ppid;
- state.tid = thread.tid;
- state.pgid = it.value.pgid;
- state.sid = it.value.sid;
- state.times_scheduled = thread.times_scheduled;
- state.ticks_user = thread.ticks_user;
- state.ticks_kernel = thread.ticks_kernel;
- state.cpu = thread.cpu;
- state.cpu_percent = 0;
- state.priority = thread.priority;
- state.effective_priority = thread.effective_priority;
- state.state = thread.state;
- sum_ticks_scheduled += thread.ticks_user + thread.ticks_kernel;
- sum_ticks_scheduled_kernel += thread.ticks_kernel;
- {
- auto pit = m_threads.find({ it.value.pid, thread.tid });
- if (pit == m_threads.end())
- m_threads.set({ it.value.pid, thread.tid }, make<Thread>());
- }
- auto pit = m_threads.find({ it.value.pid, thread.tid });
- ASSERT(pit != m_threads.end());
- (*pit).value->previous_state = (*pit).value->current_state;
- (*pit).value->current_state = state;
-
- live_pids.set({ it.value.pid, thread.tid });
- }
- }
- }
-
- m_pids.clear();
- for (auto& c : m_cpus) {
- c.total_cpu_percent = 0.0;
- c.total_cpu_percent_kernel = 0.0;
- }
- Vector<PidAndTid, 16> pids_to_remove;
- for (auto& it : m_threads) {
- if (!live_pids.contains(it.key)) {
- pids_to_remove.append(it.key);
- continue;
- }
- auto& process = *it.value;
- u32 ticks_scheduled_diff = (process.current_state.ticks_user + process.current_state.ticks_kernel)
- - (process.previous_state.ticks_user + process.previous_state.ticks_kernel);
- u32 ticks_scheduled_diff_kernel = process.current_state.ticks_kernel - process.previous_state.ticks_kernel;
- process.current_state.cpu_percent = ((float)ticks_scheduled_diff * 100) / (float)(sum_ticks_scheduled - last_sum_ticks_scheduled);
- process.current_state.cpu_percent_kernel = ((float)ticks_scheduled_diff_kernel * 100) / (float)(sum_ticks_scheduled - last_sum_ticks_scheduled);
- if (it.key.pid != 0) {
- auto& cpu_info = m_cpus[process.current_state.cpu];
- cpu_info.total_cpu_percent += process.current_state.cpu_percent;
- cpu_info.total_cpu_percent_kernel += process.current_state.cpu_percent_kernel;
- m_pids.append(it.key);
- }
- }
- for (auto pid : pids_to_remove)
- m_threads.remove(pid);
-
- if (on_cpu_info_change)
- on_cpu_info_change(m_cpus);
-
- // FIXME: This is a rather hackish way of invalidating indexes.
- // It would be good if GUI::Model had a way to orchestrate removal/insertion while preserving indexes.
- did_update(previous_pid_count == m_pids.size() ? GUI::Model::UpdateFlag::DontInvalidateIndexes : GUI::Model::UpdateFlag::InvalidateAllIndexes);
-}
diff --git a/Applications/SystemMonitor/ProcessModel.h b/Applications/SystemMonitor/ProcessModel.h
deleted file mode 100644
index 11f39cac76..0000000000
--- a/Applications/SystemMonitor/ProcessModel.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <LibGUI/Model.h>
-#include <unistd.h>
-
-class GraphWidget;
-
-struct PidAndTid {
- bool operator==(const PidAndTid& other) const
- {
- return pid == other.pid && tid == other.tid;
- }
- pid_t pid;
- int tid;
-};
-
-class ProcessModel final : public GUI::Model {
-public:
- enum Column {
- Icon = 0,
- Name,
- CPU,
- Processor,
- State,
- Priority,
- EffectivePriority,
- User,
- PID,
- TID,
- PPID,
- PGID,
- SID,
- Virtual,
- Physical,
- DirtyPrivate,
- CleanInode,
- PurgeableVolatile,
- PurgeableNonvolatile,
- Veil,
- Pledge,
- Syscalls,
- InodeFaults,
- ZeroFaults,
- CowFaults,
- FileReadBytes,
- FileWriteBytes,
- UnixSocketReadBytes,
- UnixSocketWriteBytes,
- IPv4SocketReadBytes,
- IPv4SocketWriteBytes,
- __Count
- };
-
- static ProcessModel& the();
-
- static NonnullRefPtr<ProcessModel> create() { return adopt(*new ProcessModel); }
- virtual ~ProcessModel() override;
-
- virtual int row_count(const GUI::ModelIndex&) const override;
- virtual int column_count(const GUI::ModelIndex&) const override;
- virtual String column_name(int column) const override;
- virtual GUI::Variant data(const GUI::ModelIndex&, GUI::ModelRole) const override;
- virtual void update() override;
-
- struct CpuInfo {
- u32 id;
- float total_cpu_percent { 0.0 };
- float total_cpu_percent_kernel { 0.0 };
-
- CpuInfo(u32 id)
- : id(id)
- {
- }
- };
-
- Function<void(const NonnullOwnPtrVector<CpuInfo>&)> on_cpu_info_change;
-
- const NonnullOwnPtrVector<CpuInfo>& cpus() const { return m_cpus; }
-
-private:
- ProcessModel();
-
- struct ThreadState {
- pid_t tid;
- pid_t pid;
- pid_t ppid;
- pid_t pgid;
- pid_t sid;
- unsigned times_scheduled;
- unsigned ticks_user;
- unsigned ticks_kernel;
- String executable;
- String name;
- String state;
- String user;
- String pledge;
- String veil;
- u32 cpu;
- u32 priority;
- u32 effective_priority;
- size_t amount_virtual;
- size_t amount_resident;
- size_t amount_dirty_private;
- size_t amount_clean_inode;
- size_t amount_purgeable_volatile;
- size_t amount_purgeable_nonvolatile;
- unsigned syscall_count;
- unsigned inode_faults;
- unsigned zero_faults;
- unsigned cow_faults;
- unsigned unix_socket_read_bytes;
- unsigned unix_socket_write_bytes;
- unsigned ipv4_socket_read_bytes;
- unsigned ipv4_socket_write_bytes;
- unsigned file_read_bytes;
- unsigned file_write_bytes;
- float cpu_percent;
- float cpu_percent_kernel;
- };
-
- struct Thread {
- ThreadState current_state;
- ThreadState previous_state;
- };
-
- HashMap<uid_t, String> m_usernames;
- HashMap<PidAndTid, NonnullOwnPtr<Thread>> m_threads;
- NonnullOwnPtrVector<CpuInfo> m_cpus;
- Vector<PidAndTid> m_pids;
- RefPtr<Gfx::Bitmap> m_generic_process_icon;
- RefPtr<Gfx::Bitmap> m_high_priority_icon;
- RefPtr<Gfx::Bitmap> m_low_priority_icon;
- RefPtr<Gfx::Bitmap> m_normal_priority_icon;
- RefPtr<Core::File> m_proc_all;
-};
-
-namespace AK {
-template<>
-struct Traits<PidAndTid> : public GenericTraits<PidAndTid> {
- static unsigned hash(const PidAndTid& value) { return pair_int_hash(value.pid, value.tid); }
-};
-}
diff --git a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp b/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp
deleted file mode 100644
index 9e2d22443c..0000000000
--- a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ProcessUnveiledPathsWidget.h"
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/TableView.h>
-
-ProcessUnveiledPathsWidget::ProcessUnveiledPathsWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
- m_table_view = add<GUI::TableView>();
-
- Vector<GUI::JsonArrayModel::FieldSpec> pid_unveil_fields;
- pid_unveil_fields.empend("path", "Path", Gfx::TextAlignment::CenterLeft);
- pid_unveil_fields.empend("permissions", "Permissions", Gfx::TextAlignment::CenterLeft);
-
- m_model = GUI::JsonArrayModel::create({}, move(pid_unveil_fields));
- m_table_view->set_model(GUI::SortingProxyModel::create(*m_model));
-}
-
-ProcessUnveiledPathsWidget::~ProcessUnveiledPathsWidget()
-{
-}
-
-void ProcessUnveiledPathsWidget::set_pid(pid_t pid)
-{
- if (m_pid == pid)
- return;
- m_pid = pid;
- m_model->set_json_path(String::formatted("/proc/{}/unveil", m_pid));
-}
diff --git a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h b/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h
deleted file mode 100644
index d1eac898b2..0000000000
--- a/Applications/SystemMonitor/ProcessUnveiledPathsWidget.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Widget.h>
-
-class ProcessUnveiledPathsWidget final : public GUI::Widget {
- C_OBJECT(ProcessUnveiledPathsWidget);
-
-public:
- virtual ~ProcessUnveiledPathsWidget() override;
-
- void set_pid(pid_t);
-
-private:
- ProcessUnveiledPathsWidget();
-
- RefPtr<GUI::TableView> m_table_view;
- RefPtr<GUI::JsonArrayModel> m_model;
- pid_t m_pid { -1 };
-};
diff --git a/Applications/SystemMonitor/ThreadStackWidget.cpp b/Applications/SystemMonitor/ThreadStackWidget.cpp
deleted file mode 100644
index 01e37791a0..0000000000
--- a/Applications/SystemMonitor/ThreadStackWidget.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "ThreadStackWidget.h"
-#include <AK/ByteBuffer.h>
-#include <LibCore/File.h>
-#include <LibCore/Timer.h>
-#include <LibGUI/BoxLayout.h>
-
-ThreadStackWidget::ThreadStackWidget()
-{
- set_layout<GUI::VerticalBoxLayout>();
- layout()->set_margins({ 4, 4, 4, 4 });
- m_stack_editor = add<GUI::TextEditor>();
- m_stack_editor->set_mode(GUI::TextEditor::ReadOnly);
-
- m_timer = add<Core::Timer>(1000, [this] { refresh(); });
-}
-
-ThreadStackWidget::~ThreadStackWidget()
-{
-}
-
-void ThreadStackWidget::set_ids(pid_t pid, pid_t tid)
-{
- if (m_pid == pid && m_tid == tid)
- return;
- m_pid = pid;
- m_tid = tid;
- refresh();
-}
-
-void ThreadStackWidget::refresh()
-{
- auto file = Core::File::construct(String::formatted("/proc/{}/stacks/{}", m_pid, m_tid));
- if (!file->open(Core::IODevice::ReadOnly)) {
- m_stack_editor->set_text(String::formatted("Unable to open {}", file->filename()));
- return;
- }
-
- auto new_text = file->read_all();
- if (m_stack_editor->text() != new_text) {
- m_stack_editor->set_text(new_text);
- }
-}
diff --git a/Applications/SystemMonitor/ThreadStackWidget.h b/Applications/SystemMonitor/ThreadStackWidget.h
deleted file mode 100644
index 5a10e93b0a..0000000000
--- a/Applications/SystemMonitor/ThreadStackWidget.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Widget.h>
-
-class ThreadStackWidget final : public GUI::Widget {
- C_OBJECT(ThreadStackWidget)
-public:
- virtual ~ThreadStackWidget() override;
-
- void set_ids(pid_t pid, pid_t tid);
- void refresh();
-
-private:
- ThreadStackWidget();
-
- pid_t m_pid { -1 };
- pid_t m_tid { -1 };
- RefPtr<GUI::TextEditor> m_stack_editor;
- RefPtr<Core::Timer> m_timer;
-};
diff --git a/Applications/SystemMonitor/main.cpp b/Applications/SystemMonitor/main.cpp
deleted file mode 100644
index bdf88e44d1..0000000000
--- a/Applications/SystemMonitor/main.cpp
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "DevicesModel.h"
-#include "GraphWidget.h"
-#include "InterruptsWidget.h"
-#include "MemoryStatsWidget.h"
-#include "NetworkStatisticsWidget.h"
-#include "ProcessFileDescriptorMapWidget.h"
-#include "ProcessMemoryMapWidget.h"
-#include "ProcessModel.h"
-#include "ProcessUnveiledPathsWidget.h"
-#include "ThreadStackWidget.h"
-#include <AK/NumberFormat.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/Timer.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/JsonArrayModel.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/LazyWidget.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/SortingProxyModel.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/TabWidget.h>
-#include <LibGUI/TableView.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Palette.h>
-#include <LibPCIDB/Database.h>
-#include <serenity.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <unistd.h>
-
-static NonnullRefPtr<GUI::Widget> build_file_systems_tab();
-static NonnullRefPtr<GUI::Widget> build_pci_devices_tab();
-static NonnullRefPtr<GUI::Widget> build_devices_tab();
-static NonnullRefPtr<GUI::Widget> build_graphs_tab();
-static NonnullRefPtr<GUI::Widget> build_processors_tab();
-
-class UnavailableProcessWidget final : public GUI::Frame {
- C_OBJECT(UnavailableProcessWidget)
-public:
- virtual ~UnavailableProcessWidget() override { }
-
- const String& text() const { return m_text; }
- void set_text(String text) { m_text = move(text); }
-
-private:
- UnavailableProcessWidget(String text)
- : m_text(move(text))
- {
- }
-
- virtual void paint_event(GUI::PaintEvent& event) override
- {
- Frame::paint_event(event);
- if (text().is_empty())
- return;
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.draw_text(frame_inner_rect(), text(), Gfx::TextAlignment::Center, palette().window_text(), Gfx::TextElision::Right);
- }
-
- String m_text;
-};
-
-static bool can_access_pid(pid_t pid)
-{
- auto path = String::formatted("/proc/{}", pid);
- return access(path.characters(), X_OK) == 0;
-}
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio proc shared_buffer accept rpath exec unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio proc shared_buffer accept rpath exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/etc/passwd", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/proc", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/dev", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin/Profiler", "rx") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin/Inspector", "rx") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- const char* args_tab = "processes";
- Core::ArgsParser parser;
- parser.add_option(args_tab, "Tab, one of 'processes', 'graphs', 'fs', 'pci', 'devices', 'network', 'processors' or 'interrupts'", "open-tab", 't', "tab");
- parser.parse(argc, argv);
- StringView args_tab_view = args_tab;
-
- auto app_icon = GUI::Icon::default_icon("app-system-monitor");
-
- auto window = GUI::Window::construct();
- window->set_title("System Monitor");
- window->resize(680, 400);
-
- auto& keeper = window->set_main_widget<GUI::Widget>();
- keeper.set_layout<GUI::VerticalBoxLayout>();
- keeper.set_fill_with_background_color(true);
- keeper.layout()->set_margins({ 2, 2, 2, 2 });
-
- auto& tabwidget = keeper.add<GUI::TabWidget>();
-
- auto process_container_splitter = GUI::VerticalSplitter::construct();
- tabwidget.add_widget("Processes", process_container_splitter);
- process_container_splitter->layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& process_table_container = process_container_splitter->add<GUI::Widget>();
-
- auto graphs_widget = build_graphs_tab();
- tabwidget.add_widget("Graphs", graphs_widget);
-
- auto file_systems_widget = build_file_systems_tab();
- tabwidget.add_widget("File systems", file_systems_widget);
-
- auto pci_devices_widget = build_pci_devices_tab();
- tabwidget.add_widget("PCI devices", pci_devices_widget);
-
- auto devices_widget = build_devices_tab();
- tabwidget.add_widget("Devices", devices_widget);
-
- auto network_stats_widget = NetworkStatisticsWidget::construct();
- tabwidget.add_widget("Network", network_stats_widget);
-
- auto processors_widget = build_processors_tab();
- tabwidget.add_widget("Processors", processors_widget);
-
- auto interrupts_widget = InterruptsWidget::construct();
- tabwidget.add_widget("Interrupts", interrupts_widget);
-
- process_table_container.set_layout<GUI::VerticalBoxLayout>();
- process_table_container.layout()->set_spacing(0);
-
- auto& process_table_view = process_table_container.add<GUI::TableView>();
- process_table_view.set_column_headers_visible(true);
- process_table_view.set_model(GUI::SortingProxyModel::create(ProcessModel::create()));
- process_table_view.set_key_column_and_sort_order(ProcessModel::Column::CPU, GUI::SortOrder::Descending);
- process_table_view.model()->update();
-
- auto& refresh_timer = window->add<Core::Timer>(
- 3000, [&] {
- process_table_view.model()->update();
- if (auto* memory_stats_widget = MemoryStatsWidget::the())
- memory_stats_widget->refresh();
- });
-
- auto selected_id = [&](ProcessModel::Column column) -> pid_t {
- if (process_table_view.selection().is_empty())
- return -1;
- auto pid_index = process_table_view.model()->index(process_table_view.selection().first().row(), column);
- return pid_index.data().to_i32();
- };
-
- auto kill_action = GUI::Action::create("Kill process", { Mod_Ctrl, Key_K }, Gfx::Bitmap::load_from_file("/res/icons/16x16/kill.png"), [&](const GUI::Action&) {
- pid_t pid = selected_id(ProcessModel::Column::PID);
- if (pid != -1)
- kill(pid, SIGKILL);
- });
-
- auto stop_action = GUI::Action::create("Stop process", { Mod_Ctrl, Key_S }, Gfx::Bitmap::load_from_file("/res/icons/16x16/stop-hand.png"), [&](const GUI::Action&) {
- pid_t pid = selected_id(ProcessModel::Column::PID);
- if (pid != -1)
- kill(pid, SIGSTOP);
- });
-
- auto continue_action = GUI::Action::create("Continue process", { Mod_Ctrl, Key_C }, Gfx::Bitmap::load_from_file("/res/icons/16x16/continue.png"), [&](const GUI::Action&) {
- pid_t pid = selected_id(ProcessModel::Column::PID);
- if (pid != -1)
- kill(pid, SIGCONT);
- });
-
- auto profile_action = GUI::Action::create("Profile process", { Mod_Ctrl, Key_P },
- Gfx::Bitmap::load_from_file("/res/icons/16x16/app-profiler.png"), [&](auto&) {
- pid_t pid = selected_id(ProcessModel::Column::PID);
- if (pid != -1) {
- auto pid_string = String::format("%d", pid);
- pid_t child;
- const char* argv[] = { "/bin/Profiler", "--pid", pid_string.characters(), nullptr };
- if ((errno = posix_spawn(&child, "/bin/Profiler", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child) < 0)
- perror("disown");
- }
- }
- });
-
- auto inspect_action = GUI::Action::create("Inspect process", { Mod_Ctrl, Key_I },
- Gfx::Bitmap::load_from_file("/res/icons/16x16/app-inspector.png"), [&](auto&) {
- pid_t pid = selected_id(ProcessModel::Column::PID);
- if (pid != -1) {
- auto pid_string = String::format("%d", pid);
- pid_t child;
- const char* argv[] = { "/bin/Inspector", pid_string.characters(), nullptr };
- if ((errno = posix_spawn(&child, "/bin/Inspector", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child) < 0)
- perror("disown");
- }
- }
- });
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("System Monitor");
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- GUI::Application::the()->quit();
- return;
- }));
-
- auto& process_menu = menubar->add_menu("Process");
- process_menu.add_action(kill_action);
- process_menu.add_action(stop_action);
- process_menu.add_action(continue_action);
- process_menu.add_separator();
- process_menu.add_action(profile_action);
- process_menu.add_action(inspect_action);
-
- auto process_context_menu = GUI::Menu::construct();
- process_context_menu->add_action(kill_action);
- process_context_menu->add_action(stop_action);
- process_context_menu->add_action(continue_action);
- process_context_menu->add_separator();
- process_context_menu->add_action(profile_action);
- process_context_menu->add_action(inspect_action);
- process_table_view.on_context_menu_request = [&]([[maybe_unused]] const GUI::ModelIndex& index, const GUI::ContextMenuEvent& event) {
- process_context_menu->popup(event.screen_position());
- };
-
- auto& frequency_menu = menubar->add_menu("Frequency");
- GUI::ActionGroup frequency_action_group;
- frequency_action_group.set_exclusive(true);
-
- auto make_frequency_action = [&](auto& title, int interval, bool checked = false) {
- auto action = GUI::Action::create_checkable(title, [&refresh_timer, interval](auto&) {
- refresh_timer.restart(interval);
- });
- action->set_checked(checked);
- frequency_action_group.add_action(*action);
- frequency_menu.add_action(*action);
- };
-
- make_frequency_action("1 sec", 1000);
- make_frequency_action("3 sec", 3000, true);
- make_frequency_action("5 sec", 5000);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("System Monitor", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- auto& process_tab_unused_widget = process_container_splitter->add<UnavailableProcessWidget>("No process selected");
- process_tab_unused_widget.set_visible(true);
-
- auto& process_tab_widget = process_container_splitter->add<GUI::TabWidget>();
- process_tab_widget.set_tab_position(GUI::TabWidget::TabPosition::Bottom);
- process_tab_widget.set_visible(false);
-
- auto& memory_map_widget = process_tab_widget.add_tab<ProcessMemoryMapWidget>("Memory map");
- auto& open_files_widget = process_tab_widget.add_tab<ProcessFileDescriptorMapWidget>("Open files");
- auto& unveiled_paths_widget = process_tab_widget.add_tab<ProcessUnveiledPathsWidget>("Unveiled paths");
- auto& stack_widget = process_tab_widget.add_tab<ThreadStackWidget>("Stack");
-
- process_table_view.on_selection = [&](auto&) {
- auto pid = selected_id(ProcessModel::Column::PID);
- auto tid = selected_id(ProcessModel::Column::TID);
- if (!can_access_pid(pid)) {
- process_tab_widget.set_visible(false);
- process_tab_unused_widget.set_text("Process cannot be accessed");
- process_tab_unused_widget.set_visible(true);
- return;
- }
-
- process_tab_widget.set_visible(true);
- process_tab_unused_widget.set_visible(false);
- open_files_widget.set_pid(pid);
- stack_widget.set_ids(pid, tid);
- memory_map_widget.set_pid(pid);
- unveiled_paths_widget.set_pid(pid);
- };
-
- window->show();
-
- window->set_icon(app_icon.bitmap_for_size(16));
-
- if (args_tab_view == "processes")
- tabwidget.set_active_widget(process_container_splitter);
- else if (args_tab_view == "graphs")
- tabwidget.set_active_widget(graphs_widget);
- else if (args_tab_view == "fs")
- tabwidget.set_active_widget(file_systems_widget);
- else if (args_tab_view == "pci")
- tabwidget.set_active_widget(pci_devices_widget);
- else if (args_tab_view == "devices")
- tabwidget.set_active_widget(devices_widget);
- else if (args_tab_view == "network")
- tabwidget.set_active_widget(network_stats_widget);
- else if (args_tab_view == "processors")
- tabwidget.set_active_widget(processors_widget);
- else if (args_tab_view == "interrupts")
- tabwidget.set_active_widget(interrupts_widget);
-
- return app->exec();
-}
-
-class ProgressBarPaintingDelegate final : public GUI::TableCellPaintingDelegate {
-public:
- virtual ~ProgressBarPaintingDelegate() override { }
-
- virtual void paint(GUI::Painter& painter, const Gfx::IntRect& a_rect, const Palette& palette, const GUI::ModelIndex& index) override
- {
- auto rect = a_rect.shrunken(2, 2);
- auto percentage = index.data(GUI::ModelRole::Custom).to_i32();
-
- auto data = index.data();
- String text;
- if (data.is_string())
- text = data.as_string();
- Gfx::StylePainter::paint_progress_bar(painter, rect, palette, 0, 100, percentage, text);
- painter.draw_rect(rect, Color::Black);
- }
-};
-
-NonnullRefPtr<GUI::Widget> build_file_systems_tab()
-{
- auto fs_widget = GUI::LazyWidget::construct();
-
- fs_widget->on_first_show = [](GUI::LazyWidget& self) {
- self.set_layout<GUI::VerticalBoxLayout>();
- self.layout()->set_margins({ 4, 4, 4, 4 });
- auto& fs_table_view = self.add<GUI::TableView>();
-
- Vector<GUI::JsonArrayModel::FieldSpec> df_fields;
- df_fields.empend("mount_point", "Mount point", Gfx::TextAlignment::CenterLeft);
- df_fields.empend("class_name", "Class", Gfx::TextAlignment::CenterLeft);
- df_fields.empend("source", "Source", Gfx::TextAlignment::CenterLeft);
- df_fields.empend(
- "Size", Gfx::TextAlignment::CenterRight,
- [](const JsonObject& object) {
- StringBuilder size_builder;
- size_builder.append(" ");
- size_builder.append(human_readable_size(object.get("total_block_count").to_u32() * object.get("block_size").to_u32()));
- size_builder.append(" ");
- return size_builder.to_string();
- },
- [](const JsonObject& object) {
- return object.get("total_block_count").to_u32() * object.get("block_size").to_u32();
- },
- [](const JsonObject& object) {
- auto total_blocks = object.get("total_block_count").to_u32();
- if (total_blocks == 0)
- return 0;
- auto free_blocks = object.get("free_block_count").to_u32();
- auto used_blocks = total_blocks - free_blocks;
- int percentage = (int)((float)used_blocks / (float)total_blocks * 100.0f);
- return percentage;
- });
- df_fields.empend(
- "Used", Gfx::TextAlignment::CenterRight,
- [](const JsonObject& object) {
- auto total_blocks = object.get("total_block_count").to_u32();
- auto free_blocks = object.get("free_block_count").to_u32();
- auto used_blocks = total_blocks - free_blocks;
- return human_readable_size(used_blocks * object.get("block_size").to_u32()); },
- [](const JsonObject& object) {
- auto total_blocks = object.get("total_block_count").to_u32();
- auto free_blocks = object.get("free_block_count").to_u32();
- auto used_blocks = total_blocks - free_blocks;
- return used_blocks * object.get("block_size").to_u32();
- });
- df_fields.empend(
- "Available", Gfx::TextAlignment::CenterRight,
- [](const JsonObject& object) {
- return human_readable_size(object.get("free_block_count").to_u32() * object.get("block_size").to_u32());
- },
- [](const JsonObject& object) {
- return object.get("free_block_count").to_u32() * object.get("block_size").to_u32();
- });
- df_fields.empend("Access", Gfx::TextAlignment::CenterLeft, [](const JsonObject& object) {
- bool readonly = object.get("readonly").to_bool();
- int mount_flags = object.get("mount_flags").to_int();
- return readonly || (mount_flags & MS_RDONLY) ? "Read-only" : "Read/Write";
- });
- df_fields.empend("Mount flags", Gfx::TextAlignment::CenterLeft, [](const JsonObject& object) {
- int mount_flags = object.get("mount_flags").to_int();
- StringBuilder builder;
- bool first = true;
- auto check = [&](int flag, const char* name) {
- if (!(mount_flags & flag))
- return;
- if (!first)
- builder.append(',');
- builder.append(name);
- first = false;
- };
- check(MS_NODEV, "nodev");
- check(MS_NOEXEC, "noexec");
- check(MS_NOSUID, "nosuid");
- check(MS_BIND, "bind");
- check(MS_RDONLY, "ro");
- if (builder.string_view().is_empty())
- return String("defaults");
- return builder.to_string();
- });
- df_fields.empend("free_block_count", "Free blocks", Gfx::TextAlignment::CenterRight);
- df_fields.empend("total_block_count", "Total blocks", Gfx::TextAlignment::CenterRight);
- df_fields.empend("free_inode_count", "Free inodes", Gfx::TextAlignment::CenterRight);
- df_fields.empend("total_inode_count", "Total inodes", Gfx::TextAlignment::CenterRight);
- df_fields.empend("block_size", "Block size", Gfx::TextAlignment::CenterRight);
- fs_table_view.set_model(GUI::SortingProxyModel::create(GUI::JsonArrayModel::create("/proc/df", move(df_fields))));
-
- fs_table_view.set_column_painting_delegate(3, make<ProgressBarPaintingDelegate>());
-
- fs_table_view.model()->update();
- };
- return fs_widget;
-}
-
-NonnullRefPtr<GUI::Widget> build_pci_devices_tab()
-{
- auto pci_widget = GUI::LazyWidget::construct();
-
- pci_widget->on_first_show = [](GUI::LazyWidget& self) {
- self.set_layout<GUI::VerticalBoxLayout>();
- self.layout()->set_margins({ 4, 4, 4, 4 });
- auto& pci_table_view = self.add<GUI::TableView>();
-
- auto db = PCIDB::Database::open();
-
- Vector<GUI::JsonArrayModel::FieldSpec> pci_fields;
- pci_fields.empend(
- "Address", Gfx::TextAlignment::CenterLeft,
- [](const JsonObject& object) {
- auto seg = object.get("seg").to_u32();
- auto bus = object.get("bus").to_u32();
- auto slot = object.get("slot").to_u32();
- auto function = object.get("function").to_u32();
- return String::formatted("{:04x}:{:02x}:{:02x}.{}", seg, bus, slot, function);
- });
- pci_fields.empend(
- "Class", Gfx::TextAlignment::CenterLeft,
- [db](const JsonObject& object) {
- auto class_id = object.get("class").to_u32();
- String class_name = db->get_class(class_id);
- return class_name == "" ? String::formatted("{:04x}", class_id) : class_name;
- });
- pci_fields.empend(
- "Vendor", Gfx::TextAlignment::CenterLeft,
- [db](const JsonObject& object) {
- auto vendor_id = object.get("vendor_id").to_u32();
- String vendor_name = db->get_vendor(vendor_id);
- return vendor_name == "" ? String::formatted("{:02x}", vendor_id) : vendor_name;
- });
- pci_fields.empend(
- "Device", Gfx::TextAlignment::CenterLeft,
- [db](const JsonObject& object) {
- auto vendor_id = object.get("vendor_id").to_u32();
- auto device_id = object.get("device_id").to_u32();
- String device_name = db->get_device(vendor_id, device_id);
- return device_name == "" ? String::formatted("{:02x}", device_id) : device_name;
- });
- pci_fields.empend(
- "Revision", Gfx::TextAlignment::CenterRight,
- [](const JsonObject& object) {
- auto revision_id = object.get("revision_id").to_u32();
- return String::formatted("{:02x}", revision_id);
- });
-
- pci_table_view.set_model(GUI::SortingProxyModel::create(GUI::JsonArrayModel::create("/proc/pci", move(pci_fields))));
- pci_table_view.model()->update();
- };
-
- return pci_widget;
-}
-
-NonnullRefPtr<GUI::Widget> build_devices_tab()
-{
- auto devices_widget = GUI::LazyWidget::construct();
-
- devices_widget->on_first_show = [](GUI::LazyWidget& self) {
- self.set_layout<GUI::VerticalBoxLayout>();
- self.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& devices_table_view = self.add<GUI::TableView>();
- devices_table_view.set_model(GUI::SortingProxyModel::create(DevicesModel::create()));
- devices_table_view.model()->update();
- };
-
- return devices_widget;
-}
-
-NonnullRefPtr<GUI::Widget> build_graphs_tab()
-{
- auto graphs_container = GUI::LazyWidget::construct();
-
- graphs_container->on_first_show = [](GUI::LazyWidget& self) {
- self.set_fill_with_background_color(true);
- self.set_background_role(ColorRole::Button);
- self.set_layout<GUI::VerticalBoxLayout>();
- self.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& cpu_graph_group_box = self.add<GUI::GroupBox>("CPU usage");
- cpu_graph_group_box.set_layout<GUI::HorizontalBoxLayout>();
- cpu_graph_group_box.layout()->set_margins({ 6, 16, 6, 6 });
- cpu_graph_group_box.set_fixed_height(120);
- Vector<GraphWidget*> cpu_graphs;
- for (size_t i = 0; i < ProcessModel::the().cpus().size(); i++) {
- auto& cpu_graph = cpu_graph_group_box.add<GraphWidget>();
- cpu_graph.set_max(100);
- cpu_graph.set_background_color(Color::White);
- cpu_graph.set_value_format(0, {
- .line_color = Color::Blue,
- .background_color = Color::from_rgb(0xaaaaff),
- .text_formatter = [](int value) {
- return String::formatted("Total: {}%", value);
- },
- });
- cpu_graph.set_value_format(1, {
- .line_color = Color::Red,
- .background_color = Color::from_rgb(0xffaaaa),
- .text_formatter = [](int value) {
- return String::formatted("Kernel: {}%", value);
- },
- });
- cpu_graphs.append(&cpu_graph);
- }
- ProcessModel::the().on_cpu_info_change = [cpu_graphs](const NonnullOwnPtrVector<ProcessModel::CpuInfo>& cpus) {
- for (size_t i = 0; i < cpus.size(); i++)
- cpu_graphs[i]->add_value({ (int)cpus[i].total_cpu_percent, (int)cpus[i].total_cpu_percent_kernel });
- };
-
- auto& memory_graph_group_box = self.add<GUI::GroupBox>("Memory usage");
- memory_graph_group_box.set_layout<GUI::VerticalBoxLayout>();
- memory_graph_group_box.layout()->set_margins({ 6, 16, 6, 6 });
- memory_graph_group_box.set_fixed_height(120);
- auto& memory_graph = memory_graph_group_box.add<GraphWidget>();
- memory_graph.set_background_color(Color::White);
- memory_graph.set_stack_values(true);
- memory_graph.set_value_format(0, {
- .line_color = Color::from_rgb(0x619910),
- .background_color = Color::from_rgb(0xbbffbb),
- .text_formatter = [&memory_graph](int value) {
- return String::formatted("Committed: {} KiB", value);
- },
- });
- memory_graph.set_value_format(1, {
- .line_color = Color::Blue,
- .background_color = Color::from_rgb(0xaaaaff),
- .text_formatter = [&memory_graph](int value) {
- return String::formatted("Allocated: {} KiB", value);
- },
- });
- memory_graph.set_value_format(2, {
- .line_color = Color::Red,
- .background_color = Color::from_rgb(0xffaaaa),
- .text_formatter = [&memory_graph](int value) {
- return String::formatted("Kernel heap: {} KiB", value);
- },
- });
-
- self.add<MemoryStatsWidget>(memory_graph);
- };
- return graphs_container;
-}
-
-NonnullRefPtr<GUI::Widget> build_processors_tab()
-{
- auto processors_widget = GUI::LazyWidget::construct();
-
- processors_widget->on_first_show = [](GUI::LazyWidget& self) {
- self.set_layout<GUI::VerticalBoxLayout>();
- self.layout()->set_margins({ 4, 4, 4, 4 });
-
- Vector<GUI::JsonArrayModel::FieldSpec> processors_field;
- processors_field.empend("processor", "Processor", Gfx::TextAlignment::CenterRight);
- processors_field.empend("cpuid", "CPUID", Gfx::TextAlignment::CenterLeft);
- processors_field.empend("brandstr", "Brand", Gfx::TextAlignment::CenterLeft);
- processors_field.empend("Features", Gfx::TextAlignment::CenterLeft, [](auto& object) {
- StringBuilder builder;
- auto features = object.get("features").as_array();
- for (auto& feature : features.values()) {
- builder.append(feature.to_string());
- builder.append(' ');
- }
- return GUI::Variant(builder.to_string());
- });
- processors_field.empend("family", "Family", Gfx::TextAlignment::CenterRight);
- processors_field.empend("model", "Model", Gfx::TextAlignment::CenterRight);
- processors_field.empend("stepping", "Stepping", Gfx::TextAlignment::CenterRight);
- processors_field.empend("type", "Type", Gfx::TextAlignment::CenterRight);
-
- auto& processors_table_view = self.add<GUI::TableView>();
- processors_table_view.set_model(GUI::JsonArrayModel::create("/proc/cpuinfo", move(processors_field)));
- processors_table_view.model()->update();
- };
-
- return processors_widget;
-}
diff --git a/Applications/Terminal/CMakeLists.txt b/Applications/Terminal/CMakeLists.txt
deleted file mode 100644
index 1fb969546e..0000000000
--- a/Applications/Terminal/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-compile_gml(TerminalSettingsWindow.gml TerminalSettingsWindowGML.h terminal_settings_window_gml)
-
-set(SOURCES
- TerminalSettingsWindowGML.h
- main.cpp
-)
-
-serenity_app(Terminal ICON app-terminal)
-target_link_libraries(Terminal LibGUI LibVT)
diff --git a/Applications/Terminal/TerminalSettingsWindow.gml b/Applications/Terminal/TerminalSettingsWindow.gml
deleted file mode 100644
index 07b8400c56..0000000000
--- a/Applications/Terminal/TerminalSettingsWindow.gml
+++ /dev/null
@@ -1,63 +0,0 @@
-@GUI::Widget {
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [4, 4, 4, 4]
- }
-
- @GUI::GroupBox {
- title: "Bell mode"
- shrink_to_fit: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [6, 16, 6, 6]
- }
-
- @GUI::RadioButton {
- name: "beep_bell_radio"
- text: "System beep"
- }
-
- @GUI::RadioButton {
- name: "visual_bell_radio"
- text: "Visual bell"
- }
-
- @GUI::RadioButton {
- name: "no_bell_radio"
- text: "No bell"
- }
- }
-
- @GUI::GroupBox {
- title: "Background opacity"
- shrink_to_fit: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [6, 16, 6, 6]
- }
-
- @GUI::OpacitySlider {
- name: "background_opacity_slider"
- min: 0
- max: 255
- orientation: "Horizontal"
- }
- }
-
- @GUI::GroupBox {
- title: "Scrollback size (lines)"
- shrink_to_fit: true
-
- layout: @GUI::VerticalBoxLayout {
- margins: [6, 16, 6, 6]
- }
-
- @GUI::SpinBox {
- name: "history_size_spinbox"
- min: 0
- max: 40960
- orientation: "Horizontal"
- }
- }
-}
diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp
deleted file mode 100644
index 9267b9465f..0000000000
--- a/Applications/Terminal/main.cpp
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 <AK/URL.h>
-#include <Applications/Terminal/TerminalSettingsWindowGML.h>
-#include <LibCore/ArgsParser.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/Event.h>
-#include <LibGUI/FontPicker.h>
-#include <LibGUI/GroupBox.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/OpacitySlider.h>
-#include <LibGUI/RadioButton.h>
-#include <LibGUI/SpinBox.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Palette.h>
-#include <LibVT/TerminalWidget.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <serenity.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-static void utmp_update(const char* tty, pid_t pid, bool create)
-{
- if (!tty)
- return;
- int utmpupdate_pid = fork();
- if (utmpupdate_pid < 0) {
- perror("fork");
- return;
- }
- if (utmpupdate_pid == 0) {
- // Be careful here! Because fork() only clones one thread it's
- // possible that we deadlock on anything involving a mutex,
- // including the heap! So resort to low-level APIs
- char pid_str[32];
- snprintf(pid_str, sizeof(pid_str), "%d", pid);
- execl("/bin/utmpupdate", "/bin/utmpupdate", "-f", "Terminal", "-p", pid_str, (create ? "-c" : "-d"), tty, nullptr);
- } else {
- wait_again:
- int status = 0;
- if (waitpid(utmpupdate_pid, &status, 0) < 0) {
- int err = errno;
- if (err == EINTR)
- goto wait_again;
- perror("waitpid");
- return;
- }
- if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
- dbgln("Terminal: utmpupdate exited with status {}", WEXITSTATUS(status));
- else if (WIFSIGNALED(status))
- dbgln("Terminal: utmpupdate exited due to unhandled signal {}", WTERMSIG(status));
- }
-}
-
-static pid_t run_command(int ptm_fd, String command)
-{
- pid_t pid = fork();
- if (pid < 0) {
- perror("fork");
- dbgln("run_command: could not fork to run '{}'", command);
- return pid;
- }
-
- if (pid == 0) {
- const char* tty_name = ptsname(ptm_fd);
- if (!tty_name) {
- perror("ptsname");
- exit(1);
- }
- close(ptm_fd);
- int pts_fd = open(tty_name, O_RDWR);
- if (pts_fd < 0) {
- perror("open");
- exit(1);
- }
-
- if (setsid() < 0) {
- perror("setsid");
- }
-
- close(0);
- close(1);
- close(2);
-
- int rc = dup2(pts_fd, 0);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = dup2(pts_fd, 1);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = dup2(pts_fd, 2);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = close(pts_fd);
- if (rc < 0) {
- perror("close");
- exit(1);
- }
- rc = ioctl(0, TIOCSCTTY);
- if (rc < 0) {
- perror("ioctl(TIOCSCTTY)");
- exit(1);
- }
-
- String shell = "/bin/Shell";
- auto* pw = getpwuid(getuid());
- if (pw && pw->pw_shell) {
- shell = pw->pw_shell;
- }
- endpwent();
-
- const char* args[4] = { shell.characters(), nullptr, nullptr, nullptr };
- if (!command.is_empty()) {
- args[1] = "-c";
- args[2] = command.characters();
- }
- const char* envs[] = { "PROMPT=\\X\\u@\\h:\\w\\a\\e[33;1m\\h\\e[0m \\e[34;1m\\w\\e[0m \\p ", "TERM=xterm", "PAGER=more", "PATH=/bin:/usr/bin:/usr/local/bin", nullptr };
- rc = execve(shell.characters(), const_cast<char**>(args), const_cast<char**>(envs));
- if (rc < 0) {
- perror("execve");
- exit(1);
- }
- ASSERT_NOT_REACHED();
- }
-
- return pid;
-}
-
-static RefPtr<GUI::Window> create_settings_window(TerminalWidget& terminal)
-{
- auto window = GUI::Window::construct(terminal.window());
- window->set_title("Terminal settings");
- window->set_minimizable(false);
- window->set_resizable(false);
- window->resize(200, 210);
- window->set_modal(true);
-
- auto& settings = window->set_main_widget<GUI::Widget>();
- settings.load_from_gml(terminal_settings_window_gml);
-
- auto& beep_bell_radio = *settings.find_descendant_of_type_named<GUI::RadioButton>("beep_bell_radio");
- auto& visual_bell_radio = *settings.find_descendant_of_type_named<GUI::RadioButton>("visual_bell_radio");
- auto& no_bell_radio = *settings.find_descendant_of_type_named<GUI::RadioButton>("no_bell_radio");
-
- switch (terminal.bell_mode()) {
- case TerminalWidget::BellMode::Visible:
- visual_bell_radio.set_checked(true);
- break;
- case TerminalWidget::BellMode::AudibleBeep:
- beep_bell_radio.set_checked(true);
- break;
- case TerminalWidget::BellMode::Disabled:
- no_bell_radio.set_checked(true);
- break;
- }
-
- beep_bell_radio.on_checked = [&terminal](bool) {
- terminal.set_bell_mode(TerminalWidget::BellMode::AudibleBeep);
- };
- visual_bell_radio.on_checked = [&terminal](bool) {
- terminal.set_bell_mode(TerminalWidget::BellMode::Visible);
- };
- no_bell_radio.on_checked = [&terminal](bool) {
- terminal.set_bell_mode(TerminalWidget::BellMode::Disabled);
- };
-
- auto& slider = *settings.find_descendant_of_type_named<GUI::OpacitySlider>("background_opacity_slider");
- slider.on_change = [&terminal](int value) {
- terminal.set_opacity(value);
- };
- slider.set_value(terminal.opacity());
-
- auto& history_size_spinbox = *settings.find_descendant_of_type_named<GUI::SpinBox>("history_size_spinbox");
- history_size_spinbox.set_value(terminal.max_history_size());
- history_size_spinbox.on_change = [&terminal](int value) {
- terminal.set_max_history_size(value);
- };
-
- return window;
-}
-
-static RefPtr<GUI::Window> create_find_window(TerminalWidget& terminal)
-{
- auto window = GUI::Window::construct();
- window->set_title("Find in Terminal");
- window->set_resizable(false);
- window->resize(300, 90);
- window->set_modal(true);
-
- auto& search = window->set_main_widget<GUI::Widget>();
- search.set_fill_with_background_color(true);
- search.set_background_role(ColorRole::Button);
- search.set_layout<GUI::VerticalBoxLayout>();
- search.layout()->set_margins({ 4, 4, 4, 4 });
-
- auto& find = search.add<GUI::Widget>();
- find.set_layout<GUI::HorizontalBoxLayout>();
- find.layout()->set_margins({ 4, 4, 4, 4 });
- find.set_fixed_height(30);
-
- auto& find_textbox = find.add<GUI::TextBox>();
- find_textbox.set_fixed_width(230);
- find_textbox.set_focus(true);
- if (terminal.has_selection()) {
- String selected_text = terminal.selected_text();
- selected_text.replace("\n", " ", true);
- find_textbox.set_text(selected_text);
- }
- auto& find_backwards = find.add<GUI::Button>();
- find_backwards.set_fixed_width(25);
- find_backwards.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png"));
- auto& find_forwards = find.add<GUI::Button>();
- find_forwards.set_fixed_width(25);
- find_forwards.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png"));
-
- find_textbox.on_return_pressed = [&]() {
- find_backwards.click();
- };
-
- auto& match_case = search.add<GUI::CheckBox>("Case sensitive");
- auto& wrap_around = search.add<GUI::CheckBox>("Wrap around");
-
- find_backwards.on_click = [&](auto) {
- auto needle = find_textbox.text();
- if (needle.is_empty()) {
- return;
- }
-
- auto found_range = terminal.find_previous(needle, terminal.normalized_selection().start(), match_case.is_checked(), wrap_around.is_checked());
-
- if (found_range.is_valid()) {
- terminal.scroll_to_row(found_range.start().row());
- terminal.set_selection(found_range);
- }
- };
- find_forwards.on_click = [&](auto) {
- auto needle = find_textbox.text();
- if (needle.is_empty()) {
- return;
- }
-
- auto found_range = terminal.find_next(needle, terminal.normalized_selection().end(), match_case.is_checked(), wrap_around.is_checked());
-
- if (found_range.is_valid()) {
- terminal.scroll_to_row(found_range.start().row());
- terminal.set_selection(found_range);
- }
- };
-
- return window;
-}
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio tty rpath accept cpath wpath shared_buffer proc exec unix fattr sigaction", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_flags = SA_NOCLDWAIT;
- act.sa_handler = SIG_IGN;
- int rc = sigaction(SIGCHLD, &act, nullptr);
- if (rc < 0) {
- perror("sigaction");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio tty rpath accept cpath wpath shared_buffer proc exec unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* command_to_execute = nullptr;
-
- Core::ArgsParser args_parser;
- args_parser.add_option(command_to_execute, "Execute this command inside the terminal", nullptr, 'e', "command");
-
- args_parser.parse(argc, argv);
-
- int ptm_fd = posix_openpt(O_RDWR | O_CLOEXEC);
- if (ptm_fd < 0) {
- perror("posix_openpt");
- return 1;
- }
- if (grantpt(ptm_fd) < 0) {
- perror("grantpt");
- return 1;
- }
- if (unlockpt(ptm_fd) < 0) {
- perror("unlockpt");
- return 1;
- }
-
- RefPtr<Core::ConfigFile> config = Core::ConfigFile::get_for_app("Terminal");
-
- pid_t shell_pid = 0;
-
- if (command_to_execute)
- shell_pid = run_command(ptm_fd, command_to_execute);
- else
- shell_pid = run_command(ptm_fd, config->read_entry("Startup", "Command", ""));
-
- auto* pts_name = ptsname(ptm_fd);
- utmp_update(pts_name, shell_pid, true);
-
- auto app_icon = GUI::Icon::default_icon("app-terminal");
-
- auto window = GUI::Window::construct();
- window->set_title("Terminal");
- window->set_background_color(Color::Black);
- window->set_double_buffering_enabled(false);
-
- auto& terminal = window->set_main_widget<TerminalWidget>(ptm_fd, true, config);
- terminal.on_command_exit = [&] {
- app->quit(0);
- };
- terminal.on_title_change = [&](auto& title) {
- window->set_title(title);
- };
- terminal.apply_size_increments_to_window(*window);
- window->show();
- window->set_icon(app_icon.bitmap_for_size(16));
-
- auto bell = config->read_entry("Window", "Bell", "Visible");
- if (bell == "AudibleBeep") {
- terminal.set_bell_mode(TerminalWidget::BellMode::AudibleBeep);
- } else if (bell == "Disabled") {
- terminal.set_bell_mode(TerminalWidget::BellMode::Disabled);
- } else {
- terminal.set_bell_mode(TerminalWidget::BellMode::Visible);
- }
-
- RefPtr<GUI::Window> settings_window;
- RefPtr<GUI::Window> find_window;
-
- auto new_opacity = config->read_num_entry("Window", "Opacity", 255);
- terminal.set_opacity(new_opacity);
- window->set_has_alpha_channel(new_opacity < 255);
-
- auto new_scrollback_size = config->read_num_entry("Terminal", "MaxHistorySize", terminal.max_history_size());
- terminal.set_max_history_size(new_scrollback_size);
-
- auto open_settings_action = GUI::Action::create("Settings...", Gfx::Bitmap::load_from_file("/res/icons/16x16/gear.png"),
- [&](const GUI::Action&) {
- if (!settings_window) {
- settings_window = create_settings_window(terminal);
- settings_window->on_close_request = [&] {
- settings_window->remove_from_parent();
- settings_window = nullptr;
- return GUI::Window::CloseRequestDecision::Close;
- };
- }
- if (!settings_window->is_visible()) {
- settings_window->center_within(*window);
- settings_window->show();
- }
- settings_window->move_to_front();
- });
-
- terminal.context_menu().add_separator();
- auto pick_font_action = GUI::Action::create("Terminal font...", Gfx::Bitmap::load_from_file("/res/icons/16x16/app-font-editor.png"),
- [&](auto&) {
- auto picker = GUI::FontPicker::construct(window, &terminal.font(), true);
- if (picker->exec() == GUI::Dialog::ExecOK) {
- terminal.set_font_and_resize_to_fit(*picker->font());
- window->resize(terminal.size());
- config->write_entry("Text", "Font", picker->font()->qualified_name());
- config->sync();
- }
- });
-
- terminal.context_menu().add_action(pick_font_action);
-
- terminal.context_menu().add_separator();
- terminal.context_menu().add_action(open_settings_action);
-
- auto menubar = GUI::MenuBar::construct();
-
- auto& app_menu = menubar->add_menu("Terminal");
- app_menu.add_action(GUI::Action::create("Open new terminal", { Mod_Ctrl | Mod_Shift, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/app-terminal.png"), [&](auto&) {
- pid_t child;
- const char* argv[] = { "Terminal", nullptr };
- if ((errno = posix_spawn(&child, "/bin/Terminal", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child) < 0)
- perror("disown");
- }
- }));
-
- app_menu.add_action(open_settings_action);
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([](auto&) {
- dbgln("Terminal: Quit menu activated!");
- GUI::Application::the()->quit();
- }));
-
- auto& edit_menu = menubar->add_menu("Edit");
- edit_menu.add_action(terminal.copy_action());
- edit_menu.add_action(terminal.paste_action());
- edit_menu.add_separator();
- edit_menu.add_action(GUI::Action::create("Find...", { Mod_Ctrl | Mod_Shift, Key_F }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"),
- [&](auto&) {
- if (!find_window) {
- find_window = create_find_window(terminal);
- find_window->on_close_request = [&] {
- find_window = nullptr;
- return GUI::Window::CloseRequestDecision::Close;
- };
- }
- find_window->show();
- find_window->move_to_front();
- }));
-
- auto& view_menu = menubar->add_menu("View");
- view_menu.add_action(terminal.clear_including_history_action());
- view_menu.add_separator();
- view_menu.add_action(pick_font_action);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_help_action([](auto&) {
- Desktop::Launcher::open(URL::create_with_file_protocol("/usr/share/man/man1/Terminal.md"), "/bin/Help");
- }));
- help_menu.add_action(GUI::CommonActions::make_about_action("Terminal", app_icon, window));
-
- app->set_menubar(move(menubar));
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin/Terminal", "x") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/bin/utmpupdate", "x") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/etc/FileIconProvider.ini", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp/portal/launch", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(config->file_name().characters(), "rwc")) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- config->sync();
- int result = app->exec();
- dbgln("Exiting terminal, updating utmp");
- utmp_update(pts_name, 0, false);
- return result;
-}
diff --git a/Applications/TextEditor/CMakeLists.txt b/Applications/TextEditor/CMakeLists.txt
deleted file mode 100644
index 07eccd212e..0000000000
--- a/Applications/TextEditor/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-compile_gml(TextEditorWindow.gml TextEditorWindowGML.h text_editor_window_gml)
-
-set(SOURCES
- main.cpp
- TextEditorWidget.cpp
- TextEditorWindowGML.h
-)
-
-serenity_app(TextEditor ICON app-text-editor)
-target_link_libraries(TextEditor LibWeb LibMarkdown LibGUI LibShell LibRegex LibDesktop)
diff --git a/Applications/TextEditor/TextEditorWidget.cpp b/Applications/TextEditor/TextEditorWidget.cpp
deleted file mode 100644
index 982bcc282c..0000000000
--- a/Applications/TextEditor/TextEditorWidget.cpp
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TextEditorWidget.h"
-#include <AK/JsonObject.h>
-#include <AK/JsonValue.h>
-#include <AK/Optional.h>
-#include <AK/StringBuilder.h>
-#include <AK/URL.h>
-#include <Applications/TextEditor/TextEditorWindowGML.h>
-#include <LibCore/File.h>
-#include <LibCore/MimeData.h>
-#include <LibDesktop/Launcher.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CppSyntaxHighlighter.h>
-#include <LibGUI/FilePicker.h>
-#include <LibGUI/FontPicker.h>
-#include <LibGUI/GMLSyntaxHighlighter.h>
-#include <LibGUI/INISyntaxHighlighter.h>
-#include <LibGUI/JSSyntaxHighlighter.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/MenuBar.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/RegularEditingEngine.h>
-#include <LibGUI/ShellSyntaxHighlighter.h>
-#include <LibGUI/Splitter.h>
-#include <LibGUI/StatusBar.h>
-#include <LibGUI/TextBox.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/ToolBar.h>
-#include <LibGUI/ToolBarContainer.h>
-#include <LibGUI/VimEditingEngine.h>
-#include <LibGfx/Font.h>
-#include <LibMarkdown/Document.h>
-#include <LibWeb/OutOfProcessWebView.h>
-#include <string.h>
-
-TextEditorWidget::TextEditorWidget()
-{
- load_from_gml(text_editor_window_gml);
-
- auto& toolbar = *find_descendant_of_type_named<GUI::ToolBar>("toolbar");
-
- m_editor = *find_descendant_of_type_named<GUI::TextEditor>("editor");
- m_editor->set_ruler_visible(true);
- m_editor->set_automatic_indentation_enabled(true);
- m_editor->set_line_wrapping_enabled(true);
- m_editor->set_editing_engine(make<GUI::RegularEditingEngine>());
-
- m_editor->on_change = [this] {
- update_preview();
-
- // Do not mark as dirty on the first change (When document is first opened.)
- if (m_document_opening) {
- m_document_opening = false;
- return;
- }
-
- bool was_dirty = m_document_dirty;
- m_document_dirty = true;
- if (!was_dirty)
- update_title();
- };
-
- m_page_view = *find_descendant_of_type_named<Web::OutOfProcessWebView>("webview");
- m_page_view->on_link_hover = [this](auto& url) {
- if (url.is_valid())
- m_statusbar->set_text(url.to_string());
- else
- update_statusbar_cursor_position();
- };
- m_page_view->on_link_click = [&](auto& url, auto&, unsigned) {
- if (!Desktop::Launcher::open(url)) {
- GUI::MessageBox::show(
- window(),
- String::formatted("The link to '{}' could not be opened.", url),
- "Failed to open link",
- GUI::MessageBox::Type::Error);
- }
- };
-
- m_find_replace_widget = *find_descendant_of_type_named<GUI::Widget>("find_replace_widget");
-
- m_find_widget = *find_descendant_of_type_named<GUI::Widget>("find_widget");
-
- m_replace_widget = *find_descendant_of_type_named<GUI::Widget>("replace_widget");
-
- m_find_textbox = m_find_widget->add<GUI::TextBox>();
- m_replace_textbox = m_replace_widget->add<GUI::TextBox>();
-
- m_find_next_action = GUI::Action::create("Find next", { Mod_Ctrl, Key_G }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find-next.png"), [&](auto&) {
- auto needle = m_find_textbox->text();
- if (needle.is_empty()) {
- dbgln("find_next(\"\")");
- return;
- }
-
- if (m_find_use_regex)
- m_editor->document().update_regex_matches(needle);
-
- auto found_range = m_editor->document().find_next(needle, m_editor->normalized_selection().end(), GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex);
- dbgln("find_next('{}') returned {}", needle, found_range);
- if (found_range.is_valid()) {
- m_editor->set_selection(found_range);
- } else {
- GUI::MessageBox::show(window(),
- String::formatted("Not found: \"{}\"", needle),
- "Not found",
- GUI::MessageBox::Type::Information);
- }
- });
-
- m_find_regex_action = GUI::Action::create("Find regex", { Mod_Ctrl | Mod_Shift, Key_R }, [&](auto&) {
- m_find_regex_button->set_checked(!m_find_regex_button->is_checked());
- m_find_use_regex = m_find_regex_button->is_checked();
- });
-
- m_find_previous_action = GUI::Action::create("Find previous", { Mod_Ctrl | Mod_Shift, Key_G }, [&](auto&) {
- auto needle = m_find_textbox->text();
- if (needle.is_empty()) {
- dbgln("find_prev(\"\")");
- return;
- }
-
- auto selection_start = m_editor->normalized_selection().start();
- if (!selection_start.is_valid())
- selection_start = m_editor->normalized_selection().end();
-
- if (m_find_use_regex)
- m_editor->document().update_regex_matches(needle);
-
- auto found_range = m_editor->document().find_previous(needle, selection_start, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex);
-
- dbgln("find_prev(\"{}\") returned {}", needle, found_range);
- if (found_range.is_valid()) {
- m_editor->set_selection(found_range);
- } else {
- GUI::MessageBox::show(window(),
- String::formatted("Not found: \"{}\"", needle),
- "Not found",
- GUI::MessageBox::Type::Information);
- }
- });
-
- m_replace_next_action = GUI::Action::create("Replace next", { Mod_Ctrl, Key_F1 }, [&](auto&) {
- auto needle = m_find_textbox->text();
- auto substitute = m_replace_textbox->text();
-
- if (needle.is_empty())
- return;
-
- auto selection_start = m_editor->normalized_selection().start();
- if (!selection_start.is_valid())
- selection_start = m_editor->normalized_selection().start();
-
- if (m_find_use_regex)
- m_editor->document().update_regex_matches(needle);
-
- auto found_range = m_editor->document().find_next(needle, selection_start, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex);
-
- if (found_range.is_valid()) {
- m_editor->set_selection(found_range);
- m_editor->insert_at_cursor_or_replace_selection(substitute);
- } else {
- GUI::MessageBox::show(window(),
- String::formatted("Not found: \"{}\"", needle),
- "Not found",
- GUI::MessageBox::Type::Information);
- }
- });
-
- m_replace_previous_action = GUI::Action::create("Replace previous", { Mod_Ctrl | Mod_Shift, Key_F1 }, [&](auto&) {
- auto needle = m_find_textbox->text();
- auto substitute = m_replace_textbox->text();
- if (needle.is_empty())
- return;
-
- auto selection_start = m_editor->normalized_selection().start();
- if (!selection_start.is_valid())
- selection_start = m_editor->normalized_selection().start();
-
- if (m_find_use_regex)
- m_editor->document().update_regex_matches(needle);
-
- auto found_range = m_editor->document().find_previous(needle, selection_start);
-
- if (found_range.is_valid()) {
- m_editor->set_selection(found_range);
- m_editor->insert_at_cursor_or_replace_selection(substitute);
- } else {
- GUI::MessageBox::show(window(),
- String::formatted("Not found: \"{}\"", needle),
- "Not found",
- GUI::MessageBox::Type::Information);
- }
- });
-
- m_replace_all_action = GUI::Action::create("Replace all", { Mod_Ctrl, Key_F2 }, [&](auto&) {
- auto needle = m_find_textbox->text();
- auto substitute = m_replace_textbox->text();
- if (needle.is_empty())
- return;
- if (m_find_use_regex)
- m_editor->document().update_regex_matches(needle);
-
- auto found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex);
- while (found_range.is_valid()) {
- m_editor->set_selection(found_range);
- m_editor->insert_at_cursor_or_replace_selection(substitute);
- found_range = m_editor->document().find_next(needle, {}, GUI::TextDocument::SearchShouldWrap::Yes, m_find_use_regex);
- }
- });
-
- m_find_previous_button = *find_descendant_of_type_named<GUI::Button>("find_previous_button");
- m_find_previous_button->set_action(*m_find_previous_action);
-
- m_find_next_button = *find_descendant_of_type_named<GUI::Button>("find_next_button");
- m_find_next_button->set_action(*m_find_next_action);
-
- m_find_textbox->on_return_pressed = [this] {
- m_find_next_button->click();
- };
-
- m_find_regex_button = m_find_widget->add<GUI::Button>(".*");
- m_find_regex_button->set_fixed_width(20);
- m_find_regex_button->set_action(*m_find_regex_action);
-
- m_find_textbox->on_escape_pressed = [this] {
- m_find_replace_widget->set_visible(false);
- m_editor->set_focus(true);
- };
-
- m_replace_previous_button = *find_descendant_of_type_named<GUI::Button>("replace_previous_button");
- m_replace_previous_button->set_action(*m_replace_previous_action);
-
- m_replace_next_button = *find_descendant_of_type_named<GUI::Button>("replace_next_button");
- m_replace_next_button->set_action(*m_replace_next_action);
-
- m_replace_all_button = *find_descendant_of_type_named<GUI::Button>("replace_all_button");
- m_replace_all_button->set_action(*m_replace_all_action);
-
- m_replace_textbox->on_return_pressed = [this] {
- m_replace_next_button->click();
- };
-
- m_replace_textbox->on_escape_pressed = [this] {
- m_find_replace_widget->set_visible(false);
- m_editor->set_focus(true);
- };
-
- m_vim_emulation_setting_action = GUI::Action::create_checkable("Vim emulation", { Mod_Ctrl | Mod_Shift | Mod_Alt, Key_V }, [&](auto& action) {
- if (action.is_checked())
- m_editor->set_editing_engine(make<GUI::VimEditingEngine>());
- else
- m_editor->set_editing_engine(make<GUI::RegularEditingEngine>());
- });
- m_vim_emulation_setting_action->set_checked(false);
-
- m_find_replace_action = GUI::Action::create("Find/Replace...", { Mod_Ctrl, Key_F }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"), [this](auto&) {
- m_find_replace_widget->set_visible(true);
- m_find_widget->set_visible(true);
- m_replace_widget->set_visible(true);
- m_find_textbox->set_focus(true);
-
- if (m_editor->has_selection()) {
- auto selected_text = m_editor->document().text_in_range(m_editor->normalized_selection());
- m_find_textbox->set_text(selected_text);
- }
- m_find_textbox->select_all();
- });
-
- m_editor->add_custom_context_menu_action(*m_find_replace_action);
- m_editor->add_custom_context_menu_action(*m_find_next_action);
- m_editor->add_custom_context_menu_action(*m_find_previous_action);
-
- m_statusbar = *find_descendant_of_type_named<GUI::StatusBar>("statusbar");
-
- m_editor->on_cursor_change = [this] { update_statusbar_cursor_position(); };
-
- m_new_action = GUI::Action::create("New", { Mod_Ctrl, Key_N }, Gfx::Bitmap::load_from_file("/res/icons/16x16/new.png"), [this](const GUI::Action&) {
- if (m_document_dirty) {
- auto save_document_first_result = GUI::MessageBox::show(window(), "Save changes to current document first?", "Warning", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNoCancel);
- if (save_document_first_result == GUI::Dialog::ExecResult::ExecYes)
- m_save_action->activate();
- if (save_document_first_result == GUI::Dialog::ExecResult::ExecCancel)
- return;
- }
-
- m_document_dirty = false;
- m_editor->set_text(StringView());
- set_path(LexicalPath());
- update_title();
- });
-
- m_open_action = GUI::CommonActions::make_open_action([this](auto&) {
- Optional<String> open_path = GUI::FilePicker::get_open_filepath(window());
-
- if (!open_path.has_value())
- return;
-
- if (m_document_dirty) {
- auto save_document_first_result = GUI::MessageBox::show(window(), "Save changes to current document first?", "Warning", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNoCancel);
- if (save_document_first_result == GUI::Dialog::ExecResult::ExecYes)
- m_save_action->activate();
- if (save_document_first_result == GUI::Dialog::ExecResult::ExecCancel)
- return;
- }
-
- open_sesame(open_path.value());
- });
-
- m_save_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
- Optional<String> save_path = GUI::FilePicker::get_save_filepath(window(), m_name.is_null() ? "Untitled" : m_name, m_extension.is_null() ? "txt" : m_extension);
- if (!save_path.has_value())
- return;
-
- if (!m_editor->write_to_file(save_path.value())) {
- GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_document_dirty = false;
- set_path(LexicalPath(save_path.value()));
- dbgln("Wrote document to {}", save_path.value());
- });
-
- m_save_action = GUI::CommonActions::make_save_action([&](auto&) {
- if (!m_path.is_empty()) {
- if (!m_editor->write_to_file(m_path)) {
- GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error);
- } else {
- m_document_dirty = false;
- update_title();
- }
- return;
- }
-
- m_save_as_action->activate();
- });
-
- m_line_wrapping_setting_action = GUI::Action::create_checkable("Line wrapping", [&](auto& action) {
- m_editor->set_line_wrapping_enabled(action.is_checked());
- });
- m_line_wrapping_setting_action->set_checked(m_editor->is_line_wrapping_enabled());
-
- auto menubar = GUI::MenuBar::construct();
- auto& app_menu = menubar->add_menu("Text Editor");
- app_menu.add_action(*m_new_action);
- app_menu.add_action(*m_open_action);
- app_menu.add_action(*m_save_action);
- app_menu.add_action(*m_save_as_action);
- app_menu.add_separator();
- app_menu.add_action(GUI::CommonActions::make_quit_action([this](auto&) {
- if (!request_close())
- return;
- GUI::Application::the()->quit();
- }));
-
- auto& edit_menu = menubar->add_menu("Edit");
- edit_menu.add_action(m_editor->undo_action());
- edit_menu.add_action(m_editor->redo_action());
- edit_menu.add_separator();
- edit_menu.add_action(m_editor->cut_action());
- edit_menu.add_action(m_editor->copy_action());
- edit_menu.add_action(m_editor->paste_action());
- edit_menu.add_action(m_editor->delete_action());
- edit_menu.add_separator();
- edit_menu.add_action(*m_vim_emulation_setting_action);
- edit_menu.add_separator();
- edit_menu.add_action(*m_find_replace_action);
- edit_menu.add_action(*m_find_next_action);
- edit_menu.add_action(*m_find_regex_action);
- edit_menu.add_action(*m_find_previous_action);
- edit_menu.add_action(*m_replace_next_action);
- edit_menu.add_action(*m_replace_previous_action);
- edit_menu.add_action(*m_replace_all_action);
-
- m_no_preview_action = GUI::Action::create_checkable(
- "No preview", [this](auto&) {
- set_preview_mode(PreviewMode::None);
- });
-
- m_markdown_preview_action = GUI::Action::create_checkable(
- "Markdown preview", [this](auto&) {
- set_preview_mode(PreviewMode::Markdown);
- },
- this);
-
- m_html_preview_action = GUI::Action::create_checkable(
- "HTML preview", [this](auto&) {
- set_preview_mode(PreviewMode::HTML);
- },
- this);
-
- m_preview_actions.add_action(*m_no_preview_action);
- m_preview_actions.add_action(*m_markdown_preview_action);
- m_preview_actions.add_action(*m_html_preview_action);
- m_preview_actions.set_exclusive(true);
-
- auto& view_menu = menubar->add_menu("View");
- view_menu.add_action(GUI::Action::create("Editor font...", Gfx::Bitmap::load_from_file("/res/icons/16x16/app-font-editor.png"),
- [&](auto&) {
- auto picker = GUI::FontPicker::construct(window(), &m_editor->font(), true);
- if (picker->exec() == GUI::Dialog::ExecOK) {
- dbgln("setting font {}", picker->font()->qualified_name());
- m_editor->set_font(picker->font());
- }
- }));
-
- view_menu.add_separator();
- view_menu.add_action(*m_line_wrapping_setting_action);
- view_menu.add_separator();
- view_menu.add_action(*m_no_preview_action);
- view_menu.add_action(*m_markdown_preview_action);
- view_menu.add_action(*m_html_preview_action);
- view_menu.add_separator();
-
- syntax_actions.set_exclusive(true);
-
- auto& syntax_menu = view_menu.add_submenu("Syntax");
- m_plain_text_highlight = GUI::Action::create_checkable("Plain text", [&](auto&) {
- m_editor->set_syntax_highlighter({});
- m_editor->update();
- });
- m_plain_text_highlight->set_checked(true);
- syntax_actions.add_action(*m_plain_text_highlight);
- syntax_menu.add_action(*m_plain_text_highlight);
-
- m_cpp_highlight = GUI::Action::create_checkable("C++", [&](auto&) {
- m_editor->set_syntax_highlighter(make<GUI::CppSyntaxHighlighter>());
- m_editor->update();
- });
- syntax_actions.add_action(*m_cpp_highlight);
- syntax_menu.add_action(*m_cpp_highlight);
-
- m_js_highlight = GUI::Action::create_checkable("JavaScript", [&](auto&) {
- m_editor->set_syntax_highlighter(make<GUI::JSSyntaxHighlighter>());
- m_editor->update();
- });
- syntax_actions.add_action(*m_js_highlight);
- syntax_menu.add_action(*m_js_highlight);
-
- m_gml_highlight = GUI::Action::create_checkable("GML", [&](auto&) {
- m_editor->set_syntax_highlighter(make<GUI::GMLSyntaxHighlighter>());
- m_editor->update();
- });
- syntax_actions.add_action(*m_gml_highlight);
- syntax_menu.add_action(*m_gml_highlight);
-
- m_ini_highlight = GUI::Action::create_checkable("INI File", [&](auto&) {
- m_editor->set_syntax_highlighter(make<GUI::IniSyntaxHighlighter>());
- m_editor->update();
- });
- syntax_actions.add_action(*m_ini_highlight);
- syntax_menu.add_action(*m_ini_highlight);
-
- m_shell_highlight = GUI::Action::create_checkable("Shell File", [&](auto&) {
- m_editor->set_syntax_highlighter(make<GUI::ShellSyntaxHighlighter>());
- m_editor->update();
- });
- syntax_actions.add_action(*m_shell_highlight);
- syntax_menu.add_action(*m_shell_highlight);
-
- auto& help_menu = menubar->add_menu("Help");
- help_menu.add_action(GUI::CommonActions::make_about_action("Text Editor", GUI::Icon::default_icon("app-text-editor"), window()));
-
- GUI::Application::the()->set_menubar(move(menubar));
-
- toolbar.add_action(*m_new_action);
- toolbar.add_action(*m_open_action);
- toolbar.add_action(*m_save_action);
-
- toolbar.add_separator();
-
- toolbar.add_action(m_editor->cut_action());
- toolbar.add_action(m_editor->copy_action());
- toolbar.add_action(m_editor->paste_action());
- toolbar.add_action(m_editor->delete_action());
-
- toolbar.add_separator();
-
- toolbar.add_action(m_editor->undo_action());
- toolbar.add_action(m_editor->redo_action());
-}
-
-TextEditorWidget::~TextEditorWidget()
-{
-}
-
-void TextEditorWidget::set_path(const LexicalPath& lexical_path)
-{
- m_path = lexical_path.string();
- m_name = lexical_path.title();
- m_extension = lexical_path.extension();
-
- if (m_extension == "c" || m_extension == "cc" || m_extension == "cxx" || m_extension == "cpp" || m_extension == "h") {
- m_cpp_highlight->activate();
- } else if (m_extension == "js" || m_extension == "json") {
- m_js_highlight->activate();
- } else if (m_extension == "gml") {
- m_gml_highlight->activate();
- } else if (m_extension == "ini") {
- m_ini_highlight->activate();
- } else {
- m_plain_text_highlight->activate();
- }
-
- if (m_auto_detect_preview_mode) {
- if (m_extension == "md")
- set_preview_mode(PreviewMode::Markdown);
- else if (m_extension == "html")
- set_preview_mode(PreviewMode::HTML);
- else
- set_preview_mode(PreviewMode::None);
- }
-
- update_title();
-}
-
-void TextEditorWidget::update_title()
-{
- StringBuilder builder;
- if (m_path.is_empty())
- builder.append("Untitled");
- else
- builder.append(m_path);
- if (m_document_dirty)
- builder.append(" (*)");
- builder.append(" - Text Editor");
- window()->set_title(builder.to_string());
-}
-
-void TextEditorWidget::open_sesame(const String& path)
-{
- auto file = Core::File::construct(path);
- if (!file->open(Core::IODevice::ReadOnly) && file->error() != ENOENT) {
- GUI::MessageBox::show(window(), String::formatted("Opening \"{}\" failed: {}", path, strerror(errno)), "Error", GUI::MessageBox::Type::Error);
- return;
- }
-
- m_editor->set_text(file->read_all());
- m_document_dirty = false;
- m_document_opening = true;
-
- set_path(LexicalPath(path));
-
- m_editor->set_focus(true);
-}
-
-bool TextEditorWidget::request_close()
-{
- if (!m_document_dirty)
- return true;
- auto result = GUI::MessageBox::show(window(), "The document has been modified. Would you like to save?", "Unsaved changes", GUI::MessageBox::Type::Warning, GUI::MessageBox::InputType::YesNoCancel);
-
- if (result == GUI::MessageBox::ExecYes) {
- m_save_action->activate();
- return true;
- }
-
- if (result == GUI::MessageBox::ExecNo)
- return true;
-
- return false;
-}
-
-void TextEditorWidget::drop_event(GUI::DropEvent& event)
-{
- event.accept();
- window()->move_to_front();
-
- if (event.mime_data().has_urls()) {
- auto urls = event.mime_data().urls();
- if (urls.is_empty())
- return;
- if (urls.size() > 1) {
- GUI::MessageBox::show(window(), "TextEditor can only open one file at a time!", "One at a time please!", GUI::MessageBox::Type::Error);
- return;
- }
- open_sesame(urls.first().path());
- }
-}
-
-void TextEditorWidget::set_preview_mode(PreviewMode mode)
-{
- if (m_preview_mode == mode)
- return;
- m_preview_mode = mode;
-
- if (m_preview_mode == PreviewMode::HTML) {
- m_html_preview_action->set_checked(true);
- m_page_view->set_visible(true);
- update_html_preview();
- } else if (m_preview_mode == PreviewMode::Markdown) {
- m_markdown_preview_action->set_checked(true);
- m_page_view->set_visible(true);
- update_markdown_preview();
- } else {
- m_no_preview_action->set_checked(true);
- m_page_view->set_visible(false);
- }
-}
-
-void TextEditorWidget::update_preview()
-{
- switch (m_preview_mode) {
- case PreviewMode::Markdown:
- update_markdown_preview();
- break;
- case PreviewMode::HTML:
- update_html_preview();
- break;
- default:
- break;
- }
-}
-
-void TextEditorWidget::update_markdown_preview()
-{
- auto document = Markdown::Document::parse(m_editor->text());
- if (document) {
- auto html = document->render_to_html();
- auto current_scroll_pos = m_page_view->visible_content_rect();
- m_page_view->load_html(html, URL::create_with_file_protocol(m_path));
- m_page_view->scroll_into_view(current_scroll_pos, true, true);
- }
-}
-
-void TextEditorWidget::update_html_preview()
-{
- auto current_scroll_pos = m_page_view->visible_content_rect();
- m_page_view->load_html(m_editor->text(), URL::create_with_file_protocol(m_path));
- m_page_view->scroll_into_view(current_scroll_pos, true, true);
-}
-
-void TextEditorWidget::update_statusbar_cursor_position()
-{
- StringBuilder builder;
- builder.appendff("Line: {}, Column: {}", m_editor->cursor().line() + 1, m_editor->cursor().column());
- m_statusbar->set_text(builder.to_string());
-}
diff --git a/Applications/TextEditor/TextEditorWidget.h b/Applications/TextEditor/TextEditorWidget.h
deleted file mode 100644
index 763087b9e4..0000000000
--- a/Applications/TextEditor/TextEditorWidget.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/LexicalPath.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-#include <LibWeb/Forward.h>
-
-class TextEditorWidget final : public GUI::Widget {
- C_OBJECT(TextEditorWidget)
-public:
- virtual ~TextEditorWidget() override;
- void open_sesame(const String& path);
- bool request_close();
-
- GUI::TextEditor& editor() { return *m_editor; }
-
- enum class PreviewMode {
- None,
- Markdown,
- HTML,
- };
-
- void set_preview_mode(PreviewMode);
- void set_auto_detect_preview_mode(bool value) { m_auto_detect_preview_mode = value; }
-
- void update_title();
-
-private:
- TextEditorWidget();
- void set_path(const LexicalPath& file);
- void update_preview();
- void update_markdown_preview();
- void update_html_preview();
- void update_statusbar_cursor_position();
-
- virtual void drop_event(GUI::DropEvent&) override;
-
- RefPtr<GUI::TextEditor> m_editor;
- String m_path;
- String m_name;
- String m_extension;
- RefPtr<GUI::Action> m_new_action;
- RefPtr<GUI::Action> m_open_action;
- RefPtr<GUI::Action> m_save_action;
- RefPtr<GUI::Action> m_save_as_action;
- RefPtr<GUI::Action> m_find_replace_action;
- RefPtr<GUI::Action> m_line_wrapping_setting_action;
- RefPtr<GUI::Action> m_vim_emulation_setting_action;
-
- RefPtr<GUI::Action> m_find_next_action;
- RefPtr<GUI::Action> m_find_regex_action;
- RefPtr<GUI::Action> m_find_previous_action;
- RefPtr<GUI::Action> m_replace_next_action;
- RefPtr<GUI::Action> m_replace_previous_action;
- RefPtr<GUI::Action> m_replace_all_action;
-
- GUI::ActionGroup m_preview_actions;
- RefPtr<GUI::Action> m_no_preview_action;
- RefPtr<GUI::Action> m_markdown_preview_action;
- RefPtr<GUI::Action> m_html_preview_action;
-
- RefPtr<GUI::StatusBar> m_statusbar;
-
- RefPtr<GUI::TextBox> m_find_textbox;
- RefPtr<GUI::TextBox> m_replace_textbox;
- RefPtr<GUI::Button> m_find_previous_button;
- RefPtr<GUI::Button> m_find_next_button;
- RefPtr<GUI::Button> m_find_regex_button;
- RefPtr<GUI::Button> m_replace_previous_button;
- RefPtr<GUI::Button> m_replace_next_button;
- RefPtr<GUI::Button> m_replace_all_button;
- RefPtr<GUI::Widget> m_find_replace_widget;
- RefPtr<GUI::Widget> m_find_widget;
- RefPtr<GUI::Widget> m_replace_widget;
-
- GUI::ActionGroup syntax_actions;
- RefPtr<GUI::Action> m_plain_text_highlight;
- RefPtr<GUI::Action> m_cpp_highlight;
- RefPtr<GUI::Action> m_js_highlight;
- RefPtr<GUI::Action> m_gml_highlight;
- RefPtr<GUI::Action> m_ini_highlight;
- RefPtr<GUI::Action> m_shell_highlight;
-
- RefPtr<Web::OutOfProcessWebView> m_page_view;
-
- bool m_document_dirty { false };
- bool m_document_opening { false };
- bool m_auto_detect_preview_mode { false };
- bool m_find_use_regex { false };
-
- PreviewMode m_preview_mode { PreviewMode::None };
-};
diff --git a/Applications/TextEditor/TextEditorWindow.gml b/Applications/TextEditor/TextEditorWindow.gml
deleted file mode 100644
index 433d01abff..0000000000
--- a/Applications/TextEditor/TextEditorWindow.gml
+++ /dev/null
@@ -1,88 +0,0 @@
-@GUI::Widget {
- name: "main"
- fill_with_background_color: true
-
- layout: @GUI::VerticalBoxLayout {
- spacing: 2
- }
-
- @GUI::ToolBarContainer {
- @GUI::ToolBar {
- name: "toolbar"
- }
- }
-
- @GUI::HorizontalSplitter {
- @GUI::TextEditor {
- name: "editor"
- }
-
- @Web::OutOfProcessWebView {
- name: "webview"
- visible: false
- }
- }
-
- @GUI::Widget {
- name: "find_replace_widget"
- visible: false
- fill_with_background_color: true
- fixed_height: 48
-
- layout: @GUI::VerticalBoxLayout {
- margins: [2, 2, 2, 4]
- }
-
- @GUI::Widget {
- name: "find_widget"
- fill_with_background_color: true
- fixed_height: 22
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Button {
- name: "find_previous_button"
- text: "Find previous"
- fixed_width: 150
- }
-
- @GUI::Button {
- name: "find_next_button"
- text: "Find next"
- fixed_width: 150
- }
- }
-
- @GUI::Widget {
- name: "replace_widget"
- fill_with_background_color: true
- fixed_height: 22
-
- layout: @GUI::HorizontalBoxLayout {
- }
-
- @GUI::Button {
- name: "replace_previous_button"
- text: "Replace previous"
- fixed_width: 100
- }
-
- @GUI::Button {
- name: "replace_next_button"
- text: "Replace next"
- fixed_width: 100
- }
-
- @GUI::Button {
- name: "replace_all_button"
- text: "Replace all"
- fixed_width: 100
- }
- }
- }
-
- @GUI::StatusBar {
- name: "statusbar"
- }
-}
diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp
deleted file mode 100644
index 8e9c8fdfb8..0000000000
--- a/Applications/TextEditor/main.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TextEditorWidget.h"
-#include <LibCore/ArgsParser.h>
-#include <LibGfx/Bitmap.h>
-#include <stdio.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- const char* preview_mode = "auto";
- const char* file_to_edit = nullptr;
- Core::ArgsParser parser;
- parser.add_option(preview_mode, "Preview mode, one of 'none', 'html', 'markdown', 'auto'", "preview-mode", '\0', "mode");
- parser.add_positional_argument(file_to_edit, "File to edit", "file", Core::ArgsParser::Required::No);
-
- parser.parse(argc, argv);
-
- StringView preview_mode_view = preview_mode;
-
- auto app_icon = GUI::Icon::default_icon("app-text-editor");
-
- auto window = GUI::Window::construct();
- window->resize(640, 400);
-
- auto& text_widget = window->set_main_widget<TextEditorWidget>();
-
- text_widget.editor().set_focus(true);
-
- window->on_close_request = [&]() -> GUI::Window::CloseRequestDecision {
- if (text_widget.request_close())
- return GUI::Window::CloseRequestDecision::Close;
- return GUI::Window::CloseRequestDecision::StayOpen;
- };
-
- if (preview_mode_view == "auto") {
- text_widget.set_auto_detect_preview_mode(true);
- } else if (preview_mode_view == "markdown") {
- text_widget.set_preview_mode(TextEditorWidget::PreviewMode::Markdown);
- } else if (preview_mode_view == "html") {
- text_widget.set_preview_mode(TextEditorWidget::PreviewMode::HTML);
- } else if (preview_mode_view == "none") {
- text_widget.set_preview_mode(TextEditorWidget::PreviewMode::None);
- } else {
- warnln("Invalid mode '{}'", preview_mode);
- return 1;
- }
-
- if (file_to_edit)
- text_widget.open_sesame(file_to_edit);
- else
- text_widget.update_title();
-
- window->show();
- window->set_icon(app_icon.bitmap_for_size(16));
-
- return app->exec();
-}
diff --git a/Applications/ThemeEditor/CMakeLists.txt b/Applications/ThemeEditor/CMakeLists.txt
deleted file mode 100644
index 94ca0e1f3e..0000000000
--- a/Applications/ThemeEditor/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- PreviewWidget.cpp
- main.cpp
-)
-
-serenity_app(ThemeEditor ICON app-theme-editor)
-target_link_libraries(ThemeEditor LibGUI)
diff --git a/Applications/ThemeEditor/PreviewWidget.cpp b/Applications/ThemeEditor/PreviewWidget.cpp
deleted file mode 100644
index a57da75936..0000000000
--- a/Applications/ThemeEditor/PreviewWidget.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PreviewWidget.h"
-#include <AK/StringView.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/CheckBox.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/RadioButton.h>
-#include <LibGUI/StatusBar.h>
-#include <LibGUI/TextEditor.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/WindowTheme.h>
-
-namespace ThemeEditor {
-
-class MiniWidgetGallery final : public GUI::Widget {
- C_OBJECT(MiniWidgetGallery);
-
-public:
- void set_preview_palette(const Gfx::Palette& palette)
- {
- set_palette(palette);
- Function<void(GUI::Widget&)> recurse = [&](GUI::Widget& parent_widget) {
- parent_widget.for_each_child_widget([&](auto& widget) {
- widget.set_palette(palette);
- recurse(widget);
- return IterationDecision::Continue;
- });
- };
- recurse(*this);
- }
-
-private:
- MiniWidgetGallery()
- {
- set_fill_with_background_color(true);
- m_button = add<GUI::Button>();
- m_button->set_text("Button");
- m_checkbox = add<GUI::CheckBox>();
- m_checkbox->set_text("Check box");
- m_radio = add<GUI::RadioButton>();
- m_radio->set_text("Radio button");
- m_statusbar = add<GUI::StatusBar>();
- m_statusbar->set_text("Status bar");
- m_editor = add<GUI::TextEditor>();
- m_editor->set_text("Text editor\nwith multiple\nlines.");
- }
-
- virtual void resize_event(GUI::ResizeEvent&) override
- {
- m_editor->set_relative_rect(10, 70, 200, 140);
- m_button->set_relative_rect(10, 10, 200, 20);
- m_checkbox->set_relative_rect(10, 30, 200, 20);
- m_radio->set_relative_rect(10, 50, 200, 20);
- m_statusbar->set_relative_rect(0, height() - 16, width(), 16);
- }
-
- RefPtr<GUI::TextEditor> m_editor;
- RefPtr<GUI::Button> m_button;
- RefPtr<GUI::CheckBox> m_checkbox;
- RefPtr<GUI::RadioButton> m_radio;
- RefPtr<GUI::StatusBar> m_statusbar;
-};
-
-PreviewWidget::PreviewWidget(const Gfx::Palette& preview_palette)
- : m_preview_palette(preview_palette)
-{
- m_active_window_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window.png");
- m_inactive_window_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window.png");
-
- m_close_bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png");
- m_maximize_bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png");
- m_minimize_bitmap = Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png");
-
- m_gallery = add<MiniWidgetGallery>();
- set_greedy_for_hits(true);
-}
-
-PreviewWidget::~PreviewWidget()
-{
-}
-
-void PreviewWidget::set_preview_palette(const Gfx::Palette& palette)
-{
- m_preview_palette = palette;
- m_gallery->set_preview_palette(palette);
- update();
-}
-
-void PreviewWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
- GUI::Painter painter(*this);
-
- painter.add_clip_rect(event.rect());
- painter.add_clip_rect(frame_inner_rect());
-
- painter.fill_rect(frame_inner_rect(), m_preview_palette.desktop_background());
-
- struct Button {
- Gfx::IntRect rect;
- RefPtr<Gfx::Bitmap> bitmap;
- };
-
- auto paint_window = [&](auto& title, const Gfx::IntRect& rect, auto state, const Gfx::Bitmap& icon) {
- int window_button_width = m_preview_palette.window_title_button_width();
- int window_button_height = m_preview_palette.window_title_button_height();
- auto title_bar_text_rect = Gfx::WindowTheme::current().title_bar_text_rect(Gfx::WindowTheme::WindowType::Normal, rect, m_preview_palette);
- int pos = title_bar_text_rect.right() + 1;
-
- Vector<Button> buttons;
- buttons.append(Button { {}, m_close_bitmap });
- buttons.append(Button { {}, m_maximize_bitmap });
- buttons.append(Button { {}, m_minimize_bitmap });
-
- for (auto& button : buttons) {
- pos -= window_button_width;
- Gfx::IntRect rect { pos, 0, window_button_width, window_button_height };
- rect.center_vertically_within(title_bar_text_rect);
- button.rect = rect;
- }
-
- auto frame_rect = Gfx::WindowTheme::current().frame_rect_for_window(Gfx::WindowTheme::WindowType::Normal, rect, m_preview_palette);
- Gfx::PainterStateSaver saver(painter);
- painter.translate(frame_rect.location());
- Gfx::WindowTheme::current().paint_normal_frame(painter, state, rect, title, icon, m_preview_palette, buttons.last().rect);
-
- for (auto& button : buttons) {
- Gfx::StylePainter::paint_button(painter, button.rect, m_preview_palette, Gfx::ButtonStyle::Normal, false);
- auto bitmap_rect = button.bitmap->rect();
- bitmap_rect.center_within(button.rect);
- painter.blit(bitmap_rect.location(), *button.bitmap, button.bitmap->rect());
- }
- };
-
- Gfx::IntRect active_rect { 0, 0, 320, 240 };
- active_rect.center_within(frame_inner_rect());
- Gfx::IntRect inactive_rect = active_rect.translated(-20, -20);
-
- paint_window("Inactive window", inactive_rect, Gfx::WindowTheme::WindowState::Inactive, *m_active_window_icon);
- paint_window("Active window", active_rect, Gfx::WindowTheme::WindowState::Active, *m_inactive_window_icon);
-}
-
-void PreviewWidget::resize_event(GUI::ResizeEvent&)
-{
- Gfx::IntRect gallery_rect { 0, 0, 320, 240 };
- gallery_rect.center_within(rect());
- m_gallery->set_relative_rect(gallery_rect);
-}
-
-}
diff --git a/Applications/ThemeEditor/PreviewWidget.h b/Applications/ThemeEditor/PreviewWidget.h
deleted file mode 100644
index 41ef25e0a8..0000000000
--- a/Applications/ThemeEditor/PreviewWidget.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-#include <LibGfx/Palette.h>
-
-namespace ThemeEditor {
-
-class MiniWidgetGallery;
-
-class PreviewWidget final : public GUI::Frame {
- C_OBJECT(PreviewWidget);
-
-public:
- virtual ~PreviewWidget() override;
-
- const Gfx::Palette& preview_palette() const { return m_preview_palette; }
- void set_preview_palette(const Gfx::Palette&);
-
-private:
- explicit PreviewWidget(const Gfx::Palette&);
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- Gfx::Palette m_preview_palette;
-
- RefPtr<Gfx::Bitmap> m_active_window_icon;
- RefPtr<Gfx::Bitmap> m_inactive_window_icon;
-
- RefPtr<MiniWidgetGallery> m_gallery;
-
- RefPtr<Gfx::Bitmap> m_close_bitmap;
- RefPtr<Gfx::Bitmap> m_maximize_bitmap;
- RefPtr<Gfx::Bitmap> m_minimize_bitmap;
-};
-
-}
diff --git a/Applications/ThemeEditor/main.cpp b/Applications/ThemeEditor/main.cpp
deleted file mode 100644
index d4a5936770..0000000000
--- a/Applications/ThemeEditor/main.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "PreviewWidget.h"
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/ColorInput.h>
-#include <LibGUI/ComboBox.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Model.h>
-#include <LibGUI/Window.h>
-
-class ColorRoleModel final : public GUI::Model {
-public:
- virtual int row_count(const GUI::ModelIndex&) const { return m_color_roles.size(); }
- virtual int column_count(const GUI::ModelIndex&) const { return 1; }
- virtual GUI::Variant data(const GUI::ModelIndex& index, GUI::ModelRole role = GUI::ModelRole::Display) const
- {
- if (role == GUI::ModelRole::Display)
- return Gfx::to_string(m_color_roles[(size_t)index.row()]);
- return {};
- }
- virtual void update() { did_update(); }
-
- explicit ColorRoleModel(const Vector<Gfx::ColorRole>& color_roles)
- : m_color_roles(color_roles)
- {
- }
-
- Gfx::ColorRole color_role(const GUI::ModelIndex& index) const
- {
- return m_color_roles[index.row()];
- }
-
- Gfx::ColorRole color_role(size_t index) const
- {
- return m_color_roles[index];
- }
-
-private:
- const Vector<Gfx::ColorRole>& m_color_roles;
-};
-
-int main(int argc, char** argv)
-{
-
- if (pledge("stdio thread rpath accept cpath wpath shared_buffer unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio thread rpath accept shared_buffer", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto app_icon = GUI::Icon::default_icon("app-theme-editor");
-
- Gfx::Palette preview_palette = app->palette();
-
- auto window = GUI::Window::construct();
- auto& main_widget = window->set_main_widget<GUI::Widget>();
- main_widget.set_fill_with_background_color(true);
- main_widget.set_layout<GUI::VerticalBoxLayout>();
-
- auto& preview_widget = main_widget.add<ThemeEditor::PreviewWidget>(app->palette());
- preview_widget.set_fixed_size(480, 360);
-
- auto& horizontal_container = main_widget.add<GUI::Widget>();
- horizontal_container.set_layout<GUI::HorizontalBoxLayout>();
- horizontal_container.set_fixed_size(480, 20);
-
- auto& combo_box = horizontal_container.add<GUI::ComboBox>();
- auto& color_input = horizontal_container.add<GUI::ColorInput>();
-
- Vector<Gfx::ColorRole> color_roles;
-#define __ENUMERATE_COLOR_ROLE(role) color_roles.append(Gfx::ColorRole::role);
- ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE)
-#undef __ENUMERATE_COLOR_ROLE
-
- combo_box.set_only_allow_values_from_model(true);
- combo_box.set_model(adopt(*new ColorRoleModel(color_roles)));
- combo_box.on_change = [&](auto&, auto& index) {
- auto role = static_cast<const ColorRoleModel*>(index.model())->color_role(index);
- color_input.set_color(preview_palette.color(role));
- };
-
- combo_box.set_selected_index((size_t)Gfx::ColorRole::Window - 1);
-
- color_input.on_change = [&] {
- auto role = static_cast<const ColorRoleModel*>(combo_box.model())->color_role(combo_box.selected_index());
- preview_palette.set_color(role, color_input.color());
- preview_widget.set_preview_palette(preview_palette);
- };
-
- window->resize(480, 500);
- window->show();
- window->set_title("Theme Editor");
- window->set_icon(app_icon.bitmap_for_size(16));
- return app->exec();
-}
diff --git a/Applications/Welcome/BackgroundWidget.cpp b/Applications/Welcome/BackgroundWidget.cpp
deleted file mode 100644
index c64f2fc93b..0000000000
--- a/Applications/Welcome/BackgroundWidget.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BackgroundWidget.h"
-#include <LibGUI/Painter.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Palette.h>
-
-BackgroundWidget::BackgroundWidget()
-{
-}
-
-BackgroundWidget::~BackgroundWidget()
-{
-}
-
-void BackgroundWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.fill_rect_with_gradient(event.rect(), Color::from_rgb(0xccdddd), Color::from_rgb(0xdcdcde));
-}
-
-void BackgroundWidget::resize_event(GUI::ResizeEvent& event)
-{
- GUI::Widget::resize_event(event);
-}
diff --git a/Applications/Welcome/BackgroundWidget.h b/Applications/Welcome/BackgroundWidget.h
deleted file mode 100644
index fea3871edc..0000000000
--- a/Applications/Welcome/BackgroundWidget.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Frame.h>
-
-class BackgroundWidget : public GUI::Frame {
- C_OBJECT(BackgroundWidget)
-public:
- virtual ~BackgroundWidget() override;
-
-private:
- BackgroundWidget();
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
-};
diff --git a/Applications/Welcome/CMakeLists.txt b/Applications/Welcome/CMakeLists.txt
deleted file mode 100644
index e9d1ef3380..0000000000
--- a/Applications/Welcome/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-set(SOURCES
- BackgroundWidget.cpp
- main.cpp
- TextWidget.cpp
- UnuncheckableButton.cpp
-)
-
-serenity_bin(Welcome)
-target_link_libraries(Welcome LibGUI)
diff --git a/Applications/Welcome/TextWidget.cpp b/Applications/Welcome/TextWidget.cpp
deleted file mode 100644
index 263d4514f8..0000000000
--- a/Applications/Welcome/TextWidget.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "TextWidget.h"
-#include <AK/Optional.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/Vector.h>
-#include <LibGUI/Painter.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Palette.h>
-
-TextWidget::TextWidget(const StringView& text)
- : m_text(text)
-{
- set_frame_thickness(0);
- set_frame_shadow(Gfx::FrameShadow::Plain);
- set_frame_shape(Gfx::FrameShape::NoFrame);
-}
-
-TextWidget::~TextWidget()
-{
-}
-
-void TextWidget::set_text(const StringView& text)
-{
- if (text == m_text)
- return;
- m_text = text;
- wrap_and_set_height();
- update();
-}
-
-void TextWidget::paint_event(GUI::PaintEvent& event)
-{
- GUI::Frame::paint_event(event);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- int indent = 0;
- if (frame_thickness() > 0)
- indent = font().glyph_width('x') / 2;
-
- for (size_t i = 0; i < m_lines.size(); i++) {
- auto& line = m_lines[i];
-
- auto text_rect = frame_inner_rect();
- text_rect.move_by(indent, i * m_line_height);
- if (!line.is_empty())
- text_rect.set_width(text_rect.width() - indent * 2);
-
- if (is_enabled()) {
- painter.draw_text(text_rect, line, m_text_alignment, palette().color(foreground_role()), Gfx::TextElision::None);
- } else {
- painter.draw_text(text_rect.translated(1, 1), line, font(), text_alignment(), Color::White, Gfx::TextElision::Right);
- painter.draw_text(text_rect, line, font(), text_alignment(), Color::from_rgb(0x808080), Gfx::TextElision::Right);
- }
- }
-}
-
-void TextWidget::resize_event(GUI::ResizeEvent& event)
-{
- wrap_and_set_height();
- GUI::Widget::resize_event(event);
-}
-
-void TextWidget::wrap_and_set_height()
-{
- Vector<String> words;
- Optional<size_t> start;
- for (size_t i = 0; i < m_text.length(); i++) {
- auto ch = m_text[i];
-
- if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
- if (start.has_value())
- words.append(m_text.substring(start.value(), i - start.value()));
- start.clear();
- } else if (!start.has_value()) {
- start = i;
- }
- }
- if (start.has_value())
- words.append(m_text.substring(start.value(), m_text.length() - start.value()));
-
- auto rect = frame_inner_rect();
- if (frame_thickness() > 0)
- rect.set_width(rect.width() - font().glyph_width('x'));
-
- StringBuilder builder;
- Vector<String> lines;
- int line_width = 0;
- for (auto& word : words) {
- int word_width = font().width(word);
- if (line_width != 0)
- word_width += font().glyph_width('x');
-
- if (line_width + word_width > rect.width()) {
- lines.append(builder.to_string());
- builder.clear();
- line_width = 0;
- }
-
- if (line_width != 0)
- builder.append(' ');
- builder.append(word);
- line_width += word_width;
- }
- auto last_line = builder.to_string();
- if (!last_line.is_empty()) {
- lines.append(last_line);
- }
-
- m_lines = lines;
-
- set_fixed_height(m_lines.size() * m_line_height + frame_thickness() * 2);
-}
diff --git a/Applications/Welcome/TextWidget.h b/Applications/Welcome/TextWidget.h
deleted file mode 100644
index c4353096ff..0000000000
--- a/Applications/Welcome/TextWidget.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <LibGUI/Frame.h>
-#include <LibGfx/TextAlignment.h>
-
-class TextWidget : public GUI::Frame {
- C_OBJECT(TextWidget);
-
-public:
- virtual ~TextWidget() override;
-
- String text() const { return m_text; }
- void set_text(const StringView&);
-
- Gfx::TextAlignment text_alignment() const { return m_text_alignment; }
- void set_text_alignment(Gfx::TextAlignment text_alignment) { m_text_alignment = text_alignment; }
-
- bool should_wrap() const { return m_should_wrap; }
- void set_should_wrap(bool should_wrap) { m_should_wrap = should_wrap; }
-
- int line_height() const { return m_line_height; }
- void set_line_height(int line_height) { m_line_height = line_height; }
-
- void wrap_and_set_height();
-
-private:
- explicit TextWidget(const StringView& text = {});
-
- virtual void paint_event(GUI::PaintEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
-
- String m_text;
- Vector<String> m_lines;
- Gfx::TextAlignment m_text_alignment { Gfx::TextAlignment::Center };
- bool m_should_wrap { false };
- int m_line_height { 0 };
-};
diff --git a/Applications/Welcome/UnuncheckableButton.cpp b/Applications/Welcome/UnuncheckableButton.cpp
deleted file mode 100644
index 29194fff81..0000000000
--- a/Applications/Welcome/UnuncheckableButton.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "UnuncheckableButton.h"
-
-UnuncheckableButton::UnuncheckableButton()
-{
-}
-
-UnuncheckableButton::~UnuncheckableButton()
-{
-}
diff --git a/Applications/Welcome/UnuncheckableButton.h b/Applications/Welcome/UnuncheckableButton.h
deleted file mode 100644
index b91a41ef9c..0000000000
--- a/Applications/Welcome/UnuncheckableButton.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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.
- */
-
-#pragma once
-
-#include <LibGUI/Button.h>
-
-class UnuncheckableButton : public GUI::Button {
- C_OBJECT(UnuncheckableButton)
-public:
- virtual ~UnuncheckableButton() override;
-
- virtual bool is_uncheckable() const override { return false; }
-
-private:
- UnuncheckableButton();
-};
diff --git a/Applications/Welcome/main.cpp b/Applications/Welcome/main.cpp
deleted file mode 100644
index 101b35fd97..0000000000
--- a/Applications/Welcome/main.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 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 HOLDER 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 "BackgroundWidget.h"
-#include "TextWidget.h"
-#include "UnuncheckableButton.h"
-#include <AK/ByteBuffer.h>
-#include <AK/Optional.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/Vector.h>
-#include <LibCore/File.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/ImageWidget.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/MessageBox.h>
-#include <LibGUI/StackWidget.h>
-#include <LibGUI/Window.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <stdio.h>
-#include <unistd.h>
-
-struct ContentPage {
- String menu_name;
- String title;
- String icon = String::empty();
- Vector<String> content;
-};
-
-static Optional<Vector<ContentPage>> parse_welcome_file(const String& path)
-{
- auto file = Core::File::construct(path);
- if (!file->open(Core::IODevice::ReadOnly))
- return {};
-
- Vector<ContentPage> pages;
- StringBuilder current_output_line;
- bool started = false;
- ContentPage current;
- while (file->can_read_line()) {
- auto line = file->read_line();
- if (line.is_empty()) {
- if (!current_output_line.to_string().is_empty())
- current.content.append(current_output_line.to_string());
- current_output_line.clear();
- continue;
- }
- switch (line[0]) {
- case '*':
- dbgln("menu_item line:\t{}", line);
- if (started)
- pages.append(current);
- else
- started = true;
-
- current = {};
- current.menu_name = line.substring(2, line.length() - 2);
- break;
- case '$':
- dbgln("icon line: \t{}", line);
- current.icon = line.substring(2, line.length() - 2);
- break;
- case '>':
- dbgln("title line:\t{}", line);
- current.title = line.substring(2, line.length() - 2);
- break;
- case '#':
- dbgln("comment line:\t{}", line);
- break;
- default:
- dbgln("content line:\t", line);
- if (current_output_line.length() != 0)
- current_output_line.append(' ');
- current_output_line.append(line);
- break;
- }
- }
-
- if (started) {
- current.content.append(current_output_line.to_string());
- pages.append(current);
- }
-
- return pages;
-}
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer rpath unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
-
- if (pledge("stdio shared_buffer rpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- Optional<Vector<ContentPage>> _pages = parse_welcome_file("/res/welcome.txt");
- if (!_pages.has_value()) {
- GUI::MessageBox::show(nullptr, "Could not open Welcome file.", "Welcome", GUI::MessageBox::Type::Error);
- return 1;
- }
- auto pages = _pages.value();
-
- auto window = GUI::Window::construct();
- window->set_title("Welcome");
- window->resize(640, 360);
- window->center_on_screen();
-
- auto& background = window->set_main_widget<BackgroundWidget>();
- background.set_fill_with_background_color(false);
- background.set_layout<GUI::VerticalBoxLayout>();
- background.layout()->set_margins({ 16, 8, 16, 8 });
- background.layout()->set_spacing(8);
-
- //
- // header
- //
-
- auto& header = background.add<GUI::Label>();
- header.set_font(Gfx::Font::load_from_file("/res/fonts/PebbletonBold14.font"));
- header.set_text("Welcome to SerenityOS!");
- header.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- header.set_fixed_height(30);
-
- //
- // main section
- //
-
- auto& main_section = background.add<GUI::Widget>();
- main_section.set_layout<GUI::HorizontalBoxLayout>();
- main_section.layout()->set_margins({ 0, 0, 0, 0 });
- main_section.layout()->set_spacing(8);
-
- auto& menu = main_section.add<GUI::Widget>();
- menu.set_layout<GUI::VerticalBoxLayout>();
- menu.layout()->set_margins({ 0, 0, 0, 0 });
- menu.layout()->set_spacing(4);
- menu.set_fixed_width(100);
-
- auto& stack = main_section.add<GUI::StackWidget>();
-
- bool first = true;
- for (auto& page : pages) {
- auto& content = stack.add<GUI::Widget>();
- content.set_layout<GUI::VerticalBoxLayout>();
- content.layout()->set_margins({ 0, 0, 0, 0 });
- content.layout()->set_spacing(8);
-
- auto& title_box = content.add<GUI::Widget>();
- title_box.set_layout<GUI::HorizontalBoxLayout>();
- title_box.layout()->set_spacing(4);
- title_box.set_fixed_height(16);
-
- if (!page.icon.is_empty()) {
- auto& icon = title_box.add<GUI::ImageWidget>();
- icon.set_fixed_size(16, 16);
- icon.load_from_file(page.icon);
- }
-
- auto& content_title = title_box.add<GUI::Label>();
- content_title.set_font(Gfx::FontDatabase::default_bold_font());
- content_title.set_text(page.title);
- content_title.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- content_title.set_fixed_height(10);
-
- for (auto& paragraph : page.content) {
- auto& content_text = content.add<TextWidget>();
- content_text.set_font(Gfx::FontDatabase::default_font());
- content_text.set_text(paragraph);
- content_text.set_text_alignment(Gfx::TextAlignment::TopLeft);
- content_text.set_line_height(12);
- content_text.wrap_and_set_height();
- }
-
- auto& menu_option = menu.add<UnuncheckableButton>();
- menu_option.set_font(Gfx::FontDatabase::default_font());
- menu_option.set_text(page.menu_name);
- menu_option.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- menu_option.set_fixed_height(20);
- menu_option.set_checkable(true);
- menu_option.set_exclusive(true);
-
- if (first)
- menu_option.set_checked(true);
-
- menu_option.on_click = [content = &content, &stack](auto) {
- stack.set_active_widget(content);
- content->invalidate_layout();
- };
-
- first = false;
- }
-
- window->show();
- return app->exec();
-}