2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
2024-03-06 05:50:24 +08:00
|
|
|
// Copyright (C) 2018-2024 Igara Studio S.A.
|
2018-02-21 21:39:30 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2015-02-12 23:16:25 +08:00
|
|
|
//
|
2016-08-27 04:02:58 +08:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2007-09-19 07:57:02 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/app.h"
|
2017-08-15 21:39:06 +08:00
|
|
|
#include "app/app_menus.h"
|
2016-11-15 06:44:29 +08:00
|
|
|
#include "app/commands/cmd_open_file.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/commands/command.h"
|
|
|
|
#include "app/commands/commands.h"
|
|
|
|
#include "app/commands/params.h"
|
|
|
|
#include "app/console.h"
|
2017-08-16 02:47:06 +08:00
|
|
|
#include "app/crash/data_recovery.h"
|
2018-07-07 22:54:44 +08:00
|
|
|
#include "app/doc.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ini_file.h"
|
|
|
|
#include "app/modules/gfx.h"
|
|
|
|
#include "app/modules/gui.h"
|
|
|
|
#include "app/modules/palettes.h"
|
2015-04-17 22:11:36 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/tools/ink.h"
|
|
|
|
#include "app/tools/tool_box.h"
|
|
|
|
#include "app/ui/editor/editor.h"
|
2014-10-29 22:58:03 +08:00
|
|
|
#include "app/ui/keyboard_shortcuts.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/main_menu_bar.h"
|
|
|
|
#include "app/ui/main_window.h"
|
|
|
|
#include "app/ui/skin/skin_property.h"
|
|
|
|
#include "app/ui/skin/skin_theme.h"
|
|
|
|
#include "app/ui/status_bar.h"
|
|
|
|
#include "app/ui/toolbar.h"
|
|
|
|
#include "app/ui_context.h"
|
2020-07-31 03:27:23 +08:00
|
|
|
#include "app/util/open_batch.h"
|
2018-11-28 21:30:33 +08:00
|
|
|
#include "base/fs.h"
|
2011-10-30 06:21:19 +08:00
|
|
|
#include "base/memory.h"
|
2018-11-28 21:30:33 +08:00
|
|
|
#include "base/string.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/sprite.h"
|
2018-08-09 23:58:43 +08:00
|
|
|
#include "os/error.h"
|
2021-04-30 03:13:45 +08:00
|
|
|
#include "os/screen.h"
|
2018-08-09 23:58:43 +08:00
|
|
|
#include "os/surface.h"
|
|
|
|
#include "os/system.h"
|
2021-02-03 02:59:28 +08:00
|
|
|
#include "os/window.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/intern.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "ui/ui.h"
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2020-06-12 01:51:28 +08:00
|
|
|
#ifdef ENABLE_STEAM
|
|
|
|
#include "steam/steam.h"
|
|
|
|
#endif
|
|
|
|
|
2012-02-13 10:21:06 +08:00
|
|
|
#include <algorithm>
|
2021-06-08 02:05:35 +08:00
|
|
|
#include <cstdio>
|
2012-02-13 10:21:06 +08:00
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
|
2023-05-02 06:18:23 +08:00
|
|
|
#if defined(ENABLE_DEVMODE) && defined(ENABLE_DATA_RECOVERY)
|
|
|
|
#include "app/crash/data_recovery.h"
|
2016-11-08 04:47:53 +08:00
|
|
|
#endif
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
2007-11-29 01:50:16 +08:00
|
|
|
|
2010-09-26 03:22:32 +08:00
|
|
|
using namespace gfx;
|
2012-06-18 09:02:54 +08:00
|
|
|
using namespace ui;
|
2013-08-06 08:20:19 +08:00
|
|
|
using namespace app::skin;
|
2010-09-26 03:22:32 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
static struct {
|
2007-11-29 01:50:16 +08:00
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
int scale;
|
2011-04-07 07:15:36 +08:00
|
|
|
} try_resolutions[] = { { 1024, 768, 2 },
|
2012-01-06 06:45:03 +08:00
|
|
|
{ 800, 600, 2 },
|
|
|
|
{ 640, 480, 2 },
|
|
|
|
{ 320, 240, 1 },
|
|
|
|
{ 320, 200, 1 },
|
|
|
|
{ 0, 0, 0 } };
|
2007-11-29 01:50:16 +08:00
|
|
|
|
2009-07-10 10:08:41 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
2021-02-18 23:30:14 +08:00
|
|
|
class CustomizedGuiManager : public ui::Manager
|
|
|
|
, public ui::LayoutIO {
|
|
|
|
public:
|
|
|
|
CustomizedGuiManager(const os::WindowRef& nativeWindow)
|
|
|
|
: ui::Manager(nativeWindow) {
|
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
protected:
|
2014-08-15 10:07:47 +08:00
|
|
|
bool onProcessMessage(Message* msg) override;
|
2017-08-17 02:17:11 +08:00
|
|
|
#if ENABLE_DEVMODE
|
|
|
|
bool onProcessDevModeKeyDown(KeyMessage* msg);
|
|
|
|
#endif
|
2017-08-15 21:39:06 +08:00
|
|
|
void onInitTheme(InitThemeEvent& ev) override;
|
2014-08-15 10:07:47 +08:00
|
|
|
LayoutIO* onGetLayoutIO() override { return this; }
|
2021-02-18 23:30:14 +08:00
|
|
|
void onNewDisplayConfiguration(Display* display) override;
|
2012-07-18 12:10:43 +08:00
|
|
|
|
|
|
|
// LayoutIO implementation
|
2014-08-15 10:07:47 +08:00
|
|
|
std::string loadLayout(Widget* widget) override;
|
|
|
|
void saveLayout(Widget* widget, const std::string& str) override;
|
2023-04-25 21:27:47 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
bool processKey(Message* msg);
|
2012-06-16 10:37:59 +08:00
|
|
|
};
|
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
static os::WindowRef main_window = nullptr;
|
2020-07-08 06:06:48 +08:00
|
|
|
static CustomizedGuiManager* manager = nullptr;
|
|
|
|
static Theme* gui_theme = nullptr;
|
2010-03-09 10:43:28 +08:00
|
|
|
|
2015-04-22 00:31:24 +08:00
|
|
|
static ui::Timer* defered_invalid_timer = nullptr;
|
|
|
|
static gfx::Region defered_invalid_region;
|
|
|
|
|
2011-04-02 22:45:43 +08:00
|
|
|
// Load & save graphics configuration
|
2021-06-08 02:05:35 +08:00
|
|
|
static bool load_gui_config(os::WindowSpec& spec, bool& maximized);
|
2008-10-01 09:27:51 +08:00
|
|
|
static void save_gui_config();
|
2007-09-20 08:32:35 +08:00
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
static bool create_main_window(bool gpuAccel,
|
2021-04-30 03:13:45 +08:00
|
|
|
bool& maximized,
|
|
|
|
std::string& lastError)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2021-04-30 03:13:45 +08:00
|
|
|
os::WindowSpec spec;
|
2021-06-08 02:05:35 +08:00
|
|
|
if (!load_gui_config(spec, maximized))
|
|
|
|
return false;
|
2007-11-29 01:50:16 +08:00
|
|
|
|
2016-02-24 05:08:25 +08:00
|
|
|
// Scale is equal to 0 when it's the first time the program is
|
|
|
|
// executed.
|
|
|
|
int scale = Preferences::instance().general.screenScale();
|
|
|
|
|
2024-03-06 05:50:24 +08:00
|
|
|
const os::SystemRef system = os::System::instance();
|
2012-08-06 08:16:16 +08:00
|
|
|
try {
|
2021-04-30 03:13:45 +08:00
|
|
|
if (!spec.frame().isEmpty() ||
|
|
|
|
!spec.contentRect().isEmpty()) {
|
2022-06-10 05:28:06 +08:00
|
|
|
spec.scale(scale == 0 ? 2: std::clamp(scale, 1, 4));
|
2024-03-06 05:50:24 +08:00
|
|
|
main_window = system->makeWindow(spec);
|
2016-02-24 05:08:25 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2021-02-03 02:59:28 +08:00
|
|
|
catch (const os::WindowCreationException& e) {
|
2015-10-01 21:54:47 +08:00
|
|
|
lastError = e.what();
|
2014-08-20 19:27:11 +08:00
|
|
|
}
|
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
if (!main_window) {
|
2014-08-20 19:27:11 +08:00
|
|
|
for (int c=0; try_resolutions[c].width; ++c) {
|
2012-08-06 08:16:16 +08:00
|
|
|
try {
|
2021-04-30 03:13:45 +08:00
|
|
|
spec.frame();
|
|
|
|
spec.position(os::WindowSpec::Position::Default);
|
|
|
|
spec.scale(scale == 0 ? try_resolutions[c].scale: scale);
|
|
|
|
spec.contentRect(gfx::Rect(0, 0,
|
|
|
|
try_resolutions[c].width * spec.scale(),
|
|
|
|
try_resolutions[c].height * spec.scale()));
|
2024-03-06 05:50:24 +08:00
|
|
|
main_window = system->makeWindow(spec);
|
2012-01-06 06:45:03 +08:00
|
|
|
break;
|
2007-11-29 01:50:16 +08:00
|
|
|
}
|
2021-02-03 02:59:28 +08:00
|
|
|
catch (const os::WindowCreationException& e) {
|
2015-10-01 21:54:47 +08:00
|
|
|
lastError = e.what();
|
2012-08-06 08:16:16 +08:00
|
|
|
}
|
2007-11-29 01:50:16 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2010-09-19 10:33:32 +08:00
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
if (main_window) {
|
2016-02-24 05:08:25 +08:00
|
|
|
// Change the scale value only in the first run (this will be
|
|
|
|
// saved when the program is closed).
|
|
|
|
if (scale == 0)
|
2021-02-03 02:59:28 +08:00
|
|
|
Preferences::instance().general.screenScale(main_window->scale());
|
2016-02-24 05:08:25 +08:00
|
|
|
|
2024-06-15 07:07:05 +08:00
|
|
|
main_window->setGpuAcceleration(gpuAccel);
|
|
|
|
|
2021-04-30 03:13:45 +08:00
|
|
|
if (main_window->isMinimized())
|
|
|
|
main_window->maximize();
|
2015-12-12 06:46:41 +08:00
|
|
|
}
|
2015-12-12 06:40:18 +08:00
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
return (main_window != nullptr);
|
2015-10-07 04:04:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initializes GUI.
|
|
|
|
int init_module_gui()
|
|
|
|
{
|
2024-03-06 05:50:24 +08:00
|
|
|
const os::SystemRef system = os::System::instance();
|
2017-08-15 21:39:06 +08:00
|
|
|
auto& pref = Preferences::instance();
|
2015-10-07 04:04:03 +08:00
|
|
|
bool maximized = false;
|
|
|
|
std::string lastError = "Unknown error";
|
2017-08-15 21:39:06 +08:00
|
|
|
bool gpuAccel = pref.general.gpuAcceleration();
|
2015-10-07 04:04:03 +08:00
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
if (!create_main_window(gpuAccel, maximized, lastError)) {
|
|
|
|
// If we've created the native window with hardware acceleration,
|
2015-10-07 04:04:03 +08:00
|
|
|
// now we try to do it without hardware acceleration.
|
|
|
|
if (gpuAccel &&
|
2024-03-06 05:50:24 +08:00
|
|
|
system->hasCapability(os::Capabilities::GpuAccelerationSwitch)) {
|
2021-02-03 02:59:28 +08:00
|
|
|
if (create_main_window(false, maximized, lastError)) {
|
2015-10-07 04:04:03 +08:00
|
|
|
// Disable hardware acceleration
|
2017-08-15 21:39:06 +08:00
|
|
|
pref.general.gpuAcceleration(false);
|
2015-10-07 04:04:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
if (!main_window) {
|
2018-08-09 23:58:43 +08:00
|
|
|
os::error_message(
|
2021-02-03 02:59:28 +08:00
|
|
|
("Unable to create a user-interface window.\nDetails: "+lastError+"\n").c_str());
|
2012-08-06 08:16:16 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-05-01 02:29:33 +08:00
|
|
|
// Create the default-manager
|
2021-02-18 23:30:14 +08:00
|
|
|
manager = new CustomizedGuiManager(main_window);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-01-22 04:50:04 +08:00
|
|
|
// Setup the GUI theme for all widgets
|
2017-04-15 19:13:20 +08:00
|
|
|
gui_theme = new SkinTheme;
|
2017-08-15 21:39:06 +08:00
|
|
|
ui::set_theme(gui_theme, pref.general.uiScale());
|
2010-10-31 07:37:31 +08:00
|
|
|
|
2012-08-06 08:16:16 +08:00
|
|
|
if (maximized)
|
2021-02-03 02:59:28 +08:00
|
|
|
main_window->maximize();
|
2009-11-22 22:39:52 +08:00
|
|
|
|
2011-05-01 02:29:33 +08:00
|
|
|
// Set graphics options for next time
|
2007-09-19 07:57:02 +08:00
|
|
|
save_gui_config();
|
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
update_windows_color_profile_from_preferences();
|
2019-05-08 21:55:56 +08:00
|
|
|
|
2007-09-19 07:57:02 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
void exit_module_gui()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2014-02-08 11:19:20 +08:00
|
|
|
save_gui_config();
|
|
|
|
|
2015-04-22 00:31:24 +08:00
|
|
|
delete defered_invalid_timer;
|
2012-04-16 02:21:24 +08:00
|
|
|
delete manager;
|
2010-10-27 06:23:04 +08:00
|
|
|
|
|
|
|
// Now we can destroy theme
|
2017-08-15 21:39:06 +08:00
|
|
|
ui::set_theme(nullptr, ui::guiscale());
|
2015-04-17 23:24:33 +08:00
|
|
|
delete gui_theme;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2020-07-08 06:06:48 +08:00
|
|
|
// This should be the last unref() of the display to delete it.
|
2021-02-03 02:59:28 +08:00
|
|
|
main_window.reset();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2021-02-03 02:59:28 +08:00
|
|
|
void update_windows_color_profile_from_preferences()
|
2019-05-08 21:55:56 +08:00
|
|
|
{
|
2024-03-06 05:50:24 +08:00
|
|
|
const os::SystemRef system = os::System::instance();
|
2019-05-08 21:55:56 +08:00
|
|
|
|
|
|
|
gen::WindowColorProfile windowProfile;
|
|
|
|
if (Preferences::instance().color.manage())
|
|
|
|
windowProfile = Preferences::instance().color.windowProfile();
|
|
|
|
else
|
|
|
|
windowProfile = gen::WindowColorProfile::SRGB;
|
|
|
|
|
2021-05-22 08:44:30 +08:00
|
|
|
os::ColorSpaceRef osCS = nullptr;
|
|
|
|
|
2019-05-08 21:55:56 +08:00
|
|
|
switch (windowProfile) {
|
|
|
|
case gen::WindowColorProfile::MONITOR:
|
2021-05-22 08:44:30 +08:00
|
|
|
osCS = nullptr;
|
2019-05-08 21:55:56 +08:00
|
|
|
break;
|
|
|
|
case gen::WindowColorProfile::SRGB:
|
2021-05-22 08:44:30 +08:00
|
|
|
osCS = system->makeColorSpace(gfx::ColorSpace::MakeSRGB());
|
2019-05-08 21:55:56 +08:00
|
|
|
break;
|
|
|
|
case gen::WindowColorProfile::SPECIFIC: {
|
|
|
|
std::string name =
|
|
|
|
Preferences::instance().color.windowProfileName();
|
|
|
|
|
2020-07-08 06:06:48 +08:00
|
|
|
std::vector<os::ColorSpaceRef> colorSpaces;
|
2019-05-08 21:55:56 +08:00
|
|
|
system->listColorSpaces(colorSpaces);
|
|
|
|
|
|
|
|
for (auto& cs : colorSpaces) {
|
|
|
|
auto gfxCs = cs->gfxColorSpace();
|
|
|
|
if (gfxCs->type() == gfx::ColorSpace::ICC &&
|
|
|
|
gfxCs->name() == name) {
|
2021-05-22 08:44:30 +08:00
|
|
|
osCS = cs;
|
2019-05-08 21:55:56 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-05-22 08:44:30 +08:00
|
|
|
|
|
|
|
// Set the default color space for all windows (osCS can be nullptr
|
|
|
|
// which means that each window should use its monitor color space)
|
|
|
|
system->setWindowsColorSpace(osCS);
|
|
|
|
|
|
|
|
// Set the color space of all windows
|
|
|
|
for (ui::Widget* widget : manager->children()) {
|
|
|
|
ASSERT(widget->type() == ui::kWindowWidget);
|
|
|
|
auto window = static_cast<ui::Window*>(widget);
|
|
|
|
if (window->ownDisplay()) {
|
|
|
|
if (auto display = window->display())
|
|
|
|
display->nativeWindow()->setColorSpace(osCS);
|
|
|
|
}
|
|
|
|
}
|
2019-05-08 21:55:56 +08:00
|
|
|
}
|
|
|
|
|
2021-06-08 02:05:35 +08:00
|
|
|
static bool load_gui_config(os::WindowSpec& spec, bool& maximized)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2024-03-06 05:50:24 +08:00
|
|
|
const os::SystemRef system = os::System::instance();
|
|
|
|
os::ScreenRef screen = system->mainScreen();
|
2021-06-08 02:05:35 +08:00
|
|
|
#ifdef LAF_SKIA
|
|
|
|
ASSERT(screen);
|
|
|
|
#else
|
|
|
|
// Compiled without Skia (none backend), without screen.
|
|
|
|
if (!screen) {
|
|
|
|
std::printf(
|
|
|
|
"\n"
|
|
|
|
" Aseprite cannot initialize GUI because it was compiled with LAF_BACKEND=none\n"
|
|
|
|
"\n"
|
|
|
|
" Check the documentation in:\n"
|
|
|
|
" https://github.com/aseprite/laf/blob/main/README.md\n"
|
|
|
|
" https://github.com/aseprite/aseprite/blob/main/INSTALL.md\n"
|
|
|
|
"\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-04-30 03:13:45 +08:00
|
|
|
spec.screen(screen);
|
|
|
|
|
|
|
|
gfx::Rect frame;
|
|
|
|
frame = get_config_rect("GfxMode", "Frame", frame);
|
|
|
|
if (!frame.isEmpty()) {
|
|
|
|
spec.position(os::WindowSpec::Position::Frame);
|
|
|
|
|
|
|
|
// Limit the content rect position into the available workarea,
|
|
|
|
// e.g. this is needed in case that the user closed Aseprite in a
|
|
|
|
// 2nd monitor that then unplugged and start Aseprite again.
|
|
|
|
bool ok = false;
|
|
|
|
os::ScreenList screens;
|
2024-03-06 05:50:24 +08:00
|
|
|
os::System::instance()->listScreens(screens);
|
2021-04-30 03:13:45 +08:00
|
|
|
for (const auto& screen : screens) {
|
|
|
|
gfx::Rect wa = screen->workarea();
|
|
|
|
gfx::Rect intersection = (frame & wa);
|
|
|
|
if (intersection.w >= 32 &&
|
|
|
|
intersection.h >= 32) {
|
|
|
|
ok = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset content rect
|
|
|
|
if (!ok) {
|
|
|
|
spec.position(os::WindowSpec::Position::Default);
|
|
|
|
frame = gfx::Rect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame.isEmpty()) {
|
|
|
|
frame = screen->workarea().shrink(64);
|
|
|
|
|
|
|
|
// Try to get Width/Height from previous Aseprite versions
|
|
|
|
frame.w = get_config_int("GfxMode", "Width", frame.w);
|
|
|
|
frame.h = get_config_int("GfxMode", "Height", frame.h);
|
|
|
|
}
|
|
|
|
spec.frame(frame);
|
2015-12-29 05:02:07 +08:00
|
|
|
|
2021-04-30 03:13:45 +08:00
|
|
|
maximized = get_config_bool("GfxMode", "Maximized", true);
|
2021-03-03 00:50:49 +08:00
|
|
|
|
|
|
|
ui::set_multiple_displays(Preferences::instance().experimental.multipleWindows());
|
2021-06-08 02:05:35 +08:00
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
static void save_gui_config()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2021-02-18 23:30:14 +08:00
|
|
|
os::Window* window = manager->display()->nativeWindow();
|
2021-02-03 02:59:28 +08:00
|
|
|
if (window) {
|
2021-04-30 03:13:45 +08:00
|
|
|
const bool maximized = (window->isMaximized() ||
|
|
|
|
window->isFullscreen());
|
|
|
|
const gfx::Rect frame = (maximized ? window->restoredFrame():
|
|
|
|
window->frame());
|
2015-12-12 06:40:18 +08:00
|
|
|
|
2021-04-30 03:13:45 +08:00
|
|
|
set_config_bool("GfxMode", "Maximized", maximized);
|
|
|
|
set_config_rect("GfxMode", "Frame", frame);
|
2010-03-29 03:18:49 +08:00
|
|
|
}
|
2007-11-25 02:23:53 +08:00
|
|
|
}
|
|
|
|
|
2018-07-07 22:54:44 +08:00
|
|
|
void update_screen_for_document(const Doc* document)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2024-09-03 10:12:13 +08:00
|
|
|
auto* ctx = UIContext::instance();
|
|
|
|
if (!ctx || !ctx->isUIAvailable())
|
|
|
|
return;
|
|
|
|
|
2011-03-23 08:11:25 +08:00
|
|
|
// Without document.
|
|
|
|
if (!document) {
|
|
|
|
// Well, change to the default palette.
|
2010-01-31 00:43:13 +08:00
|
|
|
if (set_current_palette(NULL, false)) {
|
2011-03-23 08:11:25 +08:00
|
|
|
// If the palette changes, refresh the whole screen.
|
2015-04-17 23:24:33 +08:00
|
|
|
if (manager)
|
|
|
|
manager->invalidate();
|
2007-11-19 22:23:15 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2011-03-23 08:11:25 +08:00
|
|
|
// With a document.
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
2018-07-07 22:54:44 +08:00
|
|
|
const_cast<Doc*>(document)->notifyGeneralUpdate();
|
2011-03-27 06:58:52 +08:00
|
|
|
|
|
|
|
// Update the tabs (maybe the modified status has been changed).
|
2013-01-21 05:40:37 +08:00
|
|
|
app_rebuild_documents_tabs();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-03 00:50:49 +08:00
|
|
|
void load_window_pos(Window* window, const char* section,
|
2018-11-29 22:44:10 +08:00
|
|
|
const bool limitMinSize)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2021-04-22 04:01:43 +08:00
|
|
|
Display* parentDisplay =
|
|
|
|
(window->display() ? window->display():
|
|
|
|
window->manager()->display());
|
|
|
|
Rect workarea =
|
|
|
|
(get_multiple_displays() ?
|
|
|
|
parentDisplay->nativeWindow()->screen()->workarea():
|
|
|
|
parentDisplay->bounds());
|
2021-02-18 23:30:14 +08:00
|
|
|
|
- All tools stuff refactored in various files/components.
- Added classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape, ToolIntertwine, ToolBox, etc.
- Added ToolLoopManager.
- Removed old src/modules/tools.cpp.
- Added ISettings and UISettingsImpl, adding the tools settings (onion skinning, grid, tiled mode, etc.).
- Added App::PenSizeBeforeChange, PenSizeAfterChange, CurrentToolChange signals.
- Renamed Context::get_bg/fg_color to getBg/FgColor.
- Refactored Brush class to Pen and added PenType.
- Renamed tiled_t to TiledMode.
- get_config_rect now uses the new Rect class imported from Vaca instead of old jrect.
- Added default_skin.xml to load tool icons.
- Added pen preview in Editor::cursor stuff.
- Added Editor::decorators.
Note: This big patch is from some time ago. I did my best to pre-commit other small changes before this big one.
2010-03-08 03:47:45 +08:00
|
|
|
// Default position
|
2021-03-03 00:50:49 +08:00
|
|
|
Rect origPos = window->bounds();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
- All tools stuff refactored in various files/components.
- Added classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape, ToolIntertwine, ToolBox, etc.
- Added ToolLoopManager.
- Removed old src/modules/tools.cpp.
- Added ISettings and UISettingsImpl, adding the tools settings (onion skinning, grid, tiled mode, etc.).
- Added App::PenSizeBeforeChange, PenSizeAfterChange, CurrentToolChange signals.
- Renamed Context::get_bg/fg_color to getBg/FgColor.
- Refactored Brush class to Pen and added PenType.
- Renamed tiled_t to TiledMode.
- get_config_rect now uses the new Rect class imported from Vaca instead of old jrect.
- Added default_skin.xml to load tool icons.
- Added pen preview in Editor::cursor stuff.
- Added Editor::decorators.
Note: This big patch is from some time ago. I did my best to pre-commit other small changes before this big one.
2010-03-08 03:47:45 +08:00
|
|
|
// Load configurated position
|
2021-03-03 00:50:49 +08:00
|
|
|
Rect pos = get_config_rect(section, "WindowPos", origPos);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2018-11-29 22:44:10 +08:00
|
|
|
if (limitMinSize) {
|
2022-06-10 21:31:13 +08:00
|
|
|
pos.w = std::clamp(pos.w, origPos.w, workarea.w);
|
|
|
|
pos.h = std::clamp(pos.h, origPos.h, workarea.h);
|
2018-11-29 22:44:10 +08:00
|
|
|
}
|
|
|
|
else {
|
2021-04-22 04:01:43 +08:00
|
|
|
pos.w = std::min(pos.w, workarea.w);
|
|
|
|
pos.h = std::min(pos.h, workarea.h);
|
2018-11-29 22:44:10 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2022-06-10 21:31:13 +08:00
|
|
|
pos.setOrigin(Point(std::clamp(pos.x, workarea.x, workarea.x2()-pos.w),
|
|
|
|
std::clamp(pos.y, workarea.y, workarea.y2()-pos.h)));
|
2007-09-19 07:57:02 +08:00
|
|
|
|
- All tools stuff refactored in various files/components.
- Added classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape, ToolIntertwine, ToolBox, etc.
- Added ToolLoopManager.
- Removed old src/modules/tools.cpp.
- Added ISettings and UISettingsImpl, adding the tools settings (onion skinning, grid, tiled mode, etc.).
- Added App::PenSizeBeforeChange, PenSizeAfterChange, CurrentToolChange signals.
- Renamed Context::get_bg/fg_color to getBg/FgColor.
- Refactored Brush class to Pen and added PenType.
- Renamed tiled_t to TiledMode.
- get_config_rect now uses the new Rect class imported from Vaca instead of old jrect.
- Added default_skin.xml to load tool icons.
- Added pen preview in Editor::cursor stuff.
- Added Editor::decorators.
Note: This big patch is from some time ago. I did my best to pre-commit other small changes before this big one.
2010-03-08 03:47:45 +08:00
|
|
|
window->setBounds(pos);
|
2021-03-03 00:50:49 +08:00
|
|
|
|
|
|
|
if (get_multiple_displays()) {
|
|
|
|
Rect frame = get_config_rect(section, "WindowFrame", gfx::Rect());
|
|
|
|
if (!frame.isEmpty()) {
|
2021-04-22 04:01:43 +08:00
|
|
|
limit_with_workarea(parentDisplay, frame);
|
2021-03-03 00:50:49 +08:00
|
|
|
window->loadNativeFrame(frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
del_config_value(section, "WindowFrame");
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2021-05-10 22:52:38 +08:00
|
|
|
void save_window_pos(Window* window, const char* section)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2021-03-03 00:50:49 +08:00
|
|
|
gfx::Rect rc;
|
|
|
|
|
|
|
|
if (!window->lastNativeFrame().isEmpty()) {
|
2021-05-10 22:52:38 +08:00
|
|
|
const os::Window* mainNativeWindow = manager->display()->nativeWindow();
|
2021-03-03 00:50:49 +08:00
|
|
|
rc = window->lastNativeFrame();
|
|
|
|
set_config_rect(section, "WindowFrame", rc);
|
|
|
|
rc.offset(-mainNativeWindow->frame().origin());
|
2021-05-10 22:52:38 +08:00
|
|
|
rc /= mainNativeWindow->scale();
|
2021-03-03 00:50:49 +08:00
|
|
|
}
|
|
|
|
else {
|
2021-05-10 22:52:38 +08:00
|
|
|
del_config_value(section, "WindowFrame");
|
2021-03-03 00:50:49 +08:00
|
|
|
rc = window->bounds();
|
|
|
|
}
|
|
|
|
|
|
|
|
set_config_rect(section, "WindowPos", rc);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
// TODO Replace this with new theme styles
|
2014-01-26 19:39:33 +08:00
|
|
|
Widget* setup_mini_font(Widget* widget)
|
2011-03-30 08:07:37 +08:00
|
|
|
{
|
2019-08-02 06:14:46 +08:00
|
|
|
auto skinProp = get_skin_property(widget);
|
2015-05-06 06:14:33 +08:00
|
|
|
skinProp->setMiniFont();
|
2014-01-26 19:39:33 +08:00
|
|
|
return widget;
|
2011-03-30 08:07:37 +08:00
|
|
|
}
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
// TODO Replace this with new theme styles
|
2014-01-26 19:39:33 +08:00
|
|
|
Widget* setup_mini_look(Widget* widget)
|
2010-03-22 10:18:30 +08:00
|
|
|
{
|
2019-08-02 06:14:46 +08:00
|
|
|
auto skinProp = get_skin_property(widget);
|
2017-02-14 05:34:23 +08:00
|
|
|
skinProp->setLook(MiniLook);
|
2014-01-26 19:39:33 +08:00
|
|
|
return widget;
|
2010-03-22 10:18:30 +08:00
|
|
|
}
|
|
|
|
|
2011-05-01 02:29:33 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Button style (convert radio or check buttons and draw it like
|
|
|
|
// normal buttons)
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2015-04-22 00:31:24 +08:00
|
|
|
void defer_invalid_rect(const gfx::Rect& rc)
|
|
|
|
{
|
|
|
|
if (!defered_invalid_timer)
|
|
|
|
defered_invalid_timer = new ui::Timer(250, manager);
|
|
|
|
|
|
|
|
defered_invalid_timer->stop();
|
|
|
|
defered_invalid_timer->start();
|
|
|
|
defered_invalid_region.createUnion(defered_invalid_region, gfx::Region(rc));
|
|
|
|
}
|
|
|
|
|
2020-07-31 03:27:23 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
2010-03-01 08:09:46 +08:00
|
|
|
// Manager event handler.
|
2020-07-31 03:27:23 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2020-06-12 01:51:28 +08:00
|
|
|
#ifdef ENABLE_STEAM
|
|
|
|
if (auto steamAPI = steam::SteamAPI::instance())
|
|
|
|
steamAPI->runCallbacks();
|
|
|
|
#endif
|
|
|
|
|
2013-07-29 08:17:07 +08:00
|
|
|
switch (msg->type()) {
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2021-03-03 00:50:49 +08:00
|
|
|
case kCloseDisplayMessage:
|
2021-10-20 22:53:47 +08:00
|
|
|
// Only call the exit command/close the app when the the main
|
|
|
|
// display is the closed window in this kCloseDisplayMessage
|
|
|
|
// message and it's the current running foreground window.
|
|
|
|
if (msg->display() == this->display() &&
|
|
|
|
getForegroundWindow() == App::instance()->mainWindow()) {
|
2021-03-03 00:50:49 +08:00
|
|
|
// Execute the "Exit" command.
|
|
|
|
Command* command = Commands::instance()->byId(CommandId::Exit());
|
|
|
|
UIContext::instance()->executeCommandFromMenuOrShortcut(command);
|
|
|
|
return true;
|
|
|
|
}
|
2012-02-03 07:01:54 +08:00
|
|
|
break;
|
|
|
|
|
2014-03-20 18:31:19 +08:00
|
|
|
case kDropFilesMessage:
|
2018-11-28 21:30:33 +08:00
|
|
|
// Files are processed only when the main window is the current
|
|
|
|
// window running.
|
|
|
|
//
|
|
|
|
// TODO could we send the files to each dialog?
|
|
|
|
if (getForegroundWindow() == App::instance()->mainWindow()) {
|
2018-02-21 21:39:30 +08:00
|
|
|
base::paths files = static_cast<DropFilesMessage*>(msg)->files();
|
2014-12-01 08:06:29 +08:00
|
|
|
UIContext* ctx = UIContext::instance();
|
2020-07-31 03:27:23 +08:00
|
|
|
OpenBatchOfFiles batch;
|
2014-12-01 08:06:29 +08:00
|
|
|
|
2016-11-15 06:44:29 +08:00
|
|
|
while (!files.empty()) {
|
|
|
|
auto fn = files.front();
|
|
|
|
files.erase(files.begin());
|
|
|
|
|
2014-12-01 08:06:29 +08:00
|
|
|
// If the document is already open, select it.
|
2018-07-07 22:54:44 +08:00
|
|
|
Doc* doc = ctx->documents().getByFileName(fn);
|
2014-12-01 08:06:29 +08:00
|
|
|
if (doc) {
|
2018-07-15 10:24:49 +08:00
|
|
|
DocView* docView = ctx->getFirstDocView(doc);
|
2014-12-01 08:06:29 +08:00
|
|
|
if (docView)
|
|
|
|
ctx->setActiveView(docView);
|
|
|
|
else {
|
2018-07-15 10:24:49 +08:00
|
|
|
ASSERT(false); // Must be some DocView available
|
2014-12-01 08:06:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Load the file
|
|
|
|
else {
|
2018-11-28 21:30:33 +08:00
|
|
|
// Depending on the file type we will want to do different things:
|
|
|
|
std::string extension = base::string_to_lower(
|
|
|
|
base::get_file_extension(fn));
|
|
|
|
|
|
|
|
// Install the extension
|
|
|
|
if (extension == "aseprite-extension") {
|
|
|
|
Command* cmd = Commands::instance()->byId(CommandId::Options());
|
|
|
|
Params params;
|
|
|
|
params.set("installExtension", fn.c_str());
|
2019-10-29 21:31:12 +08:00
|
|
|
ctx->executeCommandFromMenuOrShortcut(cmd, params);
|
2018-11-28 21:30:33 +08:00
|
|
|
}
|
|
|
|
// Other extensions will be handled as an image/sprite
|
|
|
|
else {
|
2020-07-31 03:27:23 +08:00
|
|
|
batch.open(ctx, fn,
|
|
|
|
false); // Open all frames
|
2018-11-28 21:30:33 +08:00
|
|
|
|
|
|
|
// Remove all used file names from the "dropped files"
|
2020-07-31 03:27:23 +08:00
|
|
|
for (const auto& usedFn : batch.usedFiles()) {
|
2018-11-28 21:30:33 +08:00
|
|
|
auto it = std::find(files.begin(), files.end(), usedFn);
|
|
|
|
if (it != files.end())
|
|
|
|
files.erase(it);
|
|
|
|
}
|
2016-11-15 06:44:29 +08:00
|
|
|
}
|
2014-12-01 08:06:29 +08:00
|
|
|
}
|
2014-03-20 18:31:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-07-24 02:15:04 +08:00
|
|
|
case kKeyDownMessage: {
|
2017-08-16 02:47:06 +08:00
|
|
|
#if ENABLE_DEVMODE
|
2017-08-17 02:17:11 +08:00
|
|
|
if (onProcessDevModeKeyDown(static_cast<KeyMessage*>(msg)))
|
|
|
|
return true;
|
|
|
|
#endif // ENABLE_DEVMODE
|
2015-04-08 01:41:40 +08:00
|
|
|
|
2015-05-04 22:25:42 +08:00
|
|
|
// Call base impl to check if there is a foreground window as
|
|
|
|
// top level that needs keys. (In this way we just do not
|
|
|
|
// process keyboard shortcuts for menus and tools).
|
|
|
|
if (Manager::onProcessMessage(msg))
|
|
|
|
return true;
|
2010-10-29 22:26:32 +08:00
|
|
|
|
2023-04-25 21:27:47 +08:00
|
|
|
if (processKey(msg))
|
|
|
|
return true;
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
2018-07-24 02:15:04 +08:00
|
|
|
}
|
2008-01-04 07:22:04 +08:00
|
|
|
|
2015-04-22 00:31:24 +08:00
|
|
|
case kTimerMessage:
|
|
|
|
if (static_cast<TimerMessage*>(msg)->timer() == defered_invalid_timer) {
|
2018-12-04 10:59:42 +08:00
|
|
|
invalidateRegion(defered_invalid_region);
|
2015-04-22 00:31:24 +08:00
|
|
|
defered_invalid_region.clear();
|
|
|
|
defered_invalid_timer->stop();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
return Manager::onProcessMessage(msg);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2008-01-14 04:49:02 +08:00
|
|
|
|
2017-08-17 02:17:11 +08:00
|
|
|
#if ENABLE_DEVMODE
|
|
|
|
bool CustomizedGuiManager::onProcessDevModeKeyDown(KeyMessage* msg)
|
|
|
|
{
|
|
|
|
// Ctrl+Shift+Q generates a crash (useful to test the anticrash feature)
|
|
|
|
if (msg->ctrlPressed() &&
|
|
|
|
msg->shiftPressed() &&
|
|
|
|
msg->scancode() == kKeyQ) {
|
|
|
|
int* p = nullptr;
|
|
|
|
*p = 0; // *Crash*
|
|
|
|
return true; // This line should not be executed anyway
|
|
|
|
}
|
|
|
|
|
2021-03-03 00:50:49 +08:00
|
|
|
// Ctrl+F1 switches screen/UI scaling
|
2018-06-23 02:41:22 +08:00
|
|
|
if (msg->ctrlPressed() &&
|
|
|
|
msg->scancode() == kKeyF1) {
|
2017-08-23 01:54:08 +08:00
|
|
|
try {
|
2021-02-24 20:26:24 +08:00
|
|
|
os::Window* window = display()->nativeWindow();
|
2021-02-03 02:59:28 +08:00
|
|
|
int screenScale = window->scale();
|
2017-08-23 01:54:08 +08:00
|
|
|
int uiScale = ui::guiscale();
|
|
|
|
|
|
|
|
if (msg->shiftPressed()) {
|
|
|
|
if (screenScale == 2 && uiScale == 1) {
|
|
|
|
screenScale = 1;
|
|
|
|
uiScale = 1;
|
|
|
|
}
|
|
|
|
else if (screenScale == 1 && uiScale == 1) {
|
|
|
|
screenScale = 1;
|
|
|
|
uiScale = 2;
|
|
|
|
}
|
|
|
|
else if (screenScale == 1 && uiScale == 2) {
|
|
|
|
screenScale = 2;
|
|
|
|
uiScale = 1;
|
|
|
|
}
|
2017-08-17 02:17:11 +08:00
|
|
|
}
|
2017-08-23 01:54:08 +08:00
|
|
|
else {
|
|
|
|
if (screenScale == 2 && uiScale == 1) {
|
|
|
|
screenScale = 1;
|
|
|
|
uiScale = 2;
|
|
|
|
}
|
|
|
|
else if (screenScale == 1 && uiScale == 2) {
|
|
|
|
screenScale = 1;
|
|
|
|
uiScale = 1;
|
|
|
|
}
|
|
|
|
else if (screenScale == 1 && uiScale == 1) {
|
|
|
|
screenScale = 2;
|
|
|
|
uiScale = 1;
|
|
|
|
}
|
2017-08-17 02:17:11 +08:00
|
|
|
}
|
2017-08-23 01:54:08 +08:00
|
|
|
|
|
|
|
if (uiScale != ui::guiscale()) {
|
|
|
|
ui::set_theme(ui::get_theme(), uiScale);
|
2017-08-17 02:17:11 +08:00
|
|
|
}
|
2021-02-03 02:59:28 +08:00
|
|
|
if (screenScale != window->scale()) {
|
2024-06-15 07:07:05 +08:00
|
|
|
updateAllDisplays(screenScale, window->gpuAcceleration());
|
2017-08-17 02:17:11 +08:00
|
|
|
}
|
|
|
|
}
|
2017-08-23 01:54:08 +08:00
|
|
|
catch (const std::exception& ex) {
|
|
|
|
Console::showException(ex);
|
2017-08-17 02:17:11 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_DATA_RECOVERY
|
|
|
|
// Ctrl+Shift+R recover active sprite from the backup store
|
2022-10-20 23:31:22 +08:00
|
|
|
auto editor = Editor::activeEditor();
|
2017-08-17 02:17:11 +08:00
|
|
|
if (msg->ctrlPressed() &&
|
|
|
|
msg->shiftPressed() &&
|
|
|
|
msg->scancode() == kKeyR &&
|
|
|
|
App::instance()->dataRecovery() &&
|
|
|
|
App::instance()->dataRecovery()->activeSession() &&
|
2022-10-20 23:31:22 +08:00
|
|
|
editor &&
|
|
|
|
editor->document()) {
|
2019-05-31 10:17:13 +08:00
|
|
|
Doc* doc = App::instance()
|
2017-08-17 02:17:11 +08:00
|
|
|
->dataRecovery()
|
|
|
|
->activeSession()
|
2022-10-20 23:31:22 +08:00
|
|
|
->restoreBackupById(editor->document()->id(), nullptr);
|
2019-05-31 10:17:13 +08:00
|
|
|
if (doc)
|
|
|
|
UIContext::instance()->documents().add(doc);
|
2017-08-17 02:17:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif // ENABLE_DATA_RECOVERY
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif // ENABLE_DEVMODE
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
void CustomizedGuiManager::onInitTheme(InitThemeEvent& ev)
|
|
|
|
{
|
|
|
|
Manager::onInitTheme(ev);
|
|
|
|
|
|
|
|
// Update the theme on all menus
|
|
|
|
AppMenus::instance()->initTheme();
|
|
|
|
}
|
|
|
|
|
2021-02-18 23:30:14 +08:00
|
|
|
void CustomizedGuiManager::onNewDisplayConfiguration(Display* display)
|
2015-07-30 05:12:35 +08:00
|
|
|
{
|
2021-02-18 23:30:14 +08:00
|
|
|
Manager::onNewDisplayConfiguration(display);
|
2020-12-12 02:52:14 +08:00
|
|
|
|
2021-03-20 05:57:56 +08:00
|
|
|
// Only whne the main display/window is modified
|
|
|
|
if (display == this->display()) {
|
|
|
|
save_gui_config();
|
|
|
|
|
|
|
|
// TODO Should we provide a more generic way for all ui::Window to
|
|
|
|
// detect the os::Window (or UI Screen Scaling) change?
|
|
|
|
Console::notifyNewDisplayConfiguration();
|
|
|
|
}
|
2015-07-30 05:12:35 +08:00
|
|
|
}
|
|
|
|
|
2023-04-25 21:27:47 +08:00
|
|
|
bool CustomizedGuiManager::processKey(Message* msg)
|
|
|
|
{
|
|
|
|
App* app = App::instance();
|
|
|
|
const KeyboardShortcuts* keys = KeyboardShortcuts::instance();
|
2023-04-25 21:38:49 +08:00
|
|
|
const KeyContext contexts[] = {
|
|
|
|
keys->getCurrentKeyContext(),
|
|
|
|
KeyContext::Normal
|
|
|
|
};
|
|
|
|
int n = (contexts[0] != contexts[1] ? 2: 1);
|
|
|
|
for (int i = 0; i < n; ++i) {
|
|
|
|
for (const KeyPtr& key : *keys) {
|
|
|
|
if (key->isPressed(msg, *keys, contexts[i])) {
|
|
|
|
// Cancel menu-bar loops (to close any popup menu)
|
|
|
|
app->mainWindow()->getMenuBar()->cancelMenuLoop();
|
|
|
|
|
|
|
|
switch (key->type()) {
|
|
|
|
|
|
|
|
case KeyType::Tool: {
|
|
|
|
tools::Tool* current_tool = app->activeTool();
|
|
|
|
tools::Tool* select_this_tool = key->tool();
|
|
|
|
tools::ToolBox* toolbox = app->toolBox();
|
|
|
|
std::vector<tools::Tool*> possibles;
|
|
|
|
|
|
|
|
// Collect all tools with the pressed keyboard-shortcut
|
|
|
|
for (tools::Tool* tool : *toolbox) {
|
|
|
|
const KeyPtr key = keys->tool(tool);
|
|
|
|
if (key && key->isPressed(msg, *keys))
|
|
|
|
possibles.push_back(tool);
|
2023-04-25 21:27:47 +08:00
|
|
|
}
|
|
|
|
|
2023-04-25 21:38:49 +08:00
|
|
|
if (possibles.size() >= 2) {
|
|
|
|
bool done = false;
|
|
|
|
|
2023-04-25 21:27:47 +08:00
|
|
|
for (size_t i=0; i<possibles.size(); ++i) {
|
2023-04-25 21:38:49 +08:00
|
|
|
if (possibles[i] != current_tool &&
|
|
|
|
ToolBar::instance()->isToolVisible(possibles[i])) {
|
|
|
|
select_this_tool = possibles[i];
|
|
|
|
done = true;
|
2023-04-25 21:27:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-04-25 21:38:49 +08:00
|
|
|
|
|
|
|
if (!done) {
|
|
|
|
for (size_t i=0; i<possibles.size(); ++i) {
|
|
|
|
// If one of the possibilities is the current tool
|
|
|
|
if (possibles[i] == current_tool) {
|
|
|
|
// We select the next tool in the possibilities
|
|
|
|
select_this_tool = possibles[(i+1) % possibles.size()];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-04-25 21:27:47 +08:00
|
|
|
}
|
|
|
|
|
2023-04-25 21:38:49 +08:00
|
|
|
ToolBar::instance()->selectTool(select_this_tool);
|
|
|
|
return true;
|
|
|
|
}
|
2023-04-25 21:27:47 +08:00
|
|
|
|
2023-04-25 21:38:49 +08:00
|
|
|
case KeyType::Command: {
|
|
|
|
Command* command = key->command();
|
|
|
|
|
|
|
|
// Commands are executed only when the main window is
|
|
|
|
// the current window running.
|
|
|
|
if (getForegroundWindow() == app->mainWindow()) {
|
|
|
|
// OK, so we can execute the command represented
|
|
|
|
// by the pressed-key in the message...
|
|
|
|
UIContext::instance()->executeCommandFromMenuOrShortcut(
|
|
|
|
command, key->params());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2023-04-25 21:27:47 +08:00
|
|
|
|
2023-04-25 21:38:49 +08:00
|
|
|
case KeyType::Quicktool: {
|
|
|
|
// Do nothing, it is used in the editor through the
|
|
|
|
// KeyboardShortcuts::getCurrentQuicktool() function.
|
|
|
|
break;
|
2023-04-25 21:27:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-04-25 21:38:49 +08:00
|
|
|
break;
|
2023-04-25 21:27:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-18 12:10:43 +08:00
|
|
|
std::string CustomizedGuiManager::loadLayout(Widget* widget)
|
|
|
|
{
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
if (widget->window() == nullptr)
|
2012-07-18 12:10:43 +08:00
|
|
|
return "";
|
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
std::string windowId = widget->window()->id();
|
|
|
|
std::string widgetId = widget->id();
|
2012-07-18 12:10:43 +08:00
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
return get_config_string(("layout:"+windowId).c_str(), widgetId.c_str(), "");
|
2012-07-18 12:10:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CustomizedGuiManager::saveLayout(Widget* widget, const std::string& str)
|
|
|
|
{
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
if (widget->window() == NULL)
|
2012-07-18 12:10:43 +08:00
|
|
|
return;
|
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
std::string windowId = widget->window()->id();
|
|
|
|
std::string widgetId = widget->id();
|
2012-07-18 12:10:43 +08:00
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
set_config_string(("layout:"+windowId).c_str(),
|
|
|
|
widgetId.c_str(),
|
|
|
|
str.c_str());
|
2012-07-18 12:10:43 +08:00
|
|
|
}
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|