mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-04 13:59:46 +00:00
Merge branch 'main' into feature/png-metadata
This commit is contained in:
commit
74a89085d8
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -56,8 +56,13 @@ jobs:
|
||||
if [[ "${{ runner.os }}" == "Linux" ]] ; then
|
||||
export XVFB=xvfb-run
|
||||
fi
|
||||
if [[ "${{ github.base_ref }}" == "beta" ]] || [[ "${{ github.ref }}" == "refs/heads/beta" ]] ; then
|
||||
export TESTS_BRANCH=beta
|
||||
else
|
||||
export TESTS_BRANCH=main
|
||||
fi
|
||||
cd build
|
||||
export ASEPRITE=$PWD/bin/aseprite
|
||||
git clone --recursive https://github.com/aseprite/tests.git
|
||||
git clone --branch $TESTS_BRANCH --recursive https://github.com/aseprite/tests.git
|
||||
cd tests
|
||||
$XVFB bash run-tests.sh
|
||||
|
@ -79,8 +79,14 @@ option(ENABLE_UI "Compile UI (turn off to compile CLI-only version)" o
|
||||
option(FULLSCREEN_PLATFORM "Enable fullscreen by default" off)
|
||||
option(ENABLE_CLANG_TIDY "Enable static analysis" off)
|
||||
option(ENABLE_CCACHE "Use CCache to improve recompilation speed (optional)" on)
|
||||
option(ENABLE_SENTRY "Use Sentry SDK to report crashes" off)
|
||||
set(CUSTOM_WEBSITE_URL "" CACHE STRING "Enable custom local webserver to check updates")
|
||||
|
||||
if(ENABLE_SENTRY)
|
||||
set(SENTRY_DIR "" CACHE STRING "Sentry native location")
|
||||
set(SENTRY_DNS "" CACHE STRING "Sentry DNS URL")
|
||||
endif()
|
||||
|
||||
if(ENABLE_NEWS OR ENABLE_UPDATER)
|
||||
set(REQUIRE_CURL ON)
|
||||
else()
|
||||
|
@ -723,6 +723,9 @@
|
||||
<style id="workspace_tabs">
|
||||
<background color="workspace" />
|
||||
</style>
|
||||
<style id="workspace_check_box" extends="check_box" padding="4">
|
||||
<text color="workspace_text" align="left middle" x="14" />
|
||||
</style>
|
||||
<style id="tab">
|
||||
<background part="tab_normal" align="middle" />
|
||||
<background part="tab_active" align="middle" state="focus" />
|
||||
|
@ -731,11 +731,16 @@ Recover files from crashed sessions or
|
||||
closed sprite that were not saved in
|
||||
previous sessions.
|
||||
END
|
||||
share_crashdb = Share crash data with Aseprite developers
|
||||
share_crashdb_tooltip = <<<END
|
||||
Check to share crash data with Aseprite developers automatically.
|
||||
This will help to find new bugs and improve the general stability
|
||||
of Aseprite for all users.
|
||||
END
|
||||
recent_files = Recent files:
|
||||
recent_folders = Recent folders:
|
||||
news = News:
|
||||
checking_updates = Checking Updates...
|
||||
is_up_to_date = {0} is up to date
|
||||
new_version_available = New {0} v{1} available!
|
||||
|
||||
[import_sprite_sheet]
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2017 David Capello -->
|
||||
<gui>
|
||||
<vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true">
|
||||
@ -14,6 +14,8 @@
|
||||
</vbox>
|
||||
<boxfiller />
|
||||
<vbox border="4">
|
||||
<check id="share_crashdb" text="@.share_crashdb"
|
||||
tooltip="@.share_crashdb_tooltip" style="workspace_check_box" />
|
||||
<link id="check_update" text="" style="workspace_link" />
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -68,6 +68,9 @@
|
||||
text="@.color_bar_entries_separator"
|
||||
tooltip="@.color_bar_entries_separator"
|
||||
pref="color_bar.entries_separator" />
|
||||
<check id="share_crashdb"
|
||||
text="@home_view.share_crashdb"
|
||||
tooltip="@home_view.share_crashdb_tooltip" />
|
||||
|
||||
<separator horizontal="true" />
|
||||
<link id="locate_file" text="@.locate_file" />
|
||||
|
@ -951,6 +951,31 @@ possible. They may also add themselves to the list below.
|
||||
*/
|
||||
```
|
||||
|
||||
# [Sentry](https://sentry.io)
|
||||
|
||||
```
|
||||
Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
# [skia](https://skia.org)
|
||||
|
||||
```
|
||||
|
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 0d1ba15a6af387f4fb57889e59ffd3e8fab29eda
|
||||
Subproject commit f58ece8248e2ebf6124b28ec49044be913f57292
|
@ -221,7 +221,6 @@ if(ENABLE_UI)
|
||||
commands/cmd_duplicate_view.cpp
|
||||
commands/cmd_exit.cpp
|
||||
commands/cmd_eyedropper.cpp
|
||||
commands/cmd_fill_and_stroke.cpp
|
||||
commands/cmd_fit_screen.cpp
|
||||
commands/cmd_frame_properties.cpp
|
||||
commands/cmd_frame_tag_properties.cpp
|
||||
@ -402,6 +401,13 @@ if(ENABLE_UI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(send_crash_files)
|
||||
if(ENABLE_SENTRY)
|
||||
set(send_crash_files sentry_wrapper.cpp)
|
||||
else()
|
||||
set(send_crash_files send_crash.cpp)
|
||||
endif()
|
||||
|
||||
add_library(app-lib
|
||||
active_site_handler.cpp
|
||||
app.cpp
|
||||
@ -501,6 +507,7 @@ add_library(app-lib
|
||||
commands/cmd_color_quantization.cpp
|
||||
commands/cmd_crop.cpp
|
||||
commands/cmd_export_sprite_sheet.cpp
|
||||
commands/cmd_fill_and_stroke.cpp
|
||||
commands/cmd_flatten_layers.cpp
|
||||
commands/cmd_flip.cpp
|
||||
commands/cmd_import_sprite_sheet.cpp
|
||||
@ -575,7 +582,6 @@ add_library(app-lib
|
||||
res/resources_loader.cpp
|
||||
resource_finder.cpp
|
||||
restore_visible_layers.cpp
|
||||
send_crash.cpp
|
||||
shade.cpp
|
||||
site.cpp
|
||||
snap_to_grid.cpp
|
||||
@ -617,6 +623,7 @@ add_library(app-lib
|
||||
util/wrap_point.cpp
|
||||
xml_document.cpp
|
||||
xml_exception.cpp
|
||||
${send_crash_files}
|
||||
${ui_app_files}
|
||||
${app_platform_files}
|
||||
${data_recovery_files}
|
||||
@ -677,3 +684,12 @@ if(ENABLE_STEAM)
|
||||
add_definitions(-DENABLE_STEAM)
|
||||
target_link_libraries(app-lib steam-lib)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SENTRY)
|
||||
target_compile_definitions(app-lib PUBLIC
|
||||
-DENABLE_SENTRY
|
||||
-DSENTRY_BUILD_STATIC=1
|
||||
-DSENTRY_DNS="${SENTRY_DNS}")
|
||||
add_subdirectory(${SENTRY_DIR} sentry)
|
||||
target_link_libraries(app-lib sentry)
|
||||
endif()
|
||||
|
@ -418,8 +418,10 @@ void App::run()
|
||||
checkUpdate.launch();
|
||||
#endif
|
||||
|
||||
#if !ENABLE_SENTRY
|
||||
app::SendCrash sendCrash;
|
||||
sendCrash.search();
|
||||
#endif
|
||||
|
||||
// Keep the console alive the whole program execute (just in case
|
||||
// we've to print errors).
|
||||
|
@ -379,13 +379,13 @@ void AppBrushes::load(const std::string& filename)
|
||||
|
||||
// Pixel-perfect
|
||||
if (TiXmlElement* pixelPerfectElem = brushElem->FirstChildElement("pixelperfect")) {
|
||||
pixelPerfect = bool_attr_is_true(pixelPerfectElem, "value");
|
||||
pixelPerfect = bool_attr(pixelPerfectElem, "value", false);
|
||||
flags |= int(BrushSlot::Flags::PixelPerfect);
|
||||
}
|
||||
|
||||
// Image color (enabled by default for backward compatibility)
|
||||
if (!brushElem->Attribute("imagecolor") ||
|
||||
bool_attr_is_true(brushElem, "imagecolor"))
|
||||
bool_attr(brushElem, "imagecolor", false))
|
||||
flags |= int(BrushSlot::Flags::ImageColor);
|
||||
|
||||
if (flags != 0)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -21,6 +21,10 @@
|
||||
#include "base/version.h"
|
||||
#include "ver/info.h"
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
#include "app/sentry_wrapper.h"
|
||||
#endif
|
||||
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
|
||||
@ -113,6 +117,14 @@ CheckUpdateThreadLauncher::~CheckUpdateThreadLauncher()
|
||||
|
||||
void CheckUpdateThreadLauncher::launch()
|
||||
{
|
||||
if (m_uuid.empty())
|
||||
m_uuid = m_preferences.updater.uuid();
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
if (!m_uuid.empty())
|
||||
Sentry::setUserID(m_uuid);
|
||||
#endif
|
||||
|
||||
// In this case we are in the "wait days" period, so we don't check
|
||||
// for updates.
|
||||
if (!m_doCheck) {
|
||||
@ -120,9 +132,6 @@ void CheckUpdateThreadLauncher::launch()
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_uuid.empty())
|
||||
m_uuid = m_preferences.updater.uuid();
|
||||
|
||||
m_delegate->onCheckingUpdates();
|
||||
|
||||
m_bgJob.reset(new CheckUpdateBackgroundJob);
|
||||
@ -168,6 +177,11 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
|
||||
if (!m_response.getUuid().empty()) {
|
||||
m_uuid = m_response.getUuid();
|
||||
m_preferences.updater.uuid(m_uuid);
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
if (!m_uuid.empty())
|
||||
Sentry::setUserID(m_uuid);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set the date of the last "check for updates" and the "WaitDays" parameter.
|
||||
|
@ -364,9 +364,14 @@ void CanvasSizeCommand::onExecute(Context* context)
|
||||
|
||||
Preferences::instance().canvasSize.trimOutside(params.trimOutside());
|
||||
|
||||
bounds.enlarge(
|
||||
gfx::Border(params.left(), params.top(),
|
||||
params.right(), params.bottom()));
|
||||
if (params.bounds.isSet()) {
|
||||
bounds = params.bounds();
|
||||
}
|
||||
else {
|
||||
bounds.enlarge(
|
||||
gfx::Border(params.left(), params.top(),
|
||||
params.right(), params.bottom()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -51,10 +52,12 @@ bool FillCommand::onEnabled(Context* ctx)
|
||||
ContextFlags::ActiveLayerIsImage)) {
|
||||
return true;
|
||||
}
|
||||
#if ENABLE_UI
|
||||
else if (current_editor &&
|
||||
current_editor->isMovingPixels()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/tx.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/pref_widget.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
@ -42,6 +43,10 @@
|
||||
#include "render/render.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
#include "app/sentry_wrapper.h"
|
||||
#endif
|
||||
|
||||
#include "options.xml.h"
|
||||
|
||||
namespace app {
|
||||
@ -490,6 +495,13 @@ public:
|
||||
else
|
||||
locateCrashFolder()->setVisible(false);
|
||||
|
||||
// Share crashdb
|
||||
#if ENABLE_SENTRY
|
||||
shareCrashdb()->setSelected(Sentry::consentGiven());
|
||||
#else
|
||||
shareCrashdb()->setVisible(false);
|
||||
#endif
|
||||
|
||||
// Undo preferences
|
||||
limitUndo()->Click.connect([this]{ onLimitUndoCheck(); });
|
||||
limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0);
|
||||
@ -541,6 +553,15 @@ public:
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
// Share crashdb
|
||||
#if ENABLE_SENTRY
|
||||
if (shareCrashdb()->isSelected())
|
||||
Sentry::giveConsent();
|
||||
else
|
||||
Sentry::revokeConsent();
|
||||
App::instance()->mainWindow()->updateConsentCheckbox();
|
||||
#endif
|
||||
|
||||
// Update language
|
||||
Strings::instance()->setCurrentLanguage(
|
||||
language()->getItemText(language()->getSelectedItemIndex()));
|
||||
|
@ -19,6 +19,7 @@ FOR_EACH_COMMAND(CopyColors)
|
||||
FOR_EACH_COMMAND(CropSprite)
|
||||
FOR_EACH_COMMAND(Despeckle)
|
||||
FOR_EACH_COMMAND(ExportSpriteSheet)
|
||||
FOR_EACH_COMMAND(Fill)
|
||||
FOR_EACH_COMMAND(FlattenLayers)
|
||||
FOR_EACH_COMMAND(Flip)
|
||||
FOR_EACH_COMMAND(HueSaturation)
|
||||
@ -41,6 +42,7 @@ FOR_EACH_COMMAND(SaveFile)
|
||||
FOR_EACH_COMMAND(SaveFileAs)
|
||||
FOR_EACH_COMMAND(SaveFileCopyAs)
|
||||
FOR_EACH_COMMAND(SpriteSize)
|
||||
FOR_EACH_COMMAND(Stroke)
|
||||
FOR_EACH_COMMAND(Undo)
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
@ -67,7 +69,6 @@ FOR_EACH_COMMAND(DuplicateSprite)
|
||||
FOR_EACH_COMMAND(DuplicateView)
|
||||
FOR_EACH_COMMAND(Exit)
|
||||
FOR_EACH_COMMAND(Eyedropper)
|
||||
FOR_EACH_COMMAND(Fill)
|
||||
FOR_EACH_COMMAND(FitScreen)
|
||||
FOR_EACH_COMMAND(FrameProperties)
|
||||
FOR_EACH_COMMAND(FrameTagProperties)
|
||||
@ -151,7 +152,6 @@ FOR_EACH_COMMAND(ShowSlices)
|
||||
FOR_EACH_COMMAND(SliceProperties)
|
||||
FOR_EACH_COMMAND(SnapToGrid)
|
||||
FOR_EACH_COMMAND(SpriteProperties)
|
||||
FOR_EACH_COMMAND(Stroke)
|
||||
FOR_EACH_COMMAND(SwapCheckerboardColors)
|
||||
FOR_EACH_COMMAND(SwitchColors)
|
||||
FOR_EACH_COMMAND(SymmetryMode)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -16,6 +16,8 @@
|
||||
|
||||
namespace app {
|
||||
|
||||
#if !ENABLE_SENTRY
|
||||
|
||||
class SendCrash
|
||||
#ifdef ENABLE_UI
|
||||
: public INotificationDelegate
|
||||
@ -43,6 +45,8 @@ namespace app {
|
||||
std::string m_dumpFilename;
|
||||
};
|
||||
|
||||
#endif // !ENABLE_SENTRY
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif // APP_SEND_CRASH_H_INCLUDED
|
||||
|
113
src/app/sentry_wrapper.cpp
Normal file
113
src/app/sentry_wrapper.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/sentry_wrapper.h"
|
||||
|
||||
#include "app/resource_finder.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/string.h"
|
||||
#include "ver/info.h"
|
||||
|
||||
#include "sentry.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
// Directory where Sentry database is saved.
|
||||
std::string Sentry::m_dbdir;
|
||||
|
||||
void Sentry::init()
|
||||
{
|
||||
sentry_options_t* options = sentry_options_new();
|
||||
sentry_options_set_dsn(options, SENTRY_DNS);
|
||||
|
||||
std::string release = "aseprite@";
|
||||
release += get_app_version();
|
||||
sentry_options_set_release(options, release.c_str());
|
||||
|
||||
#if _DEBUG
|
||||
sentry_options_set_debug(options, 1);
|
||||
#endif
|
||||
|
||||
setupDirs(options);
|
||||
|
||||
// We require the user consent to upload files.
|
||||
sentry_options_set_require_user_consent(options, 1);
|
||||
|
||||
if (sentry_init(options) == 0)
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
Sentry::~Sentry()
|
||||
{
|
||||
if (m_init)
|
||||
sentry_close();
|
||||
}
|
||||
|
||||
// static
|
||||
void Sentry::setUserID(const std::string& uuid)
|
||||
{
|
||||
sentry_value_t user = sentry_value_new_object();
|
||||
sentry_value_set_by_key(user, "id", sentry_value_new_string(uuid.c_str()));
|
||||
sentry_set_user(user);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Sentry::requireConsent()
|
||||
{
|
||||
return (sentry_user_consent_get() != SENTRY_USER_CONSENT_GIVEN);
|
||||
}
|
||||
|
||||
// static
|
||||
bool Sentry::consentGiven()
|
||||
{
|
||||
return (sentry_user_consent_get() == SENTRY_USER_CONSENT_GIVEN);
|
||||
}
|
||||
|
||||
// static
|
||||
void Sentry::giveConsent()
|
||||
{
|
||||
sentry_user_consent_give();
|
||||
}
|
||||
|
||||
// static
|
||||
void Sentry::revokeConsent()
|
||||
{
|
||||
sentry_user_consent_revoke();
|
||||
}
|
||||
|
||||
// static
|
||||
bool Sentry::areThereCrashesToReport()
|
||||
{
|
||||
if (m_dbdir.empty())
|
||||
return false;
|
||||
|
||||
for (auto f : base::list_files(base::join_path(m_dbdir, "completed"))) {
|
||||
if (base::get_file_extension(f) == "dmp")
|
||||
return true; // At least one .dmp file in the completed/ directory
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sentry::setupDirs(sentry_options_t* options)
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir("crashdb");
|
||||
const std::string dir = rf.getFirstOrCreateDefault();
|
||||
|
||||
#if SENTRY_PLATFORM_WINDOWS
|
||||
sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str());
|
||||
#else
|
||||
sentry_options_set_database_path(options, dir.c_str());
|
||||
#endif
|
||||
|
||||
m_dbdir = dir;
|
||||
}
|
||||
|
||||
} // namespace app
|
45
src/app/sentry_wrapper.h
Normal file
45
src/app/sentry_wrapper.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_SENTRY_WRAPPER_H
|
||||
#define APP_SENTRY_WRAPPER_H
|
||||
|
||||
#if !ENABLE_SENTRY
|
||||
#error ENABLE_SENTRY must be defined
|
||||
#endif
|
||||
|
||||
#include "sentry.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
class Sentry {
|
||||
public:
|
||||
void init();
|
||||
~Sentry();
|
||||
|
||||
static void setUserID(const std::string& uuid);
|
||||
|
||||
static bool requireConsent();
|
||||
static bool consentGiven();
|
||||
static void giveConsent();
|
||||
static void revokeConsent();
|
||||
|
||||
// Returns true if there are some crash to report. Used to display
|
||||
// the "give consent" check box for first time.
|
||||
static bool areThereCrashesToReport();
|
||||
|
||||
private:
|
||||
void setupDirs(sentry_options_t* options);
|
||||
|
||||
bool m_init = false;
|
||||
static std::string m_dbdir;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif // APP_SENTRY_WRAPPER_H
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -38,6 +38,10 @@
|
||||
#include "app/ui/news_listbox.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
#include "app/sentry_wrapper.h"
|
||||
#endif
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
@ -66,6 +70,23 @@ HomeView::HomeView()
|
||||
#endif
|
||||
|
||||
checkUpdate()->setVisible(false);
|
||||
shareCrashdb()->setVisible(false);
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
// Show this option in home tab only when we require consent for the
|
||||
// first time and there is crash data available to report
|
||||
if (Sentry::requireConsent() &&
|
||||
Sentry::areThereCrashesToReport()) {
|
||||
shareCrashdb()->setVisible(true);
|
||||
shareCrashdb()->Click.connect(
|
||||
[this]{
|
||||
if (shareCrashdb()->isSelected())
|
||||
Sentry::giveConsent();
|
||||
else
|
||||
Sentry::revokeConsent();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
InitTheme.connect(
|
||||
[this]{
|
||||
@ -101,6 +122,21 @@ void HomeView::dataRecoverySessionsAreReady()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
void HomeView::updateConsentCheckbox()
|
||||
{
|
||||
if (Sentry::requireConsent()) {
|
||||
shareCrashdb()->setVisible(true);
|
||||
shareCrashdb()->setSelected(false);
|
||||
}
|
||||
else if (Sentry::consentGiven()) {
|
||||
shareCrashdb()->setVisible(false);
|
||||
shareCrashdb()->setSelected(true);
|
||||
}
|
||||
layout();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string HomeView::getTabText()
|
||||
{
|
||||
return Strings::home_view_title();
|
||||
@ -176,9 +212,7 @@ void HomeView::onCheckingUpdates()
|
||||
|
||||
void HomeView::onUpToDate()
|
||||
{
|
||||
checkUpdate()->setText(
|
||||
fmt::format(Strings::home_view_is_up_to_date(), get_app_name()));
|
||||
checkUpdate()->setVisible(true);
|
||||
checkUpdate()->setVisible(false);
|
||||
|
||||
layout();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -46,6 +46,10 @@ namespace app {
|
||||
// function is called.
|
||||
void dataRecoverySessionsAreReady();
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
void updateConsentCheckbox();
|
||||
#endif
|
||||
|
||||
// TabView implementation
|
||||
std::string getTabText() override;
|
||||
TabIcon getTabIcon() override;
|
||||
|
@ -418,7 +418,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* command_name = xmlKey->Attribute("command");
|
||||
const char* command_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
bool removed = bool_attr(xmlKey, "removed", false);
|
||||
|
||||
if (command_name) {
|
||||
Command* command = Commands::instance()->byId(command_name);
|
||||
@ -481,7 +481,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* tool_id = xmlKey->Attribute("tool");
|
||||
const char* tool_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
bool removed = bool_attr(xmlKey, "removed", false);
|
||||
|
||||
if (tool_id) {
|
||||
tools::Tool* tool = App::instance()->toolBox()->getToolById(tool_id);
|
||||
@ -509,7 +509,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* tool_id = xmlKey->Attribute("tool");
|
||||
const char* tool_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
bool removed = bool_attr(xmlKey, "removed", false);
|
||||
|
||||
if (tool_id) {
|
||||
tools::Tool* tool = App::instance()->toolBox()->getToolById(tool_id);
|
||||
@ -537,7 +537,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* action_id = xmlKey->Attribute("action");
|
||||
const char* action_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
bool removed = bool_attr(xmlKey, "removed", false);
|
||||
|
||||
if (action_id) {
|
||||
KeyAction action = base::convert_to<KeyAction, std::string>(action_id);
|
||||
@ -565,7 +565,7 @@ void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
|
||||
while (xmlKey) {
|
||||
const char* action_id = xmlKey->Attribute("action");
|
||||
const char* action_key = get_shortcut(xmlKey);
|
||||
bool removed = bool_attr_is_true(xmlKey, "removed");
|
||||
bool removed = bool_attr(xmlKey, "removed", false);
|
||||
|
||||
if (action_id) {
|
||||
WheelAction action = base::convert_to<WheelAction, std::string>(action_id);
|
||||
|
@ -223,6 +223,13 @@ CheckUpdateDelegate* MainWindow::getCheckUpdateDelegate()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
void MainWindow::updateConsentCheckbox()
|
||||
{
|
||||
getHomeView()->updateConsentCheckbox();
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::showNotification(INotificationDelegate* del)
|
||||
{
|
||||
m_notifications->addLink(del);
|
||||
|
@ -66,6 +66,9 @@ namespace app {
|
||||
#ifdef ENABLE_UPDATER
|
||||
CheckUpdateDelegate* getCheckUpdateDelegate();
|
||||
#endif
|
||||
#if ENABLE_SENTRY
|
||||
void updateConsentCheckbox();
|
||||
#endif
|
||||
|
||||
void start();
|
||||
void showNotification(INotificationDelegate* del);
|
||||
|
@ -168,7 +168,7 @@ static FontData* load_font(std::map<std::string, FontData*>& fonts,
|
||||
const char* fileStr = xmlFont->Attribute("file");
|
||||
bool antialias = true;
|
||||
if (xmlFont->Attribute("antialias"))
|
||||
antialias = bool_attr_is_true(xmlFont, "antialias");
|
||||
antialias = bool_attr(xmlFont, "antialias", false);
|
||||
|
||||
std::string fontFilename;
|
||||
if (platformFileStr)
|
||||
|
@ -135,8 +135,8 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
widget = new Panel();
|
||||
}
|
||||
else if (elem_name == "box") {
|
||||
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
||||
bool vertical = bool_attr_is_true(elem, "vertical");
|
||||
bool horizontal = bool_attr(elem, "horizontal", false);
|
||||
bool vertical = bool_attr(elem, "vertical", false);
|
||||
int align = (horizontal ? HORIZONTAL: vertical ? VERTICAL: 0);
|
||||
|
||||
if (!widget)
|
||||
@ -173,11 +173,11 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
}
|
||||
|
||||
bool left = bool_attr_is_true(elem, "left");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool closewindow = bool_attr_is_true(elem, "closewindow");
|
||||
bool left = bool_attr(elem, "left", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool top = bool_attr(elem, "top", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
bool closewindow = bool_attr(elem, "closewindow", false);
|
||||
|
||||
widget->setAlign((left ? LEFT: (right ? RIGHT: CENTER)) |
|
||||
(top ? TOP: (bottom ? BOTTOM: MIDDLE)));
|
||||
@ -214,10 +214,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
}
|
||||
|
||||
bool center = bool_attr_is_true(elem, "center");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool center = bool_attr(elem, "center", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool top = bool_attr(elem, "top", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
|
||||
widget->setAlign((center ? CENTER:
|
||||
(right ? RIGHT: LEFT)) |
|
||||
@ -228,7 +228,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
if (!widget)
|
||||
widget = new ComboBox();
|
||||
|
||||
bool editable = bool_attr_is_true(elem, "editable");
|
||||
bool editable = bool_attr(elem, "editable", false);
|
||||
if (editable)
|
||||
((ComboBox*)widget)->setEditable(true);
|
||||
}
|
||||
@ -240,7 +240,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
|
||||
const char* suffix = elem->Attribute("suffix");
|
||||
const char* decimals = elem->Attribute("decimals");
|
||||
const bool readonly = bool_attr_is_true(elem, "readonly");
|
||||
const bool readonly = bool_attr(elem, "readonly", false);
|
||||
|
||||
widget = (elem_name == "expr" ?
|
||||
new ExprEntry:
|
||||
@ -257,7 +257,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
else if (elem_name == "grid") {
|
||||
const char *columns = elem->Attribute("columns");
|
||||
bool same_width_columns = bool_attr_is_true(elem, "same_width_columns");
|
||||
bool same_width_columns = bool_attr(elem, "same_width_columns", false);
|
||||
|
||||
if (columns != NULL) {
|
||||
widget = new Grid(strtol(columns, NULL, 10),
|
||||
@ -268,10 +268,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
if (!widget)
|
||||
widget = new Label("");
|
||||
|
||||
bool center = bool_attr_is_true(elem, "center");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool center = bool_attr(elem, "center", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool top = bool_attr(elem, "top", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
|
||||
widget->setAlign((center ? CENTER:
|
||||
(right ? RIGHT: LEFT)) |
|
||||
@ -290,10 +290,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
link->setUrl(url);
|
||||
}
|
||||
|
||||
bool center = bool_attr_is_true(elem, "center");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool center = bool_attr(elem, "center", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool top = bool_attr(elem, "top", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
|
||||
widget->setAlign(
|
||||
(center ? CENTER: (right ? RIGHT: LEFT)) |
|
||||
@ -303,7 +303,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
if (!widget)
|
||||
widget = new ListBox();
|
||||
|
||||
bool multiselect = bool_attr_is_true(elem, "multiselect");
|
||||
bool multiselect = bool_attr(elem, "multiselect", false);
|
||||
if (multiselect)
|
||||
static_cast<ListBox*>(widget)->setMultiselect(multiselect);
|
||||
}
|
||||
@ -323,8 +323,8 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
listitem->setValue(value);
|
||||
}
|
||||
else if (elem_name == "splitter") {
|
||||
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
||||
bool vertical = bool_attr_is_true(elem, "vertical");
|
||||
bool horizontal = bool_attr(elem, "horizontal", false);
|
||||
bool vertical = bool_attr(elem, "vertical", false);
|
||||
const char* by = elem->Attribute("by");
|
||||
const char* position = elem->Attribute("position");
|
||||
Splitter::Type type = (by && strcmp(by, "pixel") == 0 ?
|
||||
@ -361,10 +361,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
radio->setRadioGroup(radio_group);
|
||||
}
|
||||
|
||||
bool center = bool_attr_is_true(elem, "center");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool center = bool_attr(elem, "center", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool top = bool_attr(elem, "top", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
|
||||
widget->setAlign(
|
||||
(center ? CENTER:
|
||||
@ -373,12 +373,12 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
(bottom ? BOTTOM: MIDDLE)));
|
||||
}
|
||||
else if (elem_name == "separator") {
|
||||
bool center = bool_attr_is_true(elem, "center");
|
||||
bool right = bool_attr_is_true(elem, "right");
|
||||
bool middle = bool_attr_is_true(elem, "middle");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
||||
bool vertical = bool_attr_is_true(elem, "vertical");
|
||||
bool center = bool_attr(elem, "center", false);
|
||||
bool right = bool_attr(elem, "right", false);
|
||||
bool middle = bool_attr(elem, "middle", false);
|
||||
bool bottom = bool_attr(elem, "bottom", false);
|
||||
bool horizontal = bool_attr(elem, "horizontal", false);
|
||||
bool vertical = bool_attr(elem, "vertical", false);
|
||||
int align =
|
||||
(horizontal ? HORIZONTAL: 0) |
|
||||
(vertical ? VERTICAL: 0) |
|
||||
@ -400,7 +400,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
widget = new Slider(min_value, max_value, min_value);
|
||||
}
|
||||
else if (elem_name == "textbox") {
|
||||
bool wordwrap = bool_attr_is_true(elem, "wordwrap");
|
||||
bool wordwrap = bool_attr(elem, "wordwrap", false);
|
||||
|
||||
if (!widget)
|
||||
widget = new TextBox(elem->GetText(), 0);
|
||||
@ -416,7 +416,7 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
else if (elem_name == "window") {
|
||||
if (!widget) {
|
||||
bool desktop = bool_attr_is_true(elem, "desktop");
|
||||
bool desktop = bool_attr(elem, "desktop", false);
|
||||
|
||||
if (desktop)
|
||||
widget = new Window(Window::DesktopWindow);
|
||||
@ -427,8 +427,8 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
}
|
||||
else if (elem_name == "colorpicker") {
|
||||
const bool rgba = bool_attr_is_true(elem, "rgba");
|
||||
const bool simple = bool_attr_is_true(elem, "simple");
|
||||
const bool rgba = bool_attr(elem, "rgba", false);
|
||||
const bool simple = bool_attr(elem, "simple", false);
|
||||
|
||||
if (!widget) {
|
||||
ColorButtonOptions options;
|
||||
@ -453,9 +453,9 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
widget = new ButtonSet(strtol(columns, NULL, 10));
|
||||
|
||||
if (ButtonSet* buttonset = dynamic_cast<ButtonSet*>(widget)) {
|
||||
if (bool_attr_is_true(elem, "multiple"))
|
||||
if (bool_attr(elem, "multiple", false))
|
||||
buttonset->setMultiMode(ButtonSet::MultiMode::Set);
|
||||
if (bool_attr_is_true(elem, "oneormore"))
|
||||
if (bool_attr(elem, "oneormore", false))
|
||||
buttonset->setMultiMode(ButtonSet::MultiMode::OneOrMore);
|
||||
}
|
||||
}
|
||||
@ -487,21 +487,28 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
else if (elem_name == "image") {
|
||||
if (!widget) {
|
||||
const char* file = elem->Attribute("file");
|
||||
const char* icon = elem->Attribute("icon");
|
||||
|
||||
// Load image
|
||||
std::string icon(file);
|
||||
if (file) {
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir(file);
|
||||
if (!rf.findFirst())
|
||||
throw base::Exception("File %s not found", file);
|
||||
|
||||
ResourceFinder rf;
|
||||
rf.includeDataDir(file);
|
||||
if (!rf.findFirst())
|
||||
throw base::Exception("File %s not found", file);
|
||||
|
||||
try {
|
||||
os::SurfaceRef sur = os::instance()->loadRgbaSurface(rf.filename().c_str());
|
||||
widget = new ImageView(sur, 0);
|
||||
try {
|
||||
os::SurfaceRef sur = os::instance()->loadRgbaSurface(rf.filename().c_str());
|
||||
widget = new ImageView(sur, 0);
|
||||
}
|
||||
catch (...) {
|
||||
throw base::Exception("Error loading %s file", file);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
throw base::Exception("Error loading %s file", file);
|
||||
|
||||
if (icon) {
|
||||
SkinPartPtr part = SkinTheme::instance()->getPartById(std::string(icon));
|
||||
if (part) {
|
||||
widget = new ImageView(part->bitmapRef(0), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,12 +529,13 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
|
||||
{
|
||||
const char* id = elem->Attribute("id");
|
||||
const char* tooltip_dir = elem->Attribute("tooltip_dir");
|
||||
bool selected = bool_attr_is_true(elem, "selected");
|
||||
bool disabled = bool_attr_is_true(elem, "disabled");
|
||||
bool expansive = bool_attr_is_true(elem, "expansive");
|
||||
bool homogeneous = bool_attr_is_true(elem, "homogeneous");
|
||||
bool magnet = bool_attr_is_true(elem, "magnet");
|
||||
bool noborders = bool_attr_is_true(elem, "noborders");
|
||||
bool selected = bool_attr(elem, "selected", false);
|
||||
bool disabled = bool_attr(elem, "disabled", false);
|
||||
bool expansive = bool_attr(elem, "expansive", false);
|
||||
bool homogeneous = bool_attr(elem, "homogeneous", false);
|
||||
bool magnet = bool_attr(elem, "magnet", false);
|
||||
bool noborders = bool_attr(elem, "noborders", false);
|
||||
bool visible = bool_attr(elem, "visible", true);
|
||||
const char* width = elem->Attribute("width");
|
||||
const char* height = elem->Attribute("height");
|
||||
const char* minwidth = elem->Attribute("minwidth");
|
||||
@ -585,6 +593,9 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
|
||||
if (expansive)
|
||||
widget->setExpansive(true);
|
||||
|
||||
if (!visible)
|
||||
widget->setVisible(false);
|
||||
|
||||
if (homogeneous)
|
||||
widget->setAlign(widget->align() | HOMOGENEOUS);
|
||||
|
||||
@ -699,7 +710,7 @@ void WidgetLoader::fillWidgetWithXmlElementAttributesWithChildren(const TiXmlEle
|
||||
}
|
||||
|
||||
if (widget->type() == kViewWidget) {
|
||||
bool maxsize = bool_attr_is_true(elem, "maxsize");
|
||||
bool maxsize = bool_attr(elem, "maxsize", false);
|
||||
if (maxsize)
|
||||
static_cast<View*>(widget)->makeVisibleAllScrollableArea();
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ void save_xml(XmlDocumentRef doc, const std::string& filename)
|
||||
throw XmlException(doc.get());
|
||||
}
|
||||
|
||||
bool bool_attr_is_true(const TiXmlElement* elem, const char* attrName)
|
||||
bool bool_attr(const TiXmlElement* elem, const char* attrName, bool defaultVal)
|
||||
{
|
||||
const char* value = elem->Attribute(attrName);
|
||||
|
||||
return (value != NULL) && (strcmp(value, "true") == 0);
|
||||
return value == NULL ? defaultVal : strcmp(value, "true") == 0;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -23,7 +23,7 @@ namespace app {
|
||||
XmlDocumentRef open_xml(const std::string& filename);
|
||||
void save_xml(XmlDocumentRef doc, const std::string& filename);
|
||||
|
||||
bool bool_attr_is_true(const TiXmlElement* elem, const char* attrName);
|
||||
bool bool_attr(const TiXmlElement* elem, const char* attrName, bool defaultVal);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -116,6 +116,9 @@ static Item convert_to_item(TiXmlElement* elem)
|
||||
if (name == "hbox")
|
||||
return item.typeIncl("ui::HBox",
|
||||
"ui/box.h");
|
||||
if (name == "image")
|
||||
return item.typeIncl("ui::ImageView",
|
||||
"ui/image_view.h");
|
||||
if (name == "item" &&
|
||||
parent == "buttonset")
|
||||
return item.typeIncl("app::ButtonSet::Item",
|
||||
|
@ -16,10 +16,16 @@
|
||||
#include "app/send_crash.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/memory.h"
|
||||
#include "base/memory_dump.h"
|
||||
#include "base/system_console.h"
|
||||
#include "os/error.h"
|
||||
#include "os/system.h"
|
||||
#include "ver/info.h"
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
#include "app/sentry_wrapper.h"
|
||||
#else
|
||||
#include "base/memory_dump.h"
|
||||
#endif
|
||||
|
||||
#include <clocale>
|
||||
#include <cstdlib>
|
||||
@ -78,13 +84,20 @@ int app_main(int argc, char* argv[])
|
||||
#endif
|
||||
|
||||
try {
|
||||
#if ENABLE_SENTRY
|
||||
app::Sentry sentry;
|
||||
#else
|
||||
base::MemoryDump memoryDump;
|
||||
#endif
|
||||
MemLeak memleak;
|
||||
base::SystemConsole systemConsole;
|
||||
app::AppOptions options(argc, const_cast<const char**>(argv));
|
||||
os::SystemRef system(os::make_system());
|
||||
app::App app;
|
||||
|
||||
#if ENABLE_SENTRY
|
||||
sentry.init();
|
||||
#else
|
||||
// Change the memory dump filename to save on disk (.dmp
|
||||
// file). Note: Only useful on Windows.
|
||||
{
|
||||
@ -92,6 +105,7 @@ int app_main(int argc, char* argv[])
|
||||
if (!fn.empty())
|
||||
memoryDump.setFileName(fn);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int code = app.initialize(options);
|
||||
|
||||
|
@ -16,7 +16,13 @@ namespace ui {
|
||||
{
|
||||
public:
|
||||
CloseEvent(Component* source)
|
||||
: Event(source) { }
|
||||
: Event(source)
|
||||
, m_canceled(false) { }
|
||||
void cancel() { m_canceled = true; }
|
||||
bool canceled() const { return m_canceled; }
|
||||
|
||||
private:
|
||||
bool m_canceled;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -325,12 +325,16 @@ void Window::openWindowInForeground()
|
||||
|
||||
void Window::closeWindow(Widget* closer)
|
||||
{
|
||||
// Close event
|
||||
CloseEvent ev(closer);
|
||||
onBeforeClose(ev);
|
||||
if (ev.canceled())
|
||||
return;
|
||||
|
||||
m_closer = closer;
|
||||
|
||||
manager()->_closeWindow(this, true);
|
||||
|
||||
// Close event
|
||||
CloseEvent ev(closer);
|
||||
onClose(ev);
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@ namespace ui {
|
||||
virtual void onSetText() override;
|
||||
|
||||
// New events
|
||||
virtual void onBeforeClose(CloseEvent& ev) {}
|
||||
virtual void onClose(CloseEvent& ev);
|
||||
virtual void onHitTest(HitTestEvent& ev);
|
||||
virtual void onWindowResize();
|
||||
|
Loading…
Reference in New Issue
Block a user