Merge branch 'master' into beta

This commit is contained in:
David Capello 2016-11-29 12:14:33 -03:00
commit f57c298ad6
133 changed files with 2025 additions and 1063 deletions

View File

@ -70,6 +70,7 @@ option(USE_SHARED_FREETYPE "Use shared FreeType library" off)
option(USE_SHARED_ALLEGRO4 "Use shared Allegro 4 library (without resize support)" off) option(USE_SHARED_ALLEGRO4 "Use shared Allegro 4 library (without resize support)" off)
option(ENABLE_MEMLEAK "Enable memory-leaks detector (only for developers)" off) option(ENABLE_MEMLEAK "Enable memory-leaks detector (only for developers)" off)
option(ENABLE_UPDATER "Enable automatic check for updates" on) option(ENABLE_UPDATER "Enable automatic check for updates" on)
option(ENABLE_SCRIPTING "Compile with scripting support" on)
option(ENABLE_WEBSERVER "Enable support to run a webserver (for HTML5 gamedev)" off) option(ENABLE_WEBSERVER "Enable support to run a webserver (for HTML5 gamedev)" off)
option(ENABLE_TESTS "Enable the unit tests" off) option(ENABLE_TESTS "Enable the unit tests" off)
option(ENABLE_TRIAL_MODE "Compile the trial version" off) option(ENABLE_TRIAL_MODE "Compile the trial version" off)
@ -163,9 +164,16 @@ else()
add_definitions(-DNDEBUG) add_definitions(-DNDEBUG)
endif() endif()
# Fix to compile gtest with VC11 (2012) if(MSVC)
if(MSVC_VERSION EQUAL 1700) if(USE_STATIC_LIBC)
add_definitions(-D_VARIADIC_MAX=10) if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MTd")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MTd")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MT")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MT")
endif()
endif()
endif() endif()
if(NOT WIN32 AND NOT APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(NOT WIN32 AND NOT APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -438,6 +446,10 @@ if(ENABLE_MEMLEAK)
add_definitions(-DLAF_MEMLEAK) add_definitions(-DLAF_MEMLEAK)
endif() endif()
if(NOT USE_STATIC_LIBC)
set(gtest_force_shared_crt ON CACHE BOOL "Use shared (DLL) run-time lib even when Google Test is built as static lib.")
endif()
set(LAF_WITH_TESTS ${ENABLE_TESTS} CACHE BOOL "Enable LAF tests") set(LAF_WITH_TESTS ${ENABLE_TESTS} CACHE BOOL "Enable LAF tests")
add_subdirectory(laf) add_subdirectory(laf)

View File

@ -77,8 +77,7 @@ And it uses the following third-party libraries:
* [Allegro 4](http://alleg.sourceforge.net/) - [allegro4 license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/allegro4-LICENSE.txt) * [Allegro 4](http://alleg.sourceforge.net/) - [allegro4 license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/allegro4-LICENSE.txt)
* [FreeType](http://www.freetype.org/) - [FTL license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/FTL.txt) * [FreeType](http://www.freetype.org/) - [FTL license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/FTL.txt)
* [Google Test](https://github.com/google/googletest) - [gtest license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/gtest-LICENSE.txt) * [Google Test](https://github.com/google/googletest) - [BSD-like license](https://github.com/aseprite/googletest/blob/master/googletest/LICENSE)
* [XFree86](http://www.x.org/) - [XFree86 license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/XFree86-LICENSE.txt)
* [curl](http://curl.haxx.se/) - [curl license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/curl-LICENSE.txt) * [curl](http://curl.haxx.se/) - [curl license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/curl-LICENSE.txt)
* [duktape](http://duktape.org/) - [MIT license](https://github.com/aseprite/aseprite/tree/master/third_party/duktape/LICENSE.txt) * [duktape](http://duktape.org/) - [MIT license](https://github.com/aseprite/aseprite/tree/master/third_party/duktape/LICENSE.txt)
* [giflib](http://sourceforge.net/projects/giflib/) - [giflib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/giflib-LICENSE.txt) * [giflib](http://sourceforge.net/projects/giflib/) - [giflib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/giflib-LICENSE.txt)
@ -86,9 +85,9 @@ And it uses the following third-party libraries:
* [libpng](http://www.libpng.org/pub/png/) - [libpng license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libpng-LICENSE.txt) * [libpng](http://www.libpng.org/pub/png/) - [libpng license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libpng-LICENSE.txt)
* [libwebp](https://developers.google.com/speed/webp/) - [libwebp license](https://chromium.googlesource.com/webm/libwebp/+/master/COPYING) * [libwebp](https://developers.google.com/speed/webp/) - [libwebp license](https://chromium.googlesource.com/webm/libwebp/+/master/COPYING)
* [loadpng](http://tjaden.strangesoft.net/loadpng/) - [zlib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt) * [loadpng](http://tjaden.strangesoft.net/loadpng/) - [zlib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt)
* [modp_b64](https://github.com/aseprite/aseprite/tree/master/third_party/modp_b64/modp_b64.h) - [BSD license](https://github.com/aseprite/aseprite/tree/master/third_party/modp_b64/LICENSE)
* [pixman](http://www.pixman.org/) - [MIT license](http://cgit.freedesktop.org/pixman/plain/COPYING) * [pixman](http://www.pixman.org/) - [MIT license](http://cgit.freedesktop.org/pixman/plain/COPYING)
* [simpleini](https://github.com/aseprite/simpleini/) - [MIT license](https://github.com/aseprite/simpleini/blob/aseprite/LICENCE.txt) * [simpleini](https://github.com/aseprite/simpleini/) - [MIT license](https://github.com/aseprite/simpleini/blob/aseprite/LICENCE.txt)
* [stringencoders](https://github.com/client9/stringencoders) - [MIT license](https://github.com/aseprite/stringencoders/blob/master/LICENSE)
* [tinyxml](http://www.sourceforge.net/projects/tinyxml) - [zlib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt) * [tinyxml](http://www.sourceforge.net/projects/tinyxml) - [zlib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt)
* [zlib](http://www.gzip.org/zlib/) - [ZLIB license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt) * [zlib](http://www.gzip.org/zlib/) - [ZLIB license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/ZLIB.txt)
@ -103,8 +102,7 @@ This program is distributed under three different licenses:
(e.g. [laf](https://github.com/aseprite/laf), (e.g. [laf](https://github.com/aseprite/laf),
[clip](https://github.com/aseprite/clip), [clip](https://github.com/aseprite/clip),
[she](https://github.com/aseprite/aseprite/tree/master/src/she), [she](https://github.com/aseprite/aseprite/tree/master/src/she),
[gfx](https://github.com/aseprite/gfx), [gfx](src/gfx), [ui](src/ui), etc.).
[ui](https://github.com/aseprite/ui), etc.).
2. You can request a special 2. You can request a special
[educational license](http://www.aseprite.org/faq/#is-there-an-educational-license) [educational license](http://www.aseprite.org/faq/#is-there-an-educational-license)
in case you are a teacher in an educational institution and want to in case you are a teacher in an educational institution and want to

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 397 B

View File

@ -99,7 +99,7 @@
<option id="rewind_on_stop" type="bool" default="false" /> <option id="rewind_on_stop" type="bool" default="false" />
<option id="expand_menubar_on_mouseover" type="bool" default="false" migrate="Options.ExpandMenuBarOnMouseover" /> <option id="expand_menubar_on_mouseover" type="bool" default="false" migrate="Options.ExpandMenuBarOnMouseover" />
<option id="data_recovery" type="bool" default="true" /> <option id="data_recovery" type="bool" default="true" />
<option id="data_recovery_period" type="int" default="2" /> <option id="data_recovery_period" type="double" default="2.0" />
<option id="show_full_path" type="bool" default="true" /> <option id="show_full_path" type="bool" default="true" />
<option id="timeline_position" type="TimelinePosition" default="TimelinePosition::BOTTOM" /> <option id="timeline_position" type="TimelinePosition" default="TimelinePosition::BOTTOM" />
</section> </section>
@ -278,6 +278,9 @@
<option id="color1" type="app::Color" default="app::Color::fromRgb(128, 128, 128)" migrate="Option.CheckedBgColor1" /> <option id="color1" type="app::Color" default="app::Color::fromRgb(128, 128, 128)" migrate="Option.CheckedBgColor1" />
<option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" /> <option id="color2" type="app::Color" default="app::Color::fromRgb(192, 192, 192)" migrate="Option.CheckedBgColor2" />
</section> </section>
<section id="timeline">
<option id="first_frame" type="int" default="1" />
</section>
<section id="thumbnails"> <section id="thumbnails">
<option id="zoom" type="double" default="1" /> <option id="zoom" type="double" default="1" />
<option id="enabled" type="bool" default="false" /> <option id="enabled" type="bool" default="false" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -0,0 +1,22 @@
<!-- ASEPRITE -->
<!-- Copyright (C) 2016 by David Capello -->
<gui>
<window text="Notice" id="open_sequence">
<vbox>
<label text="Do you want to load the following files as an animation?" />
<view expansive="true" id="view" minwidth="128" minheight="64">
<listbox id="files" multiselect="true" />
</view>
<separator horizontal="true" />
<check id="repeat" text="Do the same for other files" />
<hbox>
<boxfiller />
<hbox homogeneous="true">
<button id="agree" text="&amp;Agree" closewindow="true" minwidth="60" />
<button id="skip" text="&amp;Skip" closewindow="true" minwidth="60" magnet="true" />
</hbox>
<boxfiller />
</hbox>
</vbox>
</window>
</gui>

View File

@ -43,6 +43,9 @@
<hbox> <hbox>
<check text="Automatically save recovery data every" id="enable_data_recovery" tooltip="With this option you can recover your documents&#10;if the program finalizes unexpectedly." /> <check text="Automatically save recovery data every" id="enable_data_recovery" tooltip="With this option you can recover your documents&#10;if the program finalizes unexpectedly." />
<combobox id="data_recovery_period"> <combobox id="data_recovery_period">
<listitem text="10 seconds" value="0.33" />
<listitem text="30 seconds" value="0.5" />
<listitem text="1 Minutes" value="1" />
<listitem text="2 Minutes" value="2" /> <listitem text="2 Minutes" value="2" />
<listitem text="5 Minutes" value="5" /> <listitem text="5 Minutes" value="5" />
<listitem text="10 Minutes" value="10" /> <listitem text="10 Minutes" value="10" />
@ -79,6 +82,10 @@
<separator text="Timeline" horizontal="true" /> <separator text="Timeline" horizontal="true" />
<check text="Show timeline automatically" id="autotimeline" tooltip="Show the timeline automatically&#10;when a new frame or layer is added." /> <check text="Show timeline automatically" id="autotimeline" tooltip="Show the timeline automatically&#10;when a new frame or layer is added." />
<check text="Rewind on Stop" id="rewind_on_stop" tooltip="The 'Stop' button should rewind the animation&#10;where it was started." /> <check text="Rewind on Stop" id="rewind_on_stop" tooltip="The 'Stop' button should rewind the animation&#10;where it was started." />
<hbox>
<label text="Default First Frame:" />
<entry id="first_frame" maxsize="3" />
</hbox>
</vbox> </vbox>
<!-- Cursors --> <!-- Cursors -->

View File

@ -1,13 +1,13 @@
<!-- ASEPRITE --> <!-- ASEPRITE -->
<!-- Copyright (C) 2014 by David Capello --> <!-- Copyright (C) 2014-2016 by David Capello -->
<gui> <gui>
<vbox id="palette_popup"> <vbox id="palette_popup">
<label text="Available Palettes:" /> <label text="Available Palettes:" />
<view id="view" expansive="true" /> <view id="view" expansive="true" />
<hbox> <hbox>
<button id="load_pal" text="Load" width="80" /> <button id="load_pal" text="&amp;Load" width="80" magnet="true" />
<hbox expansive="true" /> <hbox expansive="true" />
<button id="open_folder" text="Open Folder" width="60" /> <button id="open_folder" text="Open &amp;Folder" width="60" />
</hbox> </hbox>
</vbox> </vbox>
</gui> </gui>

View File

@ -2,30 +2,35 @@
<!-- Copyright (C) 2014-2016 by David Capello --> <!-- Copyright (C) 2014-2016 by David Capello -->
<gui> <gui>
<vbox id="timeline_conf"> <vbox id="timeline_conf">
<hbox> <hbox>
<vbox> <vbox>
<separator cell_hspan="2" text="Position:" left="true" horizontal="true" /> <separator cell_hspan="2" text="Position:" left="true" horizontal="true" />
<hbox> <hbox>
<buttonset columns="2" id="position"> <buttonset columns="2" id="position">
<item text="&amp;Left" /> <item text="&amp;Left" />
<item text="&amp;Right" /> <item text="&amp;Right" />
<item text="&amp;Bottom" hspan="2" /> <item text="&amp;Bottom" hspan="2" />
</buttonset> </buttonset>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox>
<separator cell_hspan="2" text="Thumbnails:" left="true" horizontal="true" /> <separator cell_hspan="2" text="Frame Header:" left="true" horizontal="true" />
<grid columns="3"> <hbox>
<check id="thumb_enabled" text="Force" /> <label text="First Frame:" />
<label text="Zoom:" /> <entry id="first_frame" maxsize="3" />
<slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" /> </hbox>
<check id="thumb_overlay_enabled" text="Overlay"/> <separator cell_hspan="2" text="Thumbnails:" left="true" horizontal="true" />
<label text="Size:" /> <grid columns="3">
<slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" /> <check id="thumb_enabled" text="Force" />
</grid> <label text="Zoom:" />
</vbox> <slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" />
<check id="thumb_overlay_enabled" text="Overlay"/>
<label text="Size:" />
<slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" />
</grid>
</vbox>
</hbox> </hbox>
<separator cell_hspan="2" text="Onion Skin:" left="true" horizontal="true" /> <separator cell_hspan="2" text="Onion Skin:" left="true" horizontal="true" />

2
laf

@ -1 +1 @@
Subproject commit 11274341a6390f9dda085256f98567156aa21cc9 Subproject commit 42ad03a9a30ebe619674aaf07ef27cf442133903

View File

@ -97,10 +97,14 @@ add_subdirectory(gfx)
add_subdirectory(net) add_subdirectory(net)
add_subdirectory(render) add_subdirectory(render)
add_subdirectory(docio) add_subdirectory(docio)
add_subdirectory(script)
add_subdirectory(she) add_subdirectory(she)
add_subdirectory(ui) add_subdirectory(ui)
if(ENABLE_SCRIPTING)
add_subdirectory(script)
add_definitions(-DENABLE_SCRIPTING)
endif()
if(ENABLE_UPDATER) if(ENABLE_UPDATER)
add_subdirectory(updater) add_subdirectory(updater)
endif() endif()

View File

@ -89,6 +89,23 @@ if(WITH_WEBP_SUPPORT)
list(APPEND file_formats file/webp_format.cpp) list(APPEND file_formats file/webp_format.cpp)
endif() endif()
set(scripting_files)
if(ENABLE_SCRIPTING)
set(scripting_files
commands/cmd_developer_console.cpp
commands/cmd_run_script.cpp
script/app_object.cpp
script/app_scripting.cpp
script/console_object.cpp
script/image_class.cpp
script/image_wrap.cpp
script/selection_class.cpp
script/sprite_class.cpp
script/sprite_wrap.cpp
shell.cpp
ui/devconsole_view.cpp)
endif()
add_library(app-lib add_library(app-lib
app.cpp app.cpp
app_brushes.cpp app_brushes.cpp
@ -191,7 +208,6 @@ add_library(app-lib
commands/cmd_crop.cpp commands/cmd_crop.cpp
commands/cmd_cut.cpp commands/cmd_cut.cpp
commands/cmd_deselect_mask.cpp commands/cmd_deselect_mask.cpp
commands/cmd_developer_console.cpp
commands/cmd_discard_brush.cpp commands/cmd_discard_brush.cpp
commands/cmd_duplicate_layer.cpp commands/cmd_duplicate_layer.cpp
commands/cmd_duplicate_sprite.cpp commands/cmd_duplicate_sprite.cpp
@ -253,7 +269,6 @@ add_library(app-lib
commands/cmd_reselect_mask.cpp commands/cmd_reselect_mask.cpp
commands/cmd_reverse_frames.cpp commands/cmd_reverse_frames.cpp
commands/cmd_rotate.cpp commands/cmd_rotate.cpp
commands/cmd_run_script.cpp
commands/cmd_save_file.cpp commands/cmd_save_file.cpp
commands/cmd_save_mask.cpp commands/cmd_save_mask.cpp
commands/cmd_save_palette.cpp commands/cmd_save_palette.cpp
@ -332,17 +347,8 @@ add_library(app-lib
resource_finder.cpp resource_finder.cpp
restore_visible_layers.cpp restore_visible_layers.cpp
rw_lock.cpp rw_lock.cpp
script/app_object.cpp
script/app_scripting.cpp
script/console_object.cpp
script/image_class.cpp
script/image_wrap.cpp
script/selection_class.cpp
script/sprite_class.cpp
script/sprite_wrap.cpp
send_crash.cpp send_crash.cpp
shade.cpp shade.cpp
shell.cpp
snap_to_grid.cpp snap_to_grid.cpp
thumbnail_generator.cpp thumbnail_generator.cpp
tools/active_tool.cpp tools/active_tool.cpp
@ -371,7 +377,6 @@ add_library(app-lib
ui/color_wheel.cpp ui/color_wheel.cpp
ui/configure_timeline_popup.cpp ui/configure_timeline_popup.cpp
ui/context_bar.cpp ui/context_bar.cpp
ui/devconsole_view.cpp
ui/document_view.cpp ui/document_view.cpp
ui/drop_down_button.cpp ui/drop_down_button.cpp
ui/editor/brush_preview.cpp ui/editor/brush_preview.cpp
@ -455,6 +460,7 @@ add_library(app-lib
xml_document.cpp xml_document.cpp
xml_exception.cpp xml_exception.cpp
${data_recovery_files} ${data_recovery_files}
${scripting_files}
${generated_files}) ${generated_files})
target_link_libraries(app-lib target_link_libraries(app-lib
@ -470,7 +476,6 @@ target_link_libraries(app-lib
gfx-lib gfx-lib
net-lib net-lib
render-lib render-lib
script-lib
she she
ui-lib ui-lib
undo undo
@ -482,6 +487,10 @@ target_link_libraries(app-lib
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
${FREETYPE_LIBRARIES}) ${FREETYPE_LIBRARIES})
if(ENABLE_SCRIPTING)
target_link_libraries(app-lib script-lib)
endif()
if(ENABLE_UPDATER) if(ENABLE_UPDATER)
target_link_libraries(app-lib updater-lib) target_link_libraries(app-lib updater-lib)
endif() endif()

View File

@ -32,9 +32,7 @@
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/recent_files.h" #include "app/recent_files.h"
#include "app/resource_finder.h" #include "app/resource_finder.h"
#include "app/script/app_scripting.h"
#include "app/send_crash.h" #include "app/send_crash.h"
#include "app/shell.h"
#include "app/tools/active_tool.h" #include "app/tools/active_tool.h"
#include "app/tools/tool_box.h" #include "app/tools/tool_box.h"
#include "app/ui/backup_indicator.h" #include "app/ui/backup_indicator.h"
@ -58,7 +56,7 @@
#include "base/unique_ptr.h" #include "base/unique_ptr.h"
#include "doc/site.h" #include "doc/site.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "script/engine_delegate.h" #include "render/render.h"
#include "she/display.h" #include "she/display.h"
#include "she/error.h" #include "she/error.h"
#include "she/system.h" #include "she/system.h"
@ -67,6 +65,12 @@
#include <iostream> #include <iostream>
#ifdef ENABLE_SCRIPTING
#include "app/script/app_scripting.h"
#include "app/shell.h"
#include "script/engine_delegate.h"
#endif
#ifdef ENABLE_STEAM #ifdef ENABLE_STEAM
#include "steam/steam.h" #include "steam/steam.h"
#endif #endif
@ -258,6 +262,7 @@ void App::run()
ui::Manager::getDefault()->run(); ui::Manager::getDefault()->run();
} }
#ifdef ENABLE_SCRIPTING
// Start shell to execute scripts. // Start shell to execute scripts.
if (m_isShell) { if (m_isShell) {
script::StdoutEngineDelegate delegate; script::StdoutEngineDelegate delegate;
@ -266,6 +271,7 @@ void App::run()
Shell shell; Shell shell;
shell.run(engine); shell.run(engine);
} }
#endif
// Destroy all documents in the UIContext. // Destroy all documents in the UIContext.
const doc::Documents& docs = m_modules->m_ui_context.documents(); const doc::Documents& docs = m_modules->m_ui_context.documents();

View File

@ -26,7 +26,9 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_showHelp(false) , m_showHelp(false)
, m_showVersion(false) , m_showVersion(false)
, m_verboseLevel(kNoVerbose) , m_verboseLevel(kNoVerbose)
#ifdef ENABLE_SCRIPTING
, m_shell(m_po.add("shell").description("Start an interactive console to execute scripts")) , m_shell(m_po.add("shell").description("Start an interactive console to execute scripts"))
#endif
, m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI")) , m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI"))
, m_preview(m_po.add("preview").mnemonic('p').description("Do not execute actions, just print what will be\ndone")) , m_preview(m_po.add("preview").mnemonic('p').description("Do not execute actions, just print what will be\ndone"))
, m_saveAs(m_po.add("save-as").requiresValue("<filename>").description("Save the last given sprite with other format")) , m_saveAs(m_po.add("save-as").requiresValue("<filename>").description("Save the last given sprite with other format"))
@ -54,7 +56,9 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_trim(m_po.add("trim").description("Trim all images before exporting")) , m_trim(m_po.add("trim").description("Trim all images before exporting"))
, m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle")) , m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle"))
, m_filenameFormat(m_po.add("filename-format").requiresValue("<fmt>").description("Special format to generate filenames")) , m_filenameFormat(m_po.add("filename-format").requiresValue("<fmt>").description("Special format to generate filenames"))
#ifdef ENABLE_SCRIPTING
, m_script(m_po.add("script").requiresValue("<filename>").description("Execute a specific script")) , m_script(m_po.add("script").requiresValue("<filename>").description("Execute a specific script"))
#endif
, m_listLayers(m_po.add("list-layers").description("List layers of the next given sprite\nor include layers in JSON data")) , m_listLayers(m_po.add("list-layers").description("List layers of the next given sprite\nor include layers in JSON data"))
, m_listTags(m_po.add("list-tags").description("List tags of the next given sprite sprite\nor include frame tags in JSON data")) , m_listTags(m_po.add("list-tags").description("List tags of the next given sprite sprite\nor include frame tags in JSON data"))
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done")) , m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
@ -70,7 +74,9 @@ AppOptions::AppOptions(int argc, const char* argv[])
else if (m_po.enabled(m_verbose)) else if (m_po.enabled(m_verbose))
m_verboseLevel = kVerbose; m_verboseLevel = kVerbose;
#ifdef ENABLE_SCRIPTING
m_startShell = m_po.enabled(m_shell); m_startShell = m_po.enabled(m_shell);
#endif
m_previewCLI = m_po.enabled(m_preview); m_previewCLI = m_po.enabled(m_preview);
m_showHelp = m_po.enabled(m_help); m_showHelp = m_po.enabled(m_help);
m_showVersion = m_po.enabled(m_version); m_showVersion = m_po.enabled(m_version);

View File

@ -70,7 +70,9 @@ public:
const Option& trim() const { return m_trim; } const Option& trim() const { return m_trim; }
const Option& crop() const { return m_crop; } const Option& crop() const { return m_crop; }
const Option& filenameFormat() const { return m_filenameFormat; } const Option& filenameFormat() const { return m_filenameFormat; }
#ifdef ENABLE_SCRIPTING
const Option& script() const { return m_script; } const Option& script() const { return m_script; }
#endif
const Option& listLayers() const { return m_listLayers; } const Option& listLayers() const { return m_listLayers; }
const Option& listTags() const { return m_listTags; } const Option& listTags() const { return m_listTags; }
@ -86,7 +88,9 @@ private:
bool m_showVersion; bool m_showVersion;
VerboseLevel m_verboseLevel; VerboseLevel m_verboseLevel;
#ifdef ENABLE_SCRIPTING
Option& m_shell; Option& m_shell;
#endif
Option& m_batch; Option& m_batch;
Option& m_preview; Option& m_preview;
Option& m_saveAs; Option& m_saveAs;
@ -114,7 +118,9 @@ private:
Option& m_trim; Option& m_trim;
Option& m_crop; Option& m_crop;
Option& m_filenameFormat; Option& m_filenameFormat;
#ifdef ENABLE_SCRIPTING
Option& m_script; Option& m_script;
#endif
Option& m_listLayers; Option& m_listLayers;
Option& m_listTags; Option& m_listTags;

View File

@ -353,11 +353,13 @@ void CliProcessor::process()
} }
} }
} }
#ifdef ENABLE_SCRIPTING
// --script <filename> // --script <filename>
else if (opt == &m_options.script()) { else if (opt == &m_options.script()) {
std::string filename = value.value(); std::string filename = value.value();
m_delegate->execScript(filename); m_delegate->execScript(filename);
} }
#endif
// --list-layers // --list-layers
else if (opt == &m_options.listLayers()) { else if (opt == &m_options.listLayers()) {
cof.listLayers = true; cof.listLayers = true;

View File

@ -18,14 +18,17 @@
#include "app/document.h" #include "app/document.h"
#include "app/document_exporter.h" #include "app/document_exporter.h"
#include "app/file/palette_file.h" #include "app/file/palette_file.h"
#include "app/script/app_scripting.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "base/convert_to.h" #include "base/convert_to.h"
#include "doc/frame_tag.h" #include "doc/frame_tag.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "script/engine_delegate.h"
#ifdef ENABLE_SCRIPTING
#include "app/script/app_scripting.h"
#include "script/engine_delegate.h"
#endif
#include <iostream> #include <iostream>
@ -114,9 +117,11 @@ void DefaultCliDelegate::exportFiles(DocumentExporter& exporter)
void DefaultCliDelegate::execScript(const std::string& filename) void DefaultCliDelegate::execScript(const std::string& filename)
{ {
#ifdef ENABLE_SCRIPTING
script::StdoutEngineDelegate delegate; script::StdoutEngineDelegate delegate;
AppScripting engine(&delegate); AppScripting engine(&delegate);
engine.evalFile(filename); engine.evalFile(filename);
#endif
} }
} // namespace app } // namespace app

View File

@ -86,7 +86,7 @@ void AddLayer::removeLayer(Layer* group, Layer* layer)
static_cast<LayerGroup*>(group)->removeLayer(layer); static_cast<LayerGroup*>(group)->removeLayer(layer);
group->incrementVersion(); group->incrementVersion();
layer->sprite()->incrementVersion(); group->sprite()->incrementVersion();
doc->notify_observers<DocumentEvent&>(&DocumentObserver::onAfterRemoveLayer, ev); doc->notify_observers<DocumentEvent&>(&DocumentObserver::onAfterRemoveLayer, ev);

View File

@ -8,6 +8,10 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/app.h" #include "app/app.h"
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/ui/main_window.h" #include "app/ui/main_window.h"

View File

@ -13,6 +13,7 @@
#include "app/commands/commands.h" #include "app/commands/commands.h"
#include "app/context.h" #include "app/context.h"
#include "app/document.h" #include "app/document.h"
#include "app/job.h"
#include "app/ui/main_window.h" #include "app/ui/main_window.h"
#include "ui/alert.h" #include "ui/alert.h"
@ -36,6 +37,11 @@ ExitCommand::ExitCommand()
void ExitCommand::onExecute(Context* ctx) void ExitCommand::onExecute(Context* ctx)
{ {
// Ignore ExitCommand when we are saving documents or doing a
// background task
if (Job::runningJobs() > 0)
return;
if (ctx->hasModifiedDocuments()) { if (ctx->hasModifiedDocuments()) {
Command* closeAll = CommandsModule::instance()->getCommandByName(CommandId::CloseAllFiles); Command* closeAll = CommandsModule::instance()->getCommandByName(CommandId::CloseAllFiles);
Params params; Params params;

View File

@ -9,11 +9,12 @@
#endif #endif
#include "app/app.h" #include "app/app.h"
#include "app/context.h"
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/commands/params.h" #include "app/commands/params.h"
#include "app/context.h"
#include "app/context_access.h" #include "app/context_access.h"
#include "app/document_api.h" #include "app/document_api.h"
#include "app/pref/preferences.h"
#include "app/transaction.h" #include "app/transaction.h"
#include "base/convert_to.h" #include "base/convert_to.h"
#include "doc/sprite.h" #include "doc/sprite.h"
@ -66,7 +67,7 @@ void FramePropertiesCommand::onLoadParams(const Params& params)
} }
else { else {
m_target = SPECIFIC_FRAME; m_target = SPECIFIC_FRAME;
m_frame = frame_t(base::convert_to<int>(frame)-1); m_frame = frame_t(base::convert_to<int>(frame));
} }
} }
@ -79,7 +80,8 @@ void FramePropertiesCommand::onExecute(Context* context)
{ {
const ContextReader reader(context); const ContextReader reader(context);
const Sprite* sprite = reader.sprite(); const Sprite* sprite = reader.sprite();
auto& docPref = Preferences::instance().document(context->activeDocument());
int base = docPref.timeline.firstFrame();
app::gen::FrameProperties window; app::gen::FrameProperties window;
SelectedFrames selFrames; SelectedFrames selFrames;
@ -101,7 +103,7 @@ void FramePropertiesCommand::onExecute(Context* context)
} }
case SPECIFIC_FRAME: case SPECIFIC_FRAME:
selFrames.insert(m_frame); selFrames.insert(m_frame-base);
break; break;
} }
@ -110,11 +112,11 @@ void FramePropertiesCommand::onExecute(Context* context)
return; return;
if (selFrames.size() == 1) if (selFrames.size() == 1)
window.frame()->setTextf("%d", selFrames.firstFrame()+1); window.frame()->setTextf("%d", selFrames.firstFrame()+base);
else if (selFrames.ranges() == 1) { else if (selFrames.ranges() == 1) {
window.frame()->setTextf("[%d...%d]", window.frame()->setTextf("[%d...%d]",
selFrames.firstFrame()+1, selFrames.firstFrame()+base,
selFrames.lastFrame()+1); selFrames.lastFrame()+base);
} }
else else
window.frame()->setTextf("Multiple Frames"); window.frame()->setTextf("Multiple Frames");

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -137,22 +137,27 @@ class GotoFrameCommand : public GotoCommand {
public: public:
GotoFrameCommand() : GotoCommand("GotoFrame", GotoFrameCommand() : GotoCommand("GotoFrame",
"Go to Frame") "Go to Frame")
, m_frame(0) { } , m_showUI(true) { }
Command* clone() const override { return new GotoFrameCommand(*this); } Command* clone() const override { return new GotoFrameCommand(*this); }
protected: protected:
void onLoadParams(const Params& params) override { void onLoadParams(const Params& params) override {
std::string frame = params.get("frame"); std::string frame = params.get("frame");
if (!frame.empty()) m_frame = strtol(frame.c_str(), NULL, 10); if (!frame.empty()) {
else m_frame = 0; m_frame = strtol(frame.c_str(), nullptr, 10);
m_showUI = false;
}
else
m_showUI = true;
} }
frame_t onGetFrame(Editor* editor) override { frame_t onGetFrame(Editor* editor) override {
if (m_frame == 0) { auto& docPref = editor->docPref();
if (m_showUI) {
app::gen::GotoFrame window; app::gen::GotoFrame window;
window.frame()->setTextf(
window.frame()->setTextf("%d", editor->frame()+1); "%d", editor->frame()+docPref.timeline.firstFrame());
window.openWindowInForeground(); window.openWindowInForeground();
if (window.closer() != window.ok()) if (window.closer() != window.ok())
return editor->frame(); return editor->frame();
@ -160,12 +165,11 @@ protected:
m_frame = window.frame()->textInt(); m_frame = window.frame()->textInt();
} }
return MID(0, m_frame-1, editor->sprite()->lastFrame()); return MID(0, m_frame-docPref.timeline.firstFrame(), editor->sprite()->lastFrame());
} }
private: private:
// The frame to go. 0 is "show the UI dialog", another value is the bool m_showUI;
// frame (1 is the first name for the user).
int m_frame; int m_frame;
}; };

View File

@ -62,7 +62,7 @@ public:
KeyItem(const std::string& text, Key* key, AppMenuItem* menuitem, int level) KeyItem(const std::string& text, Key* key, AppMenuItem* menuitem, int level)
: ListItem(text) : ListItem(text)
, m_key(key) , m_key(key)
, m_keyOrig(key ? new Key(*key): NULL) , m_keyOrig(key ? new Key(*key): nullptr)
, m_menuitem(menuitem) , m_menuitem(menuitem)
, m_level(level) , m_level(level)
, m_hotAccel(-1) , m_hotAccel(-1)
@ -73,6 +73,10 @@ public:
setBorder(border); setBorder(border);
} }
~KeyItem() {
delete m_keyOrig;
}
Key* key() { return m_key; } Key* key() { return m_key; }
AppMenuItem* menuitem() const { return m_menuitem; } AppMenuItem* menuitem() const { return m_menuitem; }
@ -381,6 +385,10 @@ public:
} }
} }
~KeyboardShortcutsWindow() {
deleteAllKeyItems();
}
void restoreKeys() { void restoreKeys() {
for (KeyItem* keyItem : m_allKeyItems) { for (KeyItem* keyItem : m_allKeyItems) {
keyItem->restoreKeys(); keyItem->restoreKeys();
@ -389,21 +397,12 @@ public:
private: private:
void deleteAllKeyItems() { void deleteAllKeyItems() {
while (searchList()->lastChild()) deleteList(searchList());
searchList()->removeChild(searchList()->lastChild()); deleteList(menus());
while (menus()->lastChild()) deleteList(commands());
menus()->removeChild(menus()->lastChild()); deleteList(tools());
while (commands()->lastChild()) deleteList(actions());
commands()->removeChild(commands()->lastChild()); ASSERT(m_allKeyItems.empty());
while (tools()->lastChild())
tools()->removeChild(tools()->lastChild());
while (actions()->lastChild())
actions()->removeChild(actions()->lastChild());
for (KeyItem* keyItem : m_allKeyItems) {
delete keyItem;
}
m_allKeyItems.clear();
} }
void fillAllLists() { void fillAllLists() {
@ -468,9 +467,21 @@ private:
updateViews(); updateViews();
} }
void deleteList(Widget* listbox) {
while (listbox->lastChild()) {
Widget* item = listbox->lastChild();
listbox->removeChild(item);
auto it = std::find(m_allKeyItems.begin(), m_allKeyItems.end(), item);
if (it != m_allKeyItems.end())
m_allKeyItems.erase(it);
delete item;
}
}
void fillSearchList(const std::string& search) { void fillSearchList(const std::string& search) {
while (searchList()->lastChild()) deleteList(searchList());
searchList()->removeChild(searchList()->lastChild());
std::vector<std::string> parts; std::vector<std::string> parts;
base::split_string(base::string_to_lower(search), parts, " "); base::split_string(base::string_to_lower(search), parts, " ");
@ -504,6 +515,8 @@ private:
new KeyItem(itemText, new KeyItem(itemText,
keyItem->key(), keyItem->key(),
keyItem->menuitem(), 0); keyItem->menuitem(), 0);
m_allKeyItems.push_back(copyItem);
searchList()->addChild(copyItem); searchList()->addChild(copyItem);
} }
} }
@ -586,6 +599,7 @@ private:
menuItem->text().c_str(), menuItem->text().c_str(),
menuItem->key(), menuItem, level); menuItem->key(), menuItem, level);
m_allKeyItems.push_back(keyItem);
listbox->addChild(keyItem); listbox->addChild(keyItem);
if (menuItem->hasSubmenu()) if (menuItem->hasSubmenu())

View File

@ -8,6 +8,8 @@
#include "config.h" #include "config.h"
#endif #endif
#include "app/commands/cmd_open_file.h"
#include "app/app.h" #include "app/app.h"
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/commands/params.h" #include "app/commands/params.h"
@ -32,22 +34,7 @@
namespace app { namespace app {
class OpenFileCommand : public Command { class OpenFileJob : public Job, public IFileOpProgress {
public:
OpenFileCommand();
Command* clone() const override { return new OpenFileCommand(*this); }
protected:
void onLoadParams(const Params& params) override;
void onExecute(Context* context) override;
private:
std::string m_filename;
std::string m_folder;
};
class OpenFileJob : public Job, public IFileOpProgress
{
public: public:
OpenFileJob(FileOp* fop) OpenFileJob(FileOp* fop)
: Job("Loading file") : Job("Loading file")
@ -91,6 +78,8 @@ OpenFileCommand::OpenFileCommand()
: Command("OpenFile", : Command("OpenFile",
"Open Sprite", "Open Sprite",
CmdRecordableFlag) CmdRecordableFlag)
, m_repeatCheckbox(false)
, m_seqDecision(SequenceDecision::Ask)
{ {
} }
@ -98,12 +87,15 @@ void OpenFileCommand::onLoadParams(const Params& params)
{ {
m_filename = params.get("filename"); m_filename = params.get("filename");
m_folder = params.get("folder"); // Initial folder m_folder = params.get("folder"); // Initial folder
m_repeatCheckbox = (params.get("repeat_checkbox") == "true");
} }
void OpenFileCommand::onExecute(Context* context) void OpenFileCommand::onExecute(Context* context)
{ {
Console console; Console console;
m_usedFiles.clear();
// interactive // interactive
if (context->isUIAvailable() && m_filename.empty()) { if (context->isUIAvailable() && m_filename.empty()) {
std::string exts = get_readable_extensions(); std::string exts = get_readable_extensions();
@ -118,9 +110,23 @@ void OpenFileCommand::onExecute(Context* context)
} }
if (!m_filename.empty()) { if (!m_filename.empty()) {
int flags = (m_repeatCheckbox ? FILE_LOAD_SEQUENCE_ASK_CHECKBOX: 0);
switch (m_seqDecision) {
case SequenceDecision::Ask:
flags |= FILE_LOAD_SEQUENCE_ASK;
break;
case SequenceDecision::Agree:
flags |= FILE_LOAD_SEQUENCE_YES;
break;
case SequenceDecision::Skip:
flags |= FILE_LOAD_SEQUENCE_NONE;
break;
}
base::UniquePtr<FileOp> fop( base::UniquePtr<FileOp> fop(
FileOp::createLoadDocumentOperation( FileOp::createLoadDocumentOperation(
context, m_filename.c_str(), FILE_LOAD_SEQUENCE_ASK)); context, m_filename.c_str(), flags));
bool unrecent = false; bool unrecent = false;
if (fop) { if (fop) {
@ -129,6 +135,21 @@ void OpenFileCommand::onExecute(Context* context)
unrecent = true; unrecent = true;
} }
else { else {
if (fop->isSequence()) {
if (fop->sequenceFlags() & FILE_LOAD_SEQUENCE_YES) {
m_seqDecision = SequenceDecision::Agree;
}
else if (fop->sequenceFlags() & FILE_LOAD_SEQUENCE_NONE) {
m_seqDecision = SequenceDecision::Skip;
}
m_usedFiles = fop->filenames();
}
else {
m_usedFiles.push_back(fop->filename());
}
OpenFileJob task(fop); OpenFileJob task(fop);
task.showProgressWindow(); task.showProgressWindow();
@ -136,7 +157,7 @@ void OpenFileCommand::onExecute(Context* context)
fop->postLoad(); fop->postLoad();
// Show any error // Show any error
if (fop->hasError()) if (fop->hasError() && !fop->isStop())
console.printf(fop->error().c_str()); console.printf(fop->error().c_str());
Document* document = fop->document(); Document* document = fop->document();

View File

@ -0,0 +1,53 @@
// Aseprite
// Copyright (C) 2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_COMMANDS_CMD_OPEN_FILE_H_INCLUDED
#define APP_COMMANDS_CMD_OPEN_FILE_H_INCLUDED
#pragma once
#include "app/commands/command.h"
#include <string>
#include <vector>
namespace app {
class OpenFileCommand : public Command {
public:
enum class SequenceDecision {
Ask, Agree, Skip,
};
OpenFileCommand();
Command* clone() const override { return new OpenFileCommand(*this); }
SequenceDecision sequenceDecision() const {
return m_seqDecision;
}
void setSequenceDecision(SequenceDecision seqDecision) {
m_seqDecision = seqDecision;
}
const std::vector<std::string>& usedFiles() const {
return m_usedFiles;
}
protected:
void onLoadParams(const Params& params) override;
void onExecute(Context* context) override;
private:
std::string m_filename;
std::string m_folder;
bool m_repeatCheckbox;
std::vector<std::string> m_usedFiles;
SequenceDecision m_seqDecision;
};
} // namespace app
#endif

View File

@ -109,6 +109,8 @@ public:
if (m_pref.general.rewindOnStop()) if (m_pref.general.rewindOnStop())
rewindOnStop()->setSelected(true); rewindOnStop()->setSelected(true);
firstFrame()->setTextf("%d", m_globPref.timeline.firstFrame());
if (m_pref.general.expandMenubarOnMouseover()) if (m_pref.general.expandMenubarOnMouseover())
expandMenubarOnMouseover()->setSelected(true); expandMenubarOnMouseover()->setSelected(true);
@ -158,9 +160,9 @@ public:
showScrollbars()->setSelected(true); showScrollbars()->setSelected(true);
// Scope // Scope
gridScope()->addItem("Global"); gridScope()->addItem("New Documents");
if (context->activeDocument()) { if (context->activeDocument()) {
gridScope()->addItem("Current Document"); gridScope()->addItem("Active Document");
gridScope()->setSelectedItemIndex(1); gridScope()->setSelectedItemIndex(1);
gridScope()->Change.connect(base::Bind<void>(&OptionsWindow::onChangeGridScope, this)); gridScope()->Change.connect(base::Bind<void>(&OptionsWindow::onChangeGridScope, this));
} }
@ -244,6 +246,7 @@ public:
void saveConfig() { void saveConfig() {
m_pref.general.autoshowTimeline(autotimeline()->isSelected()); m_pref.general.autoshowTimeline(autotimeline()->isSelected());
m_pref.general.rewindOnStop(rewindOnStop()->isSelected()); m_pref.general.rewindOnStop(rewindOnStop()->isSelected());
m_globPref.timeline.firstFrame(firstFrame()->textInt());
m_pref.general.showFullPath(showFullPath()->isSelected()); m_pref.general.showFullPath(showFullPath()->isSelected());
bool expandOnMouseover = expandMenubarOnMouseover()->isSelected(); bool expandOnMouseover = expandMenubarOnMouseover()->isSelected();
@ -252,7 +255,7 @@ public:
std::string warnings; std::string warnings;
int newPeriod = base::convert_to<int>(dataRecoveryPeriod()->getValue()); double newPeriod = base::convert_to<double>(dataRecoveryPeriod()->getValue());
if (enableDataRecovery()->isSelected() != m_pref.general.dataRecovery() || if (enableDataRecovery()->isSelected() != m_pref.general.dataRecovery() ||
newPeriod != m_pref.general.dataRecoveryPeriod()) { newPeriod != m_pref.general.dataRecoveryPeriod()) {
m_pref.general.dataRecovery(enableDataRecovery()->isSelected()); m_pref.general.dataRecovery(enableDataRecovery()->isSelected());

View File

@ -251,10 +251,10 @@ PaletteEntryEditor::PaletteEntryEditor()
, m_selfPalChange(false) , m_selfPalChange(false)
, m_fromPalette(0, 0) , m_fromPalette(0, 0)
{ {
m_colorType.addItem("RGB"); m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB"); m_colorType.addItem("HSB")->setFocusStop(false);
m_changeMode.addItem("Abs"); m_changeMode.addItem("Abs")->setFocusStop(false);
m_changeMode.addItem("Rel"); m_changeMode.addItem("Rel")->setFocusStop(false);
m_topBox.setBorder(gfx::Border(0)); m_topBox.setBorder(gfx::Border(0));
m_topBox.setChildSpacing(0); m_topBox.setChildSpacing(0);

View File

@ -8,6 +8,10 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/commands/params.h" #include "app/commands/params.h"
#include "app/console.h" #include "app/console.h"

View File

@ -29,7 +29,6 @@ FOR_EACH_COMMAND(CropSprite)
FOR_EACH_COMMAND(Cut) FOR_EACH_COMMAND(Cut)
FOR_EACH_COMMAND(DeselectMask) FOR_EACH_COMMAND(DeselectMask)
FOR_EACH_COMMAND(Despeckle) FOR_EACH_COMMAND(Despeckle)
FOR_EACH_COMMAND(DeveloperConsole)
FOR_EACH_COMMAND(DiscardBrush) FOR_EACH_COMMAND(DiscardBrush)
FOR_EACH_COMMAND(DuplicateLayer) FOR_EACH_COMMAND(DuplicateLayer)
FOR_EACH_COMMAND(DuplicateSprite) FOR_EACH_COMMAND(DuplicateSprite)
@ -100,7 +99,6 @@ FOR_EACH_COMMAND(ReplaceColor)
FOR_EACH_COMMAND(ReselectMask) FOR_EACH_COMMAND(ReselectMask)
FOR_EACH_COMMAND(ReverseFrames) FOR_EACH_COMMAND(ReverseFrames)
FOR_EACH_COMMAND(Rotate) FOR_EACH_COMMAND(Rotate)
FOR_EACH_COMMAND(RunScript)
FOR_EACH_COMMAND(SaveFile) FOR_EACH_COMMAND(SaveFile)
FOR_EACH_COMMAND(SaveFileAs) FOR_EACH_COMMAND(SaveFileAs)
FOR_EACH_COMMAND(SaveFileCopyAs) FOR_EACH_COMMAND(SaveFileCopyAs)
@ -136,3 +134,8 @@ FOR_EACH_COMMAND(Undo)
FOR_EACH_COMMAND(UndoHistory) FOR_EACH_COMMAND(UndoHistory)
FOR_EACH_COMMAND(UnlinkCel) FOR_EACH_COMMAND(UnlinkCel)
FOR_EACH_COMMAND(Zoom) FOR_EACH_COMMAND(Zoom)
#ifdef ENABLE_SCRIPTING
FOR_EACH_COMMAND(DeveloperConsole)
FOR_EACH_COMMAND(RunScript)
#endif

View File

@ -8,11 +8,13 @@
#include "config.h" #include "config.h"
#endif #endif
#include <stdarg.h> #include <cstdarg>
#include <stdio.h> #include <cstdio>
#include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/memory.h" #include "base/memory.h"
#include "base/string.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "app/app.h" #include "app/app.h"
@ -106,15 +108,13 @@ Console::~Console()
void Console::printf(const char* format, ...) void Console::printf(const char* format, ...)
{ {
char buf[4096]; // TODO warning buffer overflow std::va_list ap;
va_list ap;
va_start(ap, format); va_start(ap, format);
vsprintf(buf, format, ap); std::string msg = base::string_vprintf(format, ap);
va_end(ap); va_end(ap);
if (!m_withUI || !wid_console) { if (!m_withUI || !wid_console) {
fputs(buf, stdout); fputs(msg.c_str(), stdout);
fflush(stdout); fflush(stdout);
return; return;
} }
@ -125,7 +125,7 @@ void Console::printf(const char* format, ...)
ui::Manager::getDefault()->invalidate(); ui::Manager::getDefault()->invalidate();
} }
/* update the textbox */ // Update the textbox
if (!console_locked) { if (!console_locked) {
console_locked = true; console_locked = true;
@ -142,7 +142,7 @@ void Console::printf(const char* format, ...)
std::string final; std::string final;
if (!text.empty()) if (!text.empty())
final += text; final += text;
final += buf; final += msg;
wid_textbox->setText(final.c_str()); wid_textbox->setText(final.c_str());
} }

View File

@ -82,8 +82,8 @@ void BackupObserver::onRemoveDocument(doc::Document* document)
void BackupObserver::backgroundThread() void BackupObserver::backgroundThread()
{ {
int normalPeriod = 60*Preferences::instance().general.dataRecoveryPeriod(); int normalPeriod = int(60.0*Preferences::instance().general.dataRecoveryPeriod());
int lockedPeriod = 10; int lockedPeriod = 5;
#if 0 // Just for testing purposes #if 0 // Just for testing purposes
normalPeriod = 5; normalPeriod = 5;
lockedPeriod = 5; lockedPeriod = 5;

View File

@ -32,6 +32,8 @@
#include "render/render.h" #include "render/render.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "open_sequence.xml.h"
#include <cstring> #include <cstring>
#include <cstdarg> #include <cstdarg>
@ -191,6 +193,7 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena
if (fop->m_format->support(FILE_SUPPORT_SEQUENCES)) { if (fop->m_format->support(FILE_SUPPORT_SEQUENCES)) {
/* prepare to load a sequence */ /* prepare to load a sequence */
fop->prepareForSequence(); fop->prepareForSequence();
fop->m_seq.flags = flags;
/* per now, we want load just one file */ /* per now, we want load just one file */
fop->m_seq.filename_list.push_back(filename); fop->m_seq.filename_list.push_back(filename);
@ -221,18 +224,57 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena
} }
} }
/* TODO add a better dialog to edit file-names */ // TODO add a better dialog to edit file-names
if ((flags & FILE_LOAD_SEQUENCE_ASK) && context && context->isUIAvailable()) { if ((flags & FILE_LOAD_SEQUENCE_ASK) &&
/* really want load all files? */ context &&
if ((fop->m_seq.filename_list.size() > 1) && context->isUIAvailable() &&
(ui::Alert::show("Notice" fop->m_seq.filename_list.size() > 1) {
"<<Possible animation with:" app::gen::OpenSequence window;
"<<%s, %s..." window.repeat()->setVisible(flags & FILE_LOAD_SEQUENCE_ASK_CHECKBOX ? true: false);
"<<Do you want to load the sequence of bitmaps?"
"||&Agree||&Skip",
base::get_file_name(fop->m_seq.filename_list[0]).c_str(),
base::get_file_name(fop->m_seq.filename_list[1]).c_str()) != 1)) {
for (const auto& fn : fop->m_seq.filename_list) {
auto item = new ui::ListItem(base::get_file_name(fn));
item->setSelected(true);
window.files()->addChild(item);
}
window.files()->Change.connect(
[&window]{
window.agree()->setEnabled(
window.files()->getSelectedChild() != nullptr);
});
window.openWindowInForeground();
// If the user selected the "do the same for other files"
// checkbox, we've to save what the user want to do for the
// following files.
if (window.repeat()->isSelected()) {
if (window.closer() == window.agree())
fop->m_seq.flags = FILE_LOAD_SEQUENCE_YES;
else
fop->m_seq.flags = FILE_LOAD_SEQUENCE_NONE;
}
if (window.closer() == window.agree()) {
// If the user replies "Agree", we load the selected files.
std::vector<std::string> list;
auto it = window.files()->children().begin();
auto end = window.files()->children().end();
for (const auto& fn : fop->m_seq.filename_list) {
ASSERT(it != end);
if (it == end)
break;
if ((*it)->isSelected())
list.push_back(fn);
++it;
}
ASSERT(!list.empty());
fop->m_seq.filename_list = list;
}
else {
// If the user replies "Skip", we need just one file name // If the user replies "Skip", we need just one file name
// (the first one). // (the first one).
if (fop->m_seq.filename_list.size() > 1) { if (fop->m_seq.filename_list.size() > 1) {
@ -944,6 +986,7 @@ FileOp::FileOp(FileOpType type, Context* context)
m_seq.frame = frame_t(0); m_seq.frame = frame_t(0);
m_seq.layer = nullptr; m_seq.layer = nullptr;
m_seq.last_cel = nullptr; m_seq.last_cel = nullptr;
m_seq.flags = 0;
} }
void FileOp::prepareForSequence() void FileOp::prepareForSequence()

View File

@ -22,8 +22,9 @@
// Flags for FileOp::createLoadDocumentOperation() // Flags for FileOp::createLoadDocumentOperation()
#define FILE_LOAD_SEQUENCE_NONE 0x00000001 #define FILE_LOAD_SEQUENCE_NONE 0x00000001
#define FILE_LOAD_SEQUENCE_ASK 0x00000002 #define FILE_LOAD_SEQUENCE_ASK 0x00000002
#define FILE_LOAD_SEQUENCE_YES 0x00000004 #define FILE_LOAD_SEQUENCE_ASK_CHECKBOX 0x00000004
#define FILE_LOAD_ONE_FRAME 0x00000008 #define FILE_LOAD_SEQUENCE_YES 0x00000008
#define FILE_LOAD_ONE_FRAME 0x00000010
namespace doc { namespace doc {
class Document; class Document;
@ -84,6 +85,11 @@ namespace app {
}; };
// Structure to load & save files. // Structure to load & save files.
//
// TODO This class do to many things. There should be a previous
// instance (class) to verify what the user want to do with the
// sequence of files, and the result of that operation should be the
// input of this one.
class FileOp { class FileOp {
public: public:
static FileOp* createLoadDocumentOperation(Context* context, static FileOp* createLoadDocumentOperation(Context* context,
@ -101,6 +107,7 @@ namespace app {
bool isOneFrame() const { return m_oneframe; } bool isOneFrame() const { return m_oneframe; }
const std::string& filename() const { return m_filename; } const std::string& filename() const { return m_filename; }
const std::vector<std::string>& filenames() const { return m_seq.filename_list; }
Context* context() const { return m_context; } Context* context() const { return m_context; }
Document* document() const { return m_document; } Document* document() const { return m_document; }
Document* releaseDocument() { Document* releaseDocument() {
@ -142,6 +149,9 @@ namespace app {
void sequenceSetHasAlpha(bool hasAlpha) { void sequenceSetHasAlpha(bool hasAlpha) {
m_seq.has_alpha = hasAlpha; m_seq.has_alpha = hasAlpha;
} }
int sequenceFlags() const {
return m_seq.flags;
}
const std::string& error() const { return m_error; } const std::string& error() const { return m_error; }
void setError(const char *error, ...); void setError(const char *error, ...);
@ -191,6 +201,8 @@ namespace app {
bool has_alpha; bool has_alpha;
LayerImage* layer; LayerImage* layer;
Cel* last_cel; Cel* last_cel;
// Flags after the user choose what to do with the sequence.
int flags;
} m_seq; } m_seq;
void prepareForSequence(); void prepareForSequence();

View File

@ -19,10 +19,19 @@
#include "ui/widget.h" #include "ui/widget.h"
#include "ui/window.h" #include "ui/window.h"
#include <atomic>
static const int kMonitoringPeriod = 100; static const int kMonitoringPeriod = 100;
static std::atomic<int> g_runningJobs(0);
namespace app { namespace app {
// static
int Job::runningJobs()
{
return g_runningJobs;
}
Job::Job(const char* jobName) Job::Job(const char* jobName)
{ {
m_mutex = NULL; m_mutex = NULL;
@ -60,6 +69,7 @@ Job::~Job()
void Job::startJob() void Job::startJob()
{ {
m_thread = new base::thread(&Job::thread_proc, this); m_thread = new base::thread(&Job::thread_proc, this);
++g_runningJobs;
if (m_alert_window) { if (m_alert_window) {
m_alert_window->openWindowInForeground(); m_alert_window->openWindowInForeground();
@ -93,7 +103,9 @@ void Job::waitJob()
if (m_thread) { if (m_thread) {
m_thread->join(); m_thread->join();
delete m_thread; delete m_thread;
m_thread = NULL; m_thread = nullptr;
--g_runningJobs;
} }
} }

View File

@ -24,6 +24,8 @@ namespace app {
class Job { class Job {
public: public:
static int runningJobs();
Job(const char* jobName); Job(const char* jobName);
virtual ~Job(); virtual ~Job();

View File

@ -9,6 +9,7 @@
#endif #endif
#include "app/app.h" #include "app/app.h"
#include "app/commands/cmd_open_file.h"
#include "app/commands/command.h" #include "app/commands/command.h"
#include "app/commands/commands.h" #include "app/commands/commands.h"
#include "app/commands/params.h" #include "app/commands/params.h"
@ -345,16 +346,14 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
case kDropFilesMessage: case kDropFilesMessage:
{ {
const DropFilesMessage::Files& files = static_cast<DropFilesMessage*>(msg)->files(); DropFilesMessage::Files files = static_cast<DropFilesMessage*>(msg)->files();
// Open all files
Command* cmd_open_file =
CommandsModule::instance()->getCommandByName(CommandId::OpenFile);
Params params;
UIContext* ctx = UIContext::instance(); UIContext* ctx = UIContext::instance();
OpenFileCommand cmd;
while (!files.empty()) {
auto fn = files.front();
files.erase(files.begin());
for (const auto& fn : files) {
// If the document is already open, select it. // If the document is already open, select it.
Document* doc = static_cast<Document*>(ctx->documents().getByFileName(fn)); Document* doc = static_cast<Document*>(ctx->documents().getByFileName(fn));
if (doc) { if (doc) {
@ -367,8 +366,17 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
} }
// Load the file // Load the file
else { else {
Params params;
params.set("filename", fn.c_str()); params.set("filename", fn.c_str());
ctx->executeCommand(cmd_open_file, params); params.set("repeat_checkbox", "true");
ctx->executeCommand(&cmd, params);
// Remove all used file names from the "dropped files"
for (const auto& usedFn : cmd.usedFiles()) {
auto it = std::find(files.begin(), files.end(), usedFn);
if (it != files.end())
files.erase(it);
}
} }
} }
} }
@ -376,10 +384,12 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
case kKeyDownMessage: { case kKeyDownMessage: {
#ifdef _DEBUG #ifdef _DEBUG
auto keymsg = static_cast<KeyMessage*>(msg);
// Ctrl+Shift+Q generates a crash (useful to test the anticrash feature) // Ctrl+Shift+Q generates a crash (useful to test the anticrash feature)
if (msg->ctrlPressed() && if (msg->ctrlPressed() &&
msg->shiftPressed() && msg->shiftPressed() &&
static_cast<KeyMessage*>(msg)->scancode() == kKeyQ) { keymsg->scancode() == kKeyQ) {
int* p = nullptr; int* p = nullptr;
*p = 0; *p = 0;
} }
@ -388,7 +398,7 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
// Ctrl+Shift+R recover active sprite from the backup store // Ctrl+Shift+R recover active sprite from the backup store
if (msg->ctrlPressed() && if (msg->ctrlPressed() &&
msg->shiftPressed() && msg->shiftPressed() &&
static_cast<KeyMessage*>(msg)->scancode() == kKeyR && keymsg->scancode() == kKeyR &&
App::instance()->dataRecovery() && App::instance()->dataRecovery() &&
App::instance()->dataRecovery()->activeSession() && App::instance()->dataRecovery()->activeSession() &&
current_editor && current_editor &&

View File

@ -8,6 +8,10 @@
#define APP_SCRIPTING_H_INCLUDED #define APP_SCRIPTING_H_INCLUDED
#pragma once #pragma once
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "doc/object_id.h" #include "doc/object_id.h"
#include "script/engine.h" #include "script/engine.h"

View File

@ -8,6 +8,10 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/shell.h" #include "app/shell.h"
#include "script/engine.h" #include "script/engine.h"

View File

@ -8,6 +8,10 @@
#define APP_SHELL_H_INCLUDED #define APP_SHELL_H_INCLUDED
#pragma once #pragma once
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
namespace script { namespace script {
class Engine; class Engine;
} }

View File

@ -161,10 +161,8 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
case ui::kKeyDownMessage: case ui::kKeyDownMessage:
if (isEnabled() && hasText()) { if (isEnabled() && hasText()) {
KeyMessage* keymsg = static_cast<KeyMessage*>(msg); KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
bool mnemonicPressed = bool mnemonicPressed = (msg->altPressed() &&
(msg->altPressed() && mnemonicCharPressed(keymsg));
mnemonicChar() &&
mnemonicChar() == tolower(keymsg->unicodeChar()));
if (mnemonicPressed || if (mnemonicPressed ||
(hasFocus() && keymsg->scancode() == kKeySpace)) { (hasFocus() && keymsg->scancode() == kKeySpace)) {

View File

@ -58,11 +58,11 @@ ColorPopup::ColorPopup(bool canPin)
, m_canPin(canPin) , m_canPin(canPin)
, m_disableHexUpdate(false) , m_disableHexUpdate(false)
{ {
m_colorType.addItem("Index"); m_colorType.addItem("Index")->setFocusStop(false);
m_colorType.addItem("RGB"); m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB"); m_colorType.addItem("HSB")->setFocusStop(false);
m_colorType.addItem("Gray"); m_colorType.addItem("Gray")->setFocusStop(false);
m_colorType.addItem("Mask"); m_colorType.addItem("Mask")->setFocusStop(false);
m_topBox.setBorder(gfx::Border(0)); m_topBox.setBorder(gfx::Border(0));
m_topBox.setChildSpacing(0); m_topBox.setChildSpacing(0);
@ -260,6 +260,9 @@ void ColorPopup::selectColorType(app::Color::Type type)
case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break; case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break;
} }
// Remove focus from some RGB/HSB text entry
manager()->freeFocus();
m_vbox.layout(); m_vbox.layout();
m_vbox.invalidate(); m_vbox.invalidate();
} }

View File

@ -13,10 +13,12 @@
#include "app/ui/skin/skin_slider_property.h" #include "app/ui/skin/skin_slider_property.h"
#include "app/ui/skin/skin_theme.h" #include "app/ui/skin/skin_theme.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/scoped_value.h"
#include "ui/box.h" #include "ui/box.h"
#include "ui/entry.h" #include "ui/entry.h"
#include "ui/graphics.h" #include "ui/graphics.h"
#include "ui/label.h" #include "ui/label.h"
#include "ui/message.h"
#include "ui/size_hint_event.h" #include "ui/size_hint_event.h"
#include "ui/slider.h" #include "ui/slider.h"
#include "ui/theme.h" #include "ui/theme.h"
@ -81,6 +83,104 @@ namespace {
app::Color m_color; app::Color m_color;
}; };
class ColorEntry : public Entry {
public:
ColorEntry(Slider* absSlider, Slider* relSlider)
: Entry(4, "0")
, m_absSlider(absSlider)
, m_relSlider(relSlider)
, m_recent_focus(false) {
}
private:
int minValue() const {
if (m_absSlider->isVisible())
return m_absSlider->getMinValue();
else if (m_relSlider->isVisible())
return m_relSlider->getMinValue();
else
return 0;
}
int maxValue() const {
if (m_absSlider->isVisible())
return m_absSlider->getMaxValue();
else if (m_relSlider->isVisible())
return m_relSlider->getMaxValue();
else
return 0;
}
bool onProcessMessage(Message* msg) override {
switch (msg->type()) {
case kFocusEnterMessage:
m_recent_focus = true;
break;
case kKeyDownMessage:
if (Entry::onProcessMessage(msg))
return true;
if (hasFocus()) {
int scancode = static_cast<KeyMessage*>(msg)->scancode();
switch (scancode) {
// Enter just remove the focus
case kKeyEnter:
case kKeyEnterPad:
releaseFocus();
return true;
case kKeyDown:
case kKeyUp: {
int value = textInt();
if (scancode == kKeyDown)
--value;
else
++value;
setTextf("%d", MID(minValue(), value, maxValue()));
selectAllText();
onChange();
return true;
}
}
// Process focus movement key here because if our
// CustomizedGuiManager catches this kKeyDownMessage it
// will process it as a shortcut to switch the Timeline.
//
// Note: The default ui::Manager handles focus movement
// shortcuts only for foreground windows.
// TODO maybe that should change
if (hasFocus() &&
manager()->processFocusMovementMessage(msg))
return true;
}
return false;
}
bool result = Entry::onProcessMessage(msg);
if (msg->type() == kMouseDownMessage && m_recent_focus) {
m_recent_focus = false;
selectAllText();
}
return result;
}
Slider* m_absSlider;
Slider* m_relSlider;
// TODO remove this calling setFocus() in
// Widget::onProcessMessage() instead of
// Manager::handleWindowZOrder()
bool m_recent_focus;
};
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -90,6 +190,7 @@ ColorSliders::ColorSliders()
: Widget(kGenericWidget) : Widget(kGenericWidget)
, m_grid(3, false) , m_grid(3, false)
, m_mode(Absolute) , m_mode(Absolute)
, m_lockEntry(-1)
{ {
addChild(&m_grid); addChild(&m_grid);
m_grid.setChildSpacing(0); m_grid.setChildSpacing(0);
@ -136,7 +237,7 @@ void ColorSliders::addSlider(Channel channel, const char* labelText, int min, in
Label* label = new Label(labelText); Label* label = new Label(labelText);
Slider* absSlider = new Slider(min, max, 0); Slider* absSlider = new Slider(min, max, 0);
Slider* relSlider = new Slider(min-max, max-min, 0); Slider* relSlider = new Slider(min-max, max-min, 0);
Entry* entry = new Entry(4, "0"); Entry* entry = new ColorEntry(absSlider, relSlider);
m_label.push_back(label); m_label.push_back(label);
m_absSlider.push_back(absSlider); m_absSlider.push_back(absSlider);
@ -155,6 +256,8 @@ void ColorSliders::addSlider(Channel channel, const char* labelText, int min, in
HBox* box = new HBox(); HBox* box = new HBox();
box->addChild(absSlider); box->addChild(absSlider);
box->addChild(relSlider); box->addChild(relSlider);
absSlider->setFocusStop(false);
relSlider->setFocusStop(false);
absSlider->setExpansive(true); absSlider->setExpansive(true);
relSlider->setExpansive(true); relSlider->setExpansive(true);
relSlider->setVisible(false); relSlider->setVisible(false);
@ -193,6 +296,8 @@ void ColorSliders::onSliderChange(int i)
void ColorSliders::onEntryChange(int i) void ColorSliders::onEntryChange(int i)
{ {
base::ScopedValue<int> lock(m_lockEntry, i, m_lockEntry);
// Update the slider related to the changed entry widget. // Update the slider related to the changed entry widget.
int value = m_entry[i]->textInt(); int value = m_entry[i]->textInt();
@ -220,10 +325,15 @@ void ColorSliders::onControlChange(int i)
// Updates the entry related to the changed slider widget. // Updates the entry related to the changed slider widget.
void ColorSliders::updateEntryText(int entryIndex) void ColorSliders::updateEntryText(int entryIndex)
{ {
if (m_lockEntry == entryIndex)
return;
Slider* slider = (m_mode == Absolute ? m_absSlider[entryIndex]: Slider* slider = (m_mode == Absolute ? m_absSlider[entryIndex]:
m_relSlider[entryIndex]); m_relSlider[entryIndex]);
m_entry[entryIndex]->setTextf("%d", slider->getValue()); m_entry[entryIndex]->setTextf("%d", slider->getValue());
if (m_entry[entryIndex]->hasFocus())
m_entry[entryIndex]->selectAllText();
} }
void ColorSliders::updateSlidersBgColor(const app::Color& color) void ColorSliders::updateSlidersBgColor(const app::Color& color)

View File

@ -72,6 +72,7 @@ namespace app {
std::vector<Channel> m_channel; std::vector<Channel> m_channel;
ui::Grid m_grid; ui::Grid m_grid;
Mode m_mode; Mode m_mode;
int m_lockEntry;
}; };
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -52,6 +52,7 @@ ConfigureTimelinePopup::ConfigureTimelinePopup()
addChild(m_box); addChild(m_box);
m_box->position()->ItemChange.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangePosition, this)); m_box->position()->ItemChange.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangePosition, this));
m_box->firstFrame()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangeFirstFrame, this));
m_box->merge()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangeType, this)); m_box->merge()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangeType, this));
m_box->tint()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangeType, this)); m_box->tint()->Click.connect(base::Bind<void>(&ConfigureTimelinePopup::onChangeType, this));
m_box->opacity()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onOpacity, this)); m_box->opacity()->Change.connect(base::Bind<void>(&ConfigureTimelinePopup::onOpacity, this));
@ -92,6 +93,9 @@ void ConfigureTimelinePopup::updateWidgetsFromCurrentSettings()
} }
m_box->position()->setSelectedItem(selItem, false); m_box->position()->setSelectedItem(selItem, false);
m_box->firstFrame()->setTextf(
"%d", docPref.timeline.firstFrame());
switch (docPref.onionskin.type()) { switch (docPref.onionskin.type()) {
case app::gen::OnionskinType::MERGE: case app::gen::OnionskinType::MERGE:
m_box->merge()->setSelected(true); m_box->merge()->setSelected(true);
@ -155,6 +159,12 @@ void ConfigureTimelinePopup::onChangePosition()
Preferences::instance().general.timelinePosition(newTimelinePos); Preferences::instance().general.timelinePosition(newTimelinePos);
} }
void ConfigureTimelinePopup::onChangeFirstFrame()
{
docPref().timeline.firstFrame(
m_box->firstFrame()->textInt());
}
void ConfigureTimelinePopup::onChangeType() void ConfigureTimelinePopup::onChangeType()
{ {
if (m_lockUpdates) if (m_lockUpdates)

View File

@ -33,6 +33,7 @@ namespace app {
protected: protected:
bool onProcessMessage(ui::Message* msg) override; bool onProcessMessage(ui::Message* msg) override;
void onChangePosition(); void onChangePosition();
void onChangeFirstFrame();
void onChangeType(); void onChangeType();
void onOpacity(); void onOpacity();
void onOpacityStep(); void onOpacityStep();

View File

@ -8,6 +8,10 @@
#include "config.h" #include "config.h"
#endif #endif
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/ui/devconsole_view.h" #include "app/ui/devconsole_view.h"
#include "app/app_menus.h" #include "app/app_menus.h"

View File

@ -8,6 +8,10 @@
#define APP_UI_DEVCONSOLE_VIEW_H_INCLUDED #define APP_UI_DEVCONSOLE_VIEW_H_INCLUDED
#pragma once #pragma once
#ifndef ENABLE_SCRIPTING
#error ENABLE_SCRIPTING must be defined
#endif
#include "app/script/app_scripting.h" #include "app/script/app_scripting.h"
#include "app/ui/tabs.h" #include "app/ui/tabs.h"
#include "app/ui/workspace_view.h" #include "app/ui/workspace_view.h"

View File

@ -1409,7 +1409,7 @@ bool Editor::onProcessMessage(Message* msg)
case kFocusLeaveMessage: case kFocusLeaveMessage:
// As we use keys like Space-bar as modifier, we can clear the // As we use keys like Space-bar as modifier, we can clear the
// keyboard buffer when we lost the focus. // keyboard buffer when we lost the focus.
she::clear_keyboard_buffer(); she::instance()->clearKeyboardBuffer();
break; break;
case kMouseWheelMessage: case kMouseWheelMessage:

View File

@ -232,7 +232,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
MovingCelState* newState = new MovingCelState(editor, msg, handle); MovingCelState* newState = new MovingCelState(editor, msg, handle);
editor->setState(EditorStatePtr(newState)); editor->setState(EditorStatePtr(newState));
} }
catch (const LockedDocumentException& ex) { catch (const LockedDocumentException&) {
// TODO break the background task that is locking this sprite // TODO break the background task that is locking this sprite
StatusBar::instance()->showTip(1000, StatusBar::instance()->showTip(1000,
"Sprite is used by a backup/data recovery task"); "Sprite is used by a backup/data recovery task");
@ -502,7 +502,7 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
if (sprite->totalFrames() > 1) { if (sprite->totalFrames() > 1) {
sprintf( sprintf(
buf+std::strlen(buf), " :frame: %d :clock: %d", buf+std::strlen(buf), " :frame: %d :clock: %d",
editor->frame()+1, editor->frame()+editor->docPref().timeline.firstFrame(),
sprite->frameDuration(editor->frame())); sprite->frameDuration(editor->frame()));
} }

View File

@ -113,15 +113,18 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
} }
break; break;
case WHEEL_FRAME: case WHEEL_FRAME: {
{ Command* command = nullptr;
Command* command = CommandsModule::instance()->getCommandByName
((dz < 0.0) ? CommandId::GotoNextFrame: if (dz < 0.0)
CommandId::GotoPreviousFrame); command = CommandsModule::instance()->getCommandByName(CommandId::GotoNextFrame);
if (command) else if (dz > 0.0)
UIContext::instance()->executeCommand(command); command = CommandsModule::instance()->getCommandByName(CommandId::GotoPreviousFrame);
}
if (command)
UIContext::instance()->executeCommand(command);
break; break;
}
case WHEEL_ZOOM: { case WHEEL_ZOOM: {
render::Zoom zoom = editor->zoom(); render::Zoom zoom = editor->zoom();

View File

@ -93,8 +93,6 @@ void FileList::setCurrentFolder(IFileItem* folder)
invalidate(); invalidate();
View::getView(this)->updateView(); View::getView(this)->updateView();
requestFocus();
} }
void FileList::goUp() void FileList::goUp()
@ -279,7 +277,12 @@ bool FileList::onProcessMessage(Message* msg)
View* view = View::getView(this); View* view = View::getView(this);
if (view) { if (view) {
gfx::Point scroll = view->viewScroll(); gfx::Point scroll = view->viewScroll();
scroll += static_cast<MouseMessage*>(msg)->wheelDelta() * 3*(textHeight()+4*guiscale());
if (static_cast<MouseMessage*>(msg)->preciseWheel())
scroll += static_cast<MouseMessage*>(msg)->wheelDelta();
else
scroll += static_cast<MouseMessage*>(msg)->wheelDelta() * 3*(textHeight()+4*guiscale());
view->setViewScroll(scroll); view->setViewScroll(scroll);
} }
break; break;

View File

@ -196,8 +196,8 @@ protected:
int unicode = keyMsg->unicodeChar(); int unicode = keyMsg->unicodeChar();
bool up = (msg->cmdPressed() && scancode == kKeyUp); bool up = (msg->cmdPressed() && scancode == kKeyUp);
bool enter = (msg->cmdPressed() && scancode == kKeyDown); bool enter = (msg->cmdPressed() && scancode == kKeyDown);
bool back = (msg->cmdPressed() && msg->shiftPressed() && unicode == '['); bool back = (msg->cmdPressed() && (unicode == '[' || scancode == kKeyOpenbrace));
bool forward = (msg->cmdPressed() && msg->shiftPressed() && unicode == ']'); bool forward = (msg->cmdPressed() && (unicode == ']' || scancode == kKeyClosebrace));
#else #else
bool up = (msg->altPressed() && scancode == kKeyUp); bool up = (msg->altPressed() && scancode == kKeyUp);
bool enter = (msg->altPressed() && scancode == kKeyDown); bool enter = (msg->altPressed() && scancode == kKeyDown);
@ -851,12 +851,12 @@ void FileSelector::onLocationCloseListBox()
} }
} }
if (fileItem != NULL) { if (fileItem) {
m_fileList->setCurrentFolder(fileItem); m_fileList->setCurrentFolder(fileItem);
// Refocus the 'fileview' (the focus in that widget is more // Refocus the 'fileview' (the focus in that widget is more
// useful for the user) // useful for the user)
manager()->setFocus(m_fileList); m_fileList->requestFocus();
} }
} }

View File

@ -14,21 +14,41 @@
#include "app/ui/hex_color_entry.h" #include "app/ui/hex_color_entry.h"
#include "base/hex.h" #include "base/hex.h"
#include "gfx/border.h" #include "gfx/border.h"
#include "ui/message.h"
#include "ui/theme.h" #include "ui/theme.h"
namespace app { namespace app {
using namespace ui; using namespace ui;
HexColorEntry::CustomEntry::CustomEntry()
: Entry(16, "")
{
}
bool HexColorEntry::CustomEntry::onProcessMessage(ui::Message* msg)
{
switch (msg->type()) {
case kMouseDownMessage:
setFocusStop(true);
requestFocus();
break;
case kFocusLeaveMessage:
setFocusStop(false);
break;
}
return Entry::onProcessMessage(msg);
}
HexColorEntry::HexColorEntry() HexColorEntry::HexColorEntry()
: Box(HORIZONTAL) : Box(HORIZONTAL)
, m_label("#") , m_label("#")
, m_entry(16, "")
{ {
addChild(&m_label); addChild(&m_label);
addChild(&m_entry); addChild(&m_entry);
m_entry.Change.connect(&HexColorEntry::onEntryChange, this); m_entry.Change.connect(&HexColorEntry::onEntryChange, this);
m_entry.setFocusStop(false);
initTheme(); initTheme();

View File

@ -30,8 +30,15 @@ namespace app {
void onEntryChange(); void onEntryChange();
private: private:
class CustomEntry : public ui::Entry {
public:
CustomEntry();
private:
bool onProcessMessage(ui::Message* msg) override;
};
ui::Label m_label; ui::Label m_label;
ui::Entry m_entry; CustomEntry m_entry;
}; };
} // namespace app } // namespace app

View File

@ -19,7 +19,6 @@
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/ui/color_bar.h" #include "app/ui/color_bar.h"
#include "app/ui/context_bar.h" #include "app/ui/context_bar.h"
#include "app/ui/devconsole_view.h"
#include "app/ui/document_view.h" #include "app/ui/document_view.h"
#include "app/ui/editor/editor.h" #include "app/ui/editor/editor.h"
#include "app/ui/editor/editor_view.h" #include "app/ui/editor/editor_view.h"
@ -43,6 +42,10 @@
#include "ui/system.h" #include "ui/system.h"
#include "ui/view.h" #include "ui/view.h"
#ifdef ENABLE_SCRIPTING
#include "app/ui/devconsole_view.h"
#endif
namespace app { namespace app {
using namespace ui; using namespace ui;
@ -90,8 +93,10 @@ public:
MainWindow::MainWindow() MainWindow::MainWindow()
: m_mode(NormalMode) : m_mode(NormalMode)
, m_homeView(nullptr) , m_homeView(nullptr)
, m_devConsoleView(nullptr)
, m_scalePanic(nullptr) , m_scalePanic(nullptr)
#ifdef ENABLE_SCRIPTING
, m_devConsoleView(nullptr)
#endif
{ {
// Load all menus by first time. // Load all menus by first time.
AppMenus::instance()->reload(); AppMenus::instance()->reload();
@ -154,11 +159,14 @@ MainWindow::~MainWindow()
{ {
delete m_scalePanic; delete m_scalePanic;
#ifdef ENABLE_SCRIPTING
if (m_devConsoleView) { if (m_devConsoleView) {
if (m_devConsoleView->parent()) if (m_devConsoleView->parent())
m_workspace->removeView(m_devConsoleView); m_workspace->removeView(m_devConsoleView);
delete m_devConsoleView; delete m_devConsoleView;
} }
#endif
if (m_homeView) { if (m_homeView) {
if (m_homeView->parent()) if (m_homeView->parent())
m_workspace->removeView(m_homeView); m_workspace->removeView(m_homeView);
@ -241,6 +249,7 @@ bool MainWindow::isHomeSelected()
void MainWindow::showDevConsole() void MainWindow::showDevConsole()
{ {
#ifdef ENABLE_SCRIPTING
if (!m_devConsoleView) if (!m_devConsoleView)
m_devConsoleView = new DevConsoleView; m_devConsoleView = new DevConsoleView;
@ -248,6 +257,7 @@ void MainWindow::showDevConsole()
m_workspace->addView(m_devConsoleView); m_workspace->addView(m_devConsoleView);
m_tabsBar->selectTab(m_devConsoleView); m_tabsBar->selectTab(m_devConsoleView);
} }
#endif
} }
void MainWindow::setMode(Mode mode) void MainWindow::setMode(Mode mode)

View File

@ -114,9 +114,11 @@ namespace app {
Workspace* m_workspace; Workspace* m_workspace;
PreviewEditorWindow* m_previewEditor; PreviewEditorWindow* m_previewEditor;
HomeView* m_homeView; HomeView* m_homeView;
DevConsoleView* m_devConsoleView;
Notifications* m_notifications; Notifications* m_notifications;
INotificationDelegate* m_scalePanic; INotificationDelegate* m_scalePanic;
#ifdef ENABLE_SCRIPTING
DevConsoleView* m_devConsoleView;
#endif
}; };
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -34,9 +34,11 @@ PalettePopup::PalettePopup()
{ {
setAutoRemap(false); setAutoRemap(false);
setBorder(gfx::Border(4*guiscale())); setBorder(gfx::Border(4*guiscale()));
setEnterBehavior(EnterBehavior::DoNothingOnEnter);
addChild(m_popup); addChild(m_popup);
m_paletteListBox.DoubleClickItem.connect(base::Bind<void>(&PalettePopup::onLoadPal, this));
m_popup->loadPal()->Click.connect(base::Bind<void>(&PalettePopup::onLoadPal, this)); m_popup->loadPal()->Click.connect(base::Bind<void>(&PalettePopup::onLoadPal, this));
m_popup->openFolder()->Click.connect(base::Bind<void>(&PalettePopup::onOpenFolder, this)); m_popup->openFolder()->Click.connect(base::Bind<void>(&PalettePopup::onOpenFolder, this));
@ -75,6 +77,8 @@ void PalettePopup::onLoadPal()
CommandsModule::instance()->getCommandByName(CommandId::SetPalette)); CommandsModule::instance()->getCommandByName(CommandId::SetPalette));
cmd->setPalette(palette); cmd->setPalette(palette);
UIContext::instance()->executeCommand(cmd); UIContext::instance()->executeCommand(cmd);
m_paletteListBox.requestFocus();
} }
void PalettePopup::onOpenFolder() void PalettePopup::onOpenFolder()

View File

@ -186,15 +186,15 @@ app::Color PaletteView::getColorByPosition(const gfx::Point& pos)
int PaletteView::getBoxSize() const int PaletteView::getBoxSize() const
{ {
return m_boxsize / guiscale(); return int(m_boxsize) / guiscale();
} }
void PaletteView::setBoxSize(int boxsize) void PaletteView::setBoxSize(double boxsize)
{ {
m_boxsize = MID(4, boxsize, 32)*guiscale(); m_boxsize = MID(4.0, boxsize, 32.0)*guiscale();
if (m_delegate) if (m_delegate)
m_delegate->onPaletteViewChangeSize(m_boxsize / guiscale()); m_delegate->onPaletteViewChangeSize(int(m_boxsize) / guiscale());
View* view = View::getView(this); View* view = View::getView(this);
if (view) if (view)
@ -382,13 +382,19 @@ bool PaletteView::onProcessMessage(Message* msg)
gfx::Point delta = static_cast<MouseMessage*>(msg)->wheelDelta(); gfx::Point delta = static_cast<MouseMessage*>(msg)->wheelDelta();
if (msg->onlyCtrlPressed()) { if (msg->onlyCtrlPressed() ||
msg->onlyCmdPressed()) {
int z = delta.x - delta.y; int z = delta.x - delta.y;
setBoxSize(m_boxsize + z); setBoxSize(m_boxsize + z);
} }
else { else {
gfx::Point scroll = view->viewScroll(); gfx::Point scroll = view->viewScroll();
scroll += delta * 3 * m_boxsize;
if (static_cast<MouseMessage*>(msg)->preciseWheel())
scroll += delta;
else
scroll += delta * 3 * m_boxsize;
view->setViewScroll(scroll); view->setViewScroll(scroll);
} }
break; break;
@ -411,6 +417,11 @@ bool PaletteView::onProcessMessage(Message* msg)
return true; return true;
} }
case kTouchMagnifyMessage: {
setBoxSize(m_boxsize + m_boxsize * static_cast<ui::TouchMessage*>(msg)->magnification());
break;
}
} }
return Widget::onProcessMessage(msg); return Widget::onProcessMessage(msg);
@ -475,14 +486,14 @@ void PaletteView::onPaint(ui::PaintEvent& ev)
case FgBgColors: case FgBgColors:
if (fgIndex == i) { if (fgIndex == i) {
gfx::Color neg = color_utils::blackandwhite_neg(gfxColor); gfx::Color neg = color_utils::blackandwhite_neg(gfxColor);
for (int i=0; i<m_boxsize/2; ++i) for (int i=0; i<int(m_boxsize/2); ++i)
g->drawHLine(neg, box.x, box.y+i, m_boxsize/2-i); g->drawHLine(neg, box.x, box.y+i, m_boxsize/2-i);
} }
if (bgIndex == i) { if (bgIndex == i) {
gfx::Color neg = color_utils::blackandwhite_neg(gfxColor); gfx::Color neg = color_utils::blackandwhite_neg(gfxColor);
for (int i=0; i<m_boxsize/4; ++i) for (int i=0; i<int(m_boxsize/4); ++i)
g->drawHLine(neg, box.x+box.w-(i+1), box.y+box.h-m_boxsize/4+i, i+1); g->drawHLine(neg, box.x+box.w-(i+1), box.y+box.h-int(m_boxsize/4)+i, i+1);
} }
if (transparentIndex == i) if (transparentIndex == i)
@ -582,7 +593,7 @@ void PaletteView::onResize(ui::ResizeEvent& ev)
if (view) { if (view) {
int columns = int columns =
(view->viewportBounds().w-this->childSpacing()*2) (view->viewportBounds().w-this->childSpacing()*2)
/ (m_boxsize+this->childSpacing()); / (int(m_boxsize)+this->childSpacing());
setColumns(MAX(1, columns)); setColumns(MAX(1, columns));
} }
m_isUpdatingColumns = false; m_isUpdatingColumns = false;
@ -602,8 +613,8 @@ void PaletteView::onSizeHint(ui::SizeHintEvent& ev)
} }
gfx::Size sz; gfx::Size sz;
sz.w = border().width() + cols*m_boxsize + (cols-1)*childSpacing(); sz.w = border().width() + cols*int(m_boxsize) + (cols-1)*childSpacing();
sz.h = border().height() + rows*m_boxsize + (rows-1)*childSpacing(); sz.h = border().height() + rows*int(m_boxsize) + (rows-1)*childSpacing();
ev.setSizeHint(sz); ev.setSizeHint(sz);
} }
@ -629,18 +640,18 @@ void PaletteView::update_scroll(int color)
d = div(currentPalette()->size(), m_columns); d = div(currentPalette()->size(), m_columns);
cols = m_columns; cols = m_columns;
y = (m_boxsize+childSpacing()) * (color / cols); y = (int(m_boxsize)+childSpacing()) * (color / cols);
x = (m_boxsize+childSpacing()) * (color % cols); x = (int(m_boxsize)+childSpacing()) * (color % cols);
if (scroll.x > x) if (scroll.x > x)
scroll.x = x; scroll.x = x;
else if (scroll.x+vp.w-m_boxsize-2 < x) else if (scroll.x+vp.w-int(m_boxsize)-2 < x)
scroll.x = x-vp.w+m_boxsize+2; scroll.x = x-vp.w+int(m_boxsize)+2;
if (scroll.y > y) if (scroll.y > y)
scroll.y = y; scroll.y = y;
else if (scroll.y+vp.h-m_boxsize-2 < y) else if (scroll.y+vp.h-int(m_boxsize)-2 < y)
scroll.y = y-vp.h+m_boxsize+2; scroll.y = y-vp.h+int(m_boxsize)+2;
view->setViewScroll(scroll); view->setViewScroll(scroll);
} }
@ -662,9 +673,9 @@ gfx::Rect PaletteView::getPaletteEntryBounds(int index) const
int row = index / cols; int row = index / cols;
return gfx::Rect( return gfx::Rect(
bounds.x + border().left() + col*(m_boxsize+childSpacing()), bounds.x + border().left() + col*(int(m_boxsize)+childSpacing()),
bounds.y + border().top() + row*(m_boxsize+childSpacing()), bounds.y + border().top() + row*(int(m_boxsize)+childSpacing()),
m_boxsize, m_boxsize); int(m_boxsize), int(m_boxsize));
} }
PaletteView::Hit PaletteView::hitTest(const gfx::Point& pos) PaletteView::Hit PaletteView::hitTest(const gfx::Point& pos)
@ -716,8 +727,8 @@ PaletteView::Hit PaletteView::hitTest(const gfx::Point& pos)
} }
gfx::Rect box = getPaletteEntryBounds(0); gfx::Rect box = getPaletteEntryBounds(0);
box.w = (m_boxsize+childSpacing()); box.w = (int(m_boxsize)+childSpacing());
box.h = (m_boxsize+childSpacing()); box.h = (int(m_boxsize)+childSpacing());
int colsLimit = m_columns; int colsLimit = m_columns;
if (m_state == State::DRAGGING_OUTLINE) if (m_state == State::DRAGGING_OUTLINE)

View File

@ -74,7 +74,7 @@ namespace app {
app::Color getColorByPosition(const gfx::Point& pos) override; app::Color getColorByPosition(const gfx::Point& pos) override;
int getBoxSize() const; int getBoxSize() const;
void setBoxSize(int boxsize); void setBoxSize(double boxsize);
void clearSelection(); void clearSelection();
void cutToClipboard(); void cutToClipboard();
@ -147,7 +147,7 @@ namespace app {
PaletteViewStyle m_style; PaletteViewStyle m_style;
PaletteViewDelegate* m_delegate; PaletteViewDelegate* m_delegate;
int m_columns; int m_columns;
int m_boxsize; double m_boxsize;
int m_currentEntry; int m_currentEntry;
int m_rangeAnchor; int m_rangeAnchor;
doc::PalettePicks m_selectedEntries; doc::PalettePicks m_selectedEntries;

View File

@ -10,14 +10,19 @@
#include "app/ui/palettes_listbox.h" #include "app/ui/palettes_listbox.h"
#include "app/document.h"
#include "app/modules/palettes.h" #include "app/modules/palettes.h"
#include "app/res/palette_resource.h" #include "app/res/palette_resource.h"
#include "app/res/palettes_loader_delegate.h" #include "app/res/palettes_loader_delegate.h"
#include "app/ui/document_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/icon_button.h" #include "app/ui/icon_button.h"
#include "app/ui/skin/skin_theme.h" #include "app/ui/skin/skin_theme.h"
#include "app/ui_context.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/launcher.h" #include "base/launcher.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/sprite.h"
#include "she/surface.h" #include "she/surface.h"
#include "ui/graphics.h" #include "ui/graphics.h"
#include "ui/listitem.h" #include "ui/listitem.h"
@ -63,7 +68,7 @@ class PalettesListItem : public ResourceListItem {
int j, i = m_comment.find("http"); int j, i = m_comment.find("http");
if (i != std::string::npos) { if (i != std::string::npos) {
for (j=i+4; j<m_comment.size() && is_url_char(m_comment[j]); ++j) for (j=i+4; j<int(m_comment.size()) && is_url_char(m_comment[j]); ++j)
; ;
base::launcher::open_url(m_comment.substr(i, j-i)); base::launcher::open_url(m_comment.substr(i, j-i));
} }
@ -128,9 +133,22 @@ void PalettesListBox::onResourceChange(Resource* resource)
PalChange(palette); PalChange(palette);
} }
void PalettesListBox::onPaintResource(Graphics* g, const gfx::Rect& bounds, Resource* resource) void PalettesListBox::onPaintResource(Graphics* g, gfx::Rect& bounds, Resource* resource)
{ {
doc::Palette* palette = static_cast<PaletteResource*>(resource)->palette(); doc::Palette* palette = static_cast<PaletteResource*>(resource)->palette();
auto tick = SkinTheme::instance()->parts.checkSelected()->bitmap(0);
// Draw tick (to say "this palette matches the active sprite
// palette").
auto view = UIContext::instance()->activeView();
if (view && view->document()) {
auto docPal = view->document()->sprite()->palette(view->editor()->frame());
if (docPal && *docPal == *palette)
g->drawRgbaSurface(tick, bounds.x, bounds.y+bounds.h/2-tick->height()/2);
}
bounds.x += tick->width();
bounds.w -= tick->width();
gfx::Rect box( gfx::Rect box(
bounds.x, bounds.y+bounds.h-6*guiscale(), bounds.x, bounds.y+bounds.h-6*guiscale(),

View File

@ -28,7 +28,7 @@ namespace app {
protected: protected:
virtual ResourceListItem* onCreateResourceItem(Resource* resource) override; virtual ResourceListItem* onCreateResourceItem(Resource* resource) override;
virtual void onResourceChange(Resource* resource) override; virtual void onResourceChange(Resource* resource) override;
virtual void onPaintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource) override; virtual void onPaintResource(ui::Graphics* g, gfx::Rect& bounds, Resource* resource) override;
virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) override; virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) override;
ui::TooltipManager m_tooltips; ui::TooltipManager m_tooltips;

View File

@ -32,6 +32,7 @@ PopupWindowPin::PopupWindowPin(const std::string& text, ClickBehavior clickBehav
{ {
SkinTheme* theme = SkinTheme::instance(); SkinTheme* theme = SkinTheme::instance();
m_pin.setFocusStop(false);
m_pin.Click.connect(&PopupWindowPin::onPinClick, this); m_pin.Click.connect(&PopupWindowPin::onPinClick, this);
m_pin.setIconInterface( m_pin.setIconInterface(
new ButtonIconImpl(theme->parts.unpinned(), new ButtonIconImpl(theme->parts.unpinned(),

View File

@ -67,7 +67,7 @@ void ResourceListItem::onPaint(PaintEvent& ev)
g->drawString(text(), fgcolor, gfx::ColorNone, g->drawString(text(), fgcolor, gfx::ColorNone,
gfx::Point( gfx::Point(
bounds.x + guiscale()*2, bounds.x + 2*guiscale(),
bounds.y + bounds.h/2 - g->measureUIString(text()).h/2)); bounds.y + bounds.h/2 - g->measureUIString(text()).h/2));
} }
@ -124,7 +124,7 @@ Resource* ResourcesListBox::selectedResource()
return NULL; return NULL;
} }
void ResourcesListBox::paintResource(Graphics* g, const gfx::Rect& bounds, Resource* resource) void ResourcesListBox::paintResource(Graphics* g, gfx::Rect& bounds, Resource* resource)
{ {
onPaintResource(g, bounds, resource); onPaintResource(g, bounds, resource);
} }

View File

@ -47,11 +47,11 @@ class ResourceListItem : public ui::ListItem {
// abstract // abstract
virtual void onResourceChange(Resource* resource) = 0; virtual void onResourceChange(Resource* resource) = 0;
virtual void onPaintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource) = 0; virtual void onPaintResource(ui::Graphics* g, gfx::Rect& bounds, Resource* resource) = 0;
virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) = 0; virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) = 0;
private: private:
void paintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource); void paintResource(ui::Graphics* g, gfx::Rect& bounds, Resource* resource);
gfx::Size resourceSizeHint(Resource* resource); gfx::Size resourceSizeHint(Resource* resource);
void onTick(); void onTick();

View File

@ -23,6 +23,7 @@ using namespace ui;
class SelectAccelerator::KeyField : public ui::Entry { class SelectAccelerator::KeyField : public ui::Entry {
public: public:
KeyField(const Accelerator& accel) : ui::Entry(256, "") { KeyField(const Accelerator& accel) : ui::Entry(256, "") {
setTranslateDeadKeys(false);
setExpansive(true); setExpansive(true);
setFocusMagnet(true); setFocusMagnet(true);
setAccel(accel); setAccel(accel);
@ -38,9 +39,13 @@ public:
protected: protected:
bool onProcessMessage(Message* msg) override { bool onProcessMessage(Message* msg) override {
switch (msg->type()) { switch (msg->type()) {
case kKeyDownMessage: case kKeyDownMessage:
if (hasFocus() && !isReadOnly()) { if (hasFocus() && !isReadOnly()) {
KeyMessage* keymsg = static_cast<KeyMessage*>(msg); KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
if (!keymsg->scancode() && keymsg->unicodeChar() < 32)
break;
KeyModifiers modifiers = keymsg->modifiers(); KeyModifiers modifiers = keymsg->modifiers();
if (keymsg->scancode() == kKeySpace) if (keymsg->scancode() == kKeySpace)

View File

@ -895,9 +895,13 @@ void SkinTheme::paintCheckBox(PaintEvent& ev)
if (iconInterface) if (iconInterface)
paintIcon(widget, g, iconInterface, icon.x, icon.y); paintIcon(widget, g, iconInterface, icon.x, icon.y);
// draw focus // Draw focus
if (look != WithoutBordersLook && widget->hasFocus()) if (look != WithoutBordersLook &&
(widget->hasFocus() || (iconInterface &&
widget->text().empty() &&
widget->hasMouseOver()))) {
drawRect(g, bounds, parts.checkFocus().get(), gfx::ColorNone); drawRect(g, bounds, parts.checkFocus().get(), gfx::ColorNone);
}
} }
void SkinTheme::paintGrid(PaintEvent& ev) void SkinTheme::paintGrid(PaintEvent& ev)

View File

@ -35,6 +35,7 @@
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/util/range_utils.h" #include "app/util/range_utils.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/string.h"
#include "doc/document_event.h" #include "doc/document_event.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/layer.h" #include "doc/layer.h"
@ -475,7 +476,7 @@ public:
case kMouseEnterMessage: case kMouseEnterMessage:
if (Preferences::instance().statusBar.focusFrameFieldOnMouseover()) { if (Preferences::instance().statusBar.focusFrameFieldOnMouseover()) {
requestFocus(); requestFocus();
selectText(0, -1); selectAllText();
} }
break; break;
@ -488,13 +489,11 @@ public:
scancode == kKeyEnterPad)) { scancode == kKeyEnterPad)) {
Command* cmd = CommandsModule::instance()->getCommandByName(CommandId::GotoFrame); Command* cmd = CommandsModule::instance()->getCommandByName(CommandId::GotoFrame);
Params params; Params params;
int frame = textInt(); params.set("frame", text().c_str());
if (frame > 0) { UIContext::instance()->executeCommand(cmd, params);
params.set("frame", text().c_str());
UIContext::instance()->executeCommand(cmd, params);
}
// Select the text again // Select the text again
selectText(0, -1); selectAllText();
releaseFocus(); releaseFocus();
return true; // Key used. return true; // Key used.
} }
@ -611,17 +610,15 @@ void StatusBar::showBackupIcon(BackupIcon icon)
m_indicators->showBackupIcon(icon); m_indicators->showBackupIcon(icon);
} }
bool StatusBar::setStatusText(int msecs, const char *format, ...) bool StatusBar::setStatusText(int msecs, const char* format, ...)
{ {
if ((base::current_tick() > m_timeout) || (msecs > 0)) { if ((base::current_tick() > m_timeout) || (msecs > 0)) {
char buf[256]; // TODO warning buffer overflow std::va_list ap;
va_list ap;
va_start(ap, format); va_start(ap, format);
vsprintf(buf, format, ap); std::string msg = base::string_vprintf(format, ap);
va_end(ap); va_end(ap);
IndicatorsGeneration(m_indicators).add(buf); IndicatorsGeneration(m_indicators).add(msg.c_str());
m_timeout = base::current_tick() + msecs; m_timeout = base::current_tick() + msecs;
return true; return true;
} }
@ -629,21 +626,18 @@ bool StatusBar::setStatusText(int msecs, const char *format, ...)
return false; return false;
} }
void StatusBar::showTip(int msecs, const char *format, ...) void StatusBar::showTip(int msecs, const char* format, ...)
{ {
char buf[256]; // TODO warning buffer overflow std::va_list ap;
va_list ap;
int x, y;
va_start(ap, format); va_start(ap, format);
vsprintf(buf, format, ap); std::string msg = base::string_vprintf(format, ap);
va_end(ap); va_end(ap);
if (m_tipwindow == NULL) { if (m_tipwindow == NULL) {
m_tipwindow = new CustomizedTipWindow(buf); m_tipwindow = new CustomizedTipWindow(msg);
} }
else { else {
m_tipwindow->setText(buf); m_tipwindow->setText(msg);
} }
m_tipwindow->setInterval(msecs); m_tipwindow->setInterval(msecs);
@ -654,14 +648,14 @@ void StatusBar::showTip(int msecs, const char *format, ...)
m_tipwindow->openWindow(); m_tipwindow->openWindow();
m_tipwindow->remapWindow(); m_tipwindow->remapWindow();
x = bounds().x2() - m_tipwindow->bounds().w; int x = bounds().x2() - m_tipwindow->bounds().w;
y = bounds().y - m_tipwindow->bounds().h; int y = bounds().y - m_tipwindow->bounds().h;
m_tipwindow->positionWindow(x, y); m_tipwindow->positionWindow(x, y);
m_tipwindow->startTimer(); m_tipwindow->startTimer();
// Set the text in status-bar (with inmediate timeout) // Set the text in status-bar (with inmediate timeout)
IndicatorsGeneration(m_indicators).add(buf); IndicatorsGeneration(m_indicators).add(msg.c_str());
m_timeout = base::current_tick(); m_timeout = base::current_tick();
} }
@ -744,13 +738,15 @@ void StatusBar::onActiveSiteChange(const doc::Site& site)
ASSERT(m_doc == site.document()); ASSERT(m_doc == site.document());
} }
auto& docPref = Preferences::instance().document(
static_cast<app::Document*>(m_doc));
m_docControls->setVisible(true); m_docControls->setVisible(true);
showSnapToGridWarning( showSnapToGridWarning(docPref.grid.snap());
Preferences::instance().document(
static_cast<app::Document*>(m_doc)).grid.snap());
// Current frame // Current frame
m_currentFrame->setTextf("%d", site.frame()+1); m_currentFrame->setTextf(
"%d", site.frame()+docPref.timeline.firstFrame());
} }
else { else {
ASSERT(m_doc == nullptr); ASSERT(m_doc == nullptr);

View File

@ -57,8 +57,8 @@ namespace app {
void clearText(); void clearText();
bool setStatusText(int msecs, const char *format, ...); bool setStatusText(int msecs, const char* format, ...);
void showTip(int msecs, const char *format, ...); void showTip(int msecs, const char* format, ...);
void showColor(int msecs, const char* text, const Color& color); void showColor(int msecs, const char* text, const Color& color);
void showTool(int msecs, tools::Tool* tool); void showTool(int msecs, tools::Tool* tool);
void showSnapToGridWarning(bool state); void showSnapToGridWarning(bool state);

View File

@ -51,6 +51,7 @@
#include "gfx/rect.h" #include "gfx/rect.h"
#include "she/font.h" #include "she/font.h"
#include "she/surface.h" #include "she/surface.h"
#include "she/system.h"
#include "ui/scroll_helper.h" #include "ui/scroll_helper.h"
#include "ui/ui.h" #include "ui/ui.h"
@ -250,6 +251,9 @@ void Timeline::updateUsingEditor(Editor* editor)
m_hot.part = PART_NOTHING; m_hot.part = PART_NOTHING;
m_clk.part = PART_NOTHING; m_clk.part = PART_NOTHING;
m_firstFrameConn = Preferences::instance().document(m_document)
.timeline.firstFrame.AfterChange.connect(base::Bind<void>(&Timeline::invalidate, this));
setFocusStop(true); setFocusStop(true);
regenerateLayers(); regenerateLayers();
setViewScroll(viewScroll()); setViewScroll(viewScroll());
@ -258,6 +262,8 @@ void Timeline::updateUsingEditor(Editor* editor)
void Timeline::detachDocument() void Timeline::detachDocument()
{ {
m_firstFrameConn.disconnect();
if (m_document) { if (m_document) {
m_thumbnailsPrefConn.disconnect(); m_thumbnailsPrefConn.disconnect();
m_document->remove_observer(this); m_document->remove_observer(this);
@ -425,7 +431,8 @@ bool Timeline::onProcessMessage(Message* msg)
if (!m_document) if (!m_document)
break; break;
if (mouseMsg->middle() || she::is_key_pressed(kKeySpace)) { if (mouseMsg->middle() ||
she::instance()->isKeyPressed(kKeySpace)) {
captureMouse(); captureMouse();
m_state = STATE_SCROLLING; m_state = STATE_SCROLLING;
m_oldPos = static_cast<MouseMessage*>(msg)->position(); m_oldPos = static_cast<MouseMessage*>(msg)->position();
@ -1048,7 +1055,7 @@ bool Timeline::onProcessMessage(Message* msg)
m_scroll = false; m_scroll = false;
// We have to clear all the kKeySpace keys in buffer. // We have to clear all the kKeySpace keys in buffer.
she::clear_keyboard_buffer(); she::instance()->clearKeyboardBuffer();
used = true; used = true;
break; break;
} }
@ -1065,35 +1072,23 @@ bool Timeline::onProcessMessage(Message* msg)
case kMouseWheelMessage: case kMouseWheelMessage:
if (m_document) { if (m_document) {
int base_size = skinTheme()->dimensions.timelineBaseSize(); gfx::Point delta = static_cast<MouseMessage*>(msg)->wheelDelta();
int dz = static_cast<MouseMessage*>(msg)->wheelDelta().y * base_size; if (!static_cast<MouseMessage*>(msg)->preciseWheel()) {
delta.x *= frameBoxWidth();
if (msg->altPressed()) { delta.y *= layerBoxHeight();
if (dz != 0) {
double next_zoom = m_zoom + (dz < 0 ? 1 : -1);
setZoomAndUpdate(next_zoom);
}
}
else {
int dx;
int dy;
if (msg->ctrlPressed()) {
dx = dz;
dy = 0;
}
else {
dx = static_cast<MouseMessage*>(msg)->wheelDelta().x * base_size;
dy = dz;
}
if (msg->shiftPressed()) { if (msg->shiftPressed()) {
dx *= frameBoxWidth() / base_size; // On macOS shift already changes the wheel axis
dy *= layerBoxHeight() / base_size; if (std::fabs(delta.y) > delta.x)
std::swap(delta.x, delta.y);
} }
setViewScroll(viewScroll() + gfx::Point(dx, dy)); if (msg->altPressed()) {
delta.x *= 3;
delta.y *= 3;
}
} }
setViewScroll(viewScroll() + delta);
} }
break; break;
@ -1589,8 +1584,11 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, frame_t frame)
return; return;
// Draw the header for the layers. // Draw the header for the layers.
char buf[256]; char buf[4];
std::sprintf(buf, "%d", (frame+1)%100); // Draw only the first two digits. std::snprintf(
buf, sizeof(buf), "%d",
// Draw only the first two digits
(docPref().timeline.firstFrame()+frame) % 100);
she::Font* oldFont = g->font(); she::Font* oldFont = g->font();
g->setFont(skinTheme()->getMiniFont()); g->setFont(skinTheme()->getMiniFont());
@ -2694,9 +2692,10 @@ void Timeline::updateStatusBar(ui::Message* msg)
case PART_HEADER_FRAME: case PART_HEADER_FRAME:
if (validFrame(m_hot.frame)) { if (validFrame(m_hot.frame)) {
sb->setStatusText(0, sb->setStatusText(
0,
":frame: %d :clock: %d", ":frame: %d :clock: %d",
(int)m_hot.frame+1, (int)m_hot.frame+docPref().timeline.firstFrame(),
m_sprite->frameDuration(m_hot.frame)); m_sprite->frameDuration(m_hot.frame));
return; return;
} }

View File

@ -339,6 +339,7 @@ namespace app {
// Configure timeline // Configure timeline
ConfigureTimelinePopup* m_confPopup; ConfigureTimelinePopup* m_confPopup;
obs::scoped_connection m_ctxConn; obs::scoped_connection m_ctxConn;
obs::connection m_firstFrameConn;
// Marching ants stuff to show the range in the clipboard. // Marching ants stuff to show the range in the clipboard.
// TODO merge this with the marching ants of the sprite editor (ui::Editor) // TODO merge this with the marching ants of the sprite editor (ui::Editor)

View File

@ -727,6 +727,11 @@ Rect ToolBar::ToolStrip::getToolBounds(int index)
iconsize.w, bounds.h); iconsize.w, bounds.h);
} }
void ToolBar::onActiveToolChange(tools::Tool* tool)
{
invalidate();
}
void ToolBar::onSelectedToolChange(tools::Tool* tool) void ToolBar::onSelectedToolChange(tools::Tool* tool)
{ {
if (tool && m_selectedInGroup[tool->getGroup()] != tool) if (tool && m_selectedInGroup[tool->getGroup()] != tool)

View File

@ -61,6 +61,7 @@ namespace app {
void onClosePopup(); void onClosePopup();
// ActiveToolObserver impl // ActiveToolObserver impl
void onActiveToolChange(tools::Tool* tool) override;
void onSelectedToolChange(tools::Tool* tool) override; void onSelectedToolChange(tools::Tool* tool) override;
// What tool is selected for each tool-group // What tool is selected for each tool-group

View File

@ -296,6 +296,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
else if (elem_name == "listbox") { else if (elem_name == "listbox") {
if (!widget) if (!widget)
widget = new ListBox(); widget = new ListBox();
bool multiselect = bool_attr_is_true(elem, "multiselect");
if (multiselect)
static_cast<ListBox*>(widget)->setMultiselect(multiselect);
} }
else if (elem_name == "listitem") { else if (elem_name == "listitem") {
ListItem* listitem; ListItem* listitem;

@ -1 +1 @@
Subproject commit 3e9533e332e6b1982476c255eedaae917e63dfec Subproject commit 926e3cf0ae484111d89cacd769d29c4d1e073dec

View File

@ -2,7 +2,8 @@
# Copyright (C) 2012-2016 David Capello # Copyright (C) 2012-2016 David Capello
set(SHE_SOURCES set(SHE_SOURCES
common/freetype_font.cpp) common/freetype_font.cpp
system.cpp)
###################################################################### ######################################################################
# Allegro 4 backend # Allegro 4 backend

View File

@ -1,5 +1,5 @@
// SHE library // SHE library
// Copyright (C) 2012-2015 David Capello // Copyright (C) 2012-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -21,14 +21,12 @@ int key_repeated[KEY_MAX];
int she_keyboard_ucallback(int unicode_char, int* scancode) int she_keyboard_ucallback(int unicode_char, int* scancode)
{ {
int c = ((*scancode) & 0x7f); int c = ((*scancode) & 0x7f);
Event ev;
Event ev;
ev.setType(Event::KeyDown); ev.setType(Event::KeyDown);
ev.setScancode(static_cast<KeyScancode>(c)); ev.setScancode(static_cast<KeyScancode>(c));
if (unicode_char > 0) if (unicode_char > 0)
ev.setUnicodeChar(unicode_char); ev.setUnicodeChar(unicode_char);
else
ev.setUnicodeChar(::scancode_to_ascii(c));
ev.setRepeat(key_repeated[c]++); ev.setRepeat(key_repeated[c]++);
queue_event(ev); queue_event(ev);

View File

@ -63,8 +63,6 @@
#include "she/alleg4/mouse_poller.h" #include "she/alleg4/mouse_poller.h"
#endif #endif
static she::System* g_instance = nullptr;
namespace she { namespace she {
class Alleg4EventQueue : public EventQueue { class Alleg4EventQueue : public EventQueue {
@ -129,15 +127,11 @@ public:
#ifdef USE_MOUSE_POLLER #ifdef USE_MOUSE_POLLER
mouse_poller_init(); mouse_poller_init();
#endif #endif
g_instance = this;
} }
~Alleg4System() { ~Alleg4System() {
remove_timer(); remove_timer();
allegro_exit(); allegro_exit();
g_instance = nullptr;
} }
void dispose() override { void dispose() override {
@ -206,21 +200,48 @@ public:
return sur; return sur;
} }
bool isKeyPressed(KeyScancode scancode) override {
#ifdef ALLEGRO_UNIX
if (scancode == kKeyLShift || scancode == kKeyRShift) {
return key_shifts & KB_SHIFT_FLAG;
}
else if (scancode == kKeyLControl || scancode == kKeyRControl) {
return key_shifts & KB_CTRL_FLAG;
}
else if (scancode == kKeyAlt) {
return key_shifts & KB_ALT_FLAG;
}
#endif
return key[scancode] ? true: false;
}
int getUnicodeFromScancode(KeyScancode scancode) override {
if (isKeyPressed(scancode))
return scancode_to_ascii(scancode);
else
return false;
}
void clearKeyboardBuffer() override {
clear_keybuf();
}
void setTranslateDeadKeys(bool state) override {
// Do nothing
}
}; };
System* create_system() { System* create_system_impl() {
return new Alleg4System(); return new Alleg4System();
} }
System* instance()
{
return g_instance;
}
void error_message(const char* msg) void error_message(const char* msg)
{ {
if (g_instance && g_instance->logger()) System* sys = instance();
g_instance->logger()->logError(msg); if (sys && sys->logger())
sys->logger()->logError(msg);
#ifdef _WIN32 #ifdef _WIN32
std::wstring wmsg = base::from_utf8(msg); std::wstring wmsg = base::from_utf8(msg);
@ -231,27 +252,6 @@ void error_message(const char* msg)
#endif #endif
} }
bool is_key_pressed(KeyScancode scancode)
{
#ifdef ALLEGRO_UNIX
if (scancode == kKeyLShift || scancode == kKeyRShift) {
return key_shifts & KB_SHIFT_FLAG;
}
else if (scancode == kKeyLControl || scancode == kKeyRControl) {
return key_shifts & KB_CTRL_FLAG;
}
else if (scancode == kKeyAlt) {
return key_shifts & KB_ALT_FLAG;
}
#endif
return key[scancode] ? true: false;
}
void clear_keyboard_buffer()
{
clear_keybuf();
}
} // namespace she } // namespace she
// It must be defined by the user program code. // It must be defined by the user program code.

View File

@ -78,6 +78,25 @@ public:
return loadFreeTypeFont(filename, height); return loadFreeTypeFont(filename, height);
} }
KeyModifiers keyModifiers() override {
return
(KeyModifiers)
((isKeyPressed(kKeyLShift) ||
isKeyPressed(kKeyRShift) ? kKeyShiftModifier: 0) |
(isKeyPressed(kKeyLControl) ||
isKeyPressed(kKeyRControl) ? kKeyCtrlModifier: 0) |
(isKeyPressed(kKeyAlt) ? kKeyAltModifier: 0) |
(isKeyPressed(kKeyAltGr) ? (kKeyCtrlModifier | kKeyAltModifier): 0) |
(isKeyPressed(kKeyCommand) ? kKeyCmdModifier: 0) |
(isKeyPressed(kKeySpace) ? kKeySpaceModifier: 0) |
(isKeyPressed(kKeyLWin) ||
isKeyPressed(kKeyRWin) ? kKeyWinModifier: 0));
}
void clearKeyboardBuffer() override {
// Do nothing
}
private: private:
NativeDialogs* m_nativeDialogs; NativeDialogs* m_nativeDialogs;
}; };

View File

@ -56,6 +56,7 @@ namespace she {
m_scancode(kKeyNil), m_scancode(kKeyNil),
m_modifiers(kKeyUninitializedModifier), m_modifiers(kKeyUninitializedModifier),
m_unicodeChar(0), m_unicodeChar(0),
m_isDead(false),
m_repeat(0), m_repeat(0),
m_preciseWheel(false), m_preciseWheel(false),
m_pointerType(PointerType::Unknown), m_pointerType(PointerType::Unknown),
@ -70,6 +71,7 @@ namespace she {
KeyScancode scancode() const { return m_scancode; } KeyScancode scancode() const { return m_scancode; }
KeyModifiers modifiers() const { return m_modifiers; } KeyModifiers modifiers() const { return m_modifiers; }
int unicodeChar() const { return m_unicodeChar; } int unicodeChar() const { return m_unicodeChar; }
bool isDeadKey() const { return m_isDead; }
int repeat() const { return m_repeat; } int repeat() const { return m_repeat; }
gfx::Point position() const { return m_position; } gfx::Point position() const { return m_position; }
gfx::Point wheelDelta() const { return m_wheelDelta; } gfx::Point wheelDelta() const { return m_wheelDelta; }
@ -92,6 +94,7 @@ namespace she {
void setScancode(KeyScancode scancode) { m_scancode = scancode; } void setScancode(KeyScancode scancode) { m_scancode = scancode; }
void setModifiers(KeyModifiers modifiers) { m_modifiers = modifiers; } void setModifiers(KeyModifiers modifiers) { m_modifiers = modifiers; }
void setUnicodeChar(int unicodeChar) { m_unicodeChar = unicodeChar; } void setUnicodeChar(int unicodeChar) { m_unicodeChar = unicodeChar; }
void setDeadKey(bool state) { m_isDead = state; }
void setRepeat(int repeat) { m_repeat = repeat; } void setRepeat(int repeat) { m_repeat = repeat; }
void setPosition(const gfx::Point& pos) { m_position = pos; } void setPosition(const gfx::Point& pos) { m_position = pos; }
void setWheelDelta(const gfx::Point& delta) { m_wheelDelta = delta; } void setWheelDelta(const gfx::Point& delta) { m_wheelDelta = delta; }
@ -108,6 +111,7 @@ namespace she {
KeyScancode m_scancode; KeyScancode m_scancode;
KeyModifiers m_modifiers; KeyModifiers m_modifiers;
int m_unicodeChar; int m_unicodeChar;
bool m_isDead;
int m_repeat; // repeat=0 means the first time the key is pressed int m_repeat; // repeat=0 means the first time the key is pressed
gfx::Point m_position; gfx::Point m_position;
gfx::Point m_wheelDelta; gfx::Point m_wheelDelta;

View File

@ -1,5 +1,5 @@
// SHE library // SHE library
// Copyright (C) 2012-2013, 2015 David Capello // Copyright (C) 2012-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -125,30 +125,30 @@ namespace she {
kKeyCircumflex = 100, kKeyCircumflex = 100,
kKeyColon2 = 101, kKeyColon2 = 101,
kKeyKanji = 102, kKeyKanji = 102,
kKeyEqualsPad = 103, // MacOS X kKeyEqualsPad = 103, // macOS
kKeyBackquote = 104, // MacOS X kKeyBackquote = 104, // macOS
kKeySemicolon = 105, // MacOS X kKeySemicolon = 105, // macOS
kKeyCommand = 106, // MacOS X kKeyUnknown1 = 106,
kKeyUnknown1 = 107, kKeyUnknown2 = 107,
kKeyUnknown2 = 108, kKeyUnknown3 = 108,
kKeyUnknown3 = 109, kKeyUnknown4 = 109,
kKeyUnknown4 = 110, kKeyUnknown5 = 110,
kKeyUnknown5 = 111, kKeyUnknown6 = 111,
kKeyUnknown6 = 112, kKeyUnknown7 = 112,
kKeyUnknown7 = 113, kKeyUnknown8 = 113,
kKeyUnknown8 = 114,
kKeyFirstModifierScancode = 115, kKeyFirstModifierScancode = 114,
kKeyLShift = 115, kKeyLShift = 114,
kKeyRShift = 116, kKeyRShift = 115,
kKeyLControl = 117, kKeyLControl = 116,
kKeyRControl = 118, kKeyRControl = 117,
kKeyAlt = 119, kKeyAlt = 118,
kKeyAltGr = 120, kKeyAltGr = 119,
kKeyLWin = 121, kKeyLWin = 120,
kKeyRWin = 122, kKeyRWin = 121,
kKeyMenu = 123, kKeyMenu = 122,
kKeyCommand = 123, // macOS - TODO This should be inside the modifiers range
kKeyScrLock = 124, kKeyScrLock = 124,
kKeyNumLock = 125, kKeyNumLock = 125,
kKeyCapsLock = 126, kKeyCapsLock = 126,
@ -156,11 +156,6 @@ namespace she {
kKeyScancodes = 127 kKeyScancodes = 127
}; };
// Deprecated API, use modifiers in she::Event
// TODO mark these functions as deprecated
bool is_key_pressed(KeyScancode scancode);
void clear_keyboard_buffer();
} // namespace she } // namespace she
#endif #endif

View File

@ -32,12 +32,11 @@ retry:;
inMode:NSDefaultRunLoopMode inMode:NSDefaultRunLoopMode
dequeue:YES]; dequeue:YES];
if (event) { if (event) {
// Intercept Control+Tab and send it to the main NSView. Without // Intercept <Control+Tab>, <Cmd+[>, and other keyboard
// this, the NSApplication intercepts the key combination and // combinations, and send them directly to the main
// use it to go to the next key view. // NSView. Without this, the NSApplication intercepts the key
if (event.type == NSKeyDown && // combination and use it to go to the next key view.
event.modifierFlags & NSControlKeyMask && if (event.type == NSKeyDown) {
event.keyCode == kVK_Tab) {
[app.mainWindow.contentView keyDown:event]; [app.mainWindow.contentView keyDown:event];
} }
else { else {

31
src/she/osx/system.h Normal file
View File

@ -0,0 +1,31 @@
// SHE library
// Copyright (C) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef SHE_OSX_SYSTEM_H
#define SHE_OSX_SYSTEM_H
#pragma once
#include "she/common/system.h"
namespace she {
bool osx_is_key_pressed(KeyScancode scancode);
int osx_get_unicode_from_scancode(KeyScancode scancode);
class OSXSystem : public CommonSystem {
public:
bool isKeyPressed(KeyScancode scancode) override {
return osx_is_key_pressed(scancode);
}
int getUnicodeFromScancode(KeyScancode scancode) override {
return osx_get_unicode_from_scancode(scancode);
}
};
} // namespace she
#endif

View File

@ -53,6 +53,8 @@
- (void)updateCurrentCursor; - (void)updateCurrentCursor;
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender; - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender; - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
- (void)doCommandBySelector:(SEL)selector;
- (void)setTranslateDeadKeys:(BOOL)state;
@end @end
#endif #endif

View File

@ -16,15 +16,22 @@
#include "she/keys.h" #include "she/keys.h"
#include "she/osx/generate_drop_files.h" #include "she/osx/generate_drop_files.h"
#include "she/osx/window.h" #include "she/osx/window.h"
#include "she/system.h"
using namespace she; #include <Carbon/Carbon.h> // For VK codes
namespace she {
bool osx_is_key_pressed(KeyScancode scancode);
namespace { namespace {
// Internal array of pressed keys used in is_key_pressed() // Internal array of pressed keys used in isKeyPressed()
bool pressed_keys[kKeyScancodes]; int g_pressedKeys[kKeyScancodes];
bool g_translateDeadKeys = false;
UInt32 g_lastDeadKeyState = 0;
inline gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event) gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event)
{ {
NSPoint point = [view convertPoint:[event locationInWindow] NSPoint point = [view convertPoint:[event locationInWindow]
fromView:nil]; fromView:nil];
@ -37,7 +44,7 @@ inline gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event)
(view.bounds.size.height - point.y) / scale); (view.bounds.size.height - point.y) / scale);
} }
inline Event::MouseButton get_mouse_buttons(NSEvent* event) Event::MouseButton get_mouse_buttons(NSEvent* event)
{ {
// Some Wacom drivers on OS X report right-clicks with // Some Wacom drivers on OS X report right-clicks with
// buttonNumber=0, so we've to check the type event anyway. // buttonNumber=0, so we've to check the type event anyway.
@ -61,7 +68,7 @@ inline Event::MouseButton get_mouse_buttons(NSEvent* event)
return Event::MouseButton::NoneButton; return Event::MouseButton::NoneButton;
} }
inline KeyModifiers get_modifiers_from_nsevent(NSEvent* event) KeyModifiers get_modifiers_from_nsevent(NSEvent* event)
{ {
int modifiers = kKeyNoneModifier; int modifiers = kKeyNoneModifier;
NSEventModifierFlags nsFlags = event.modifierFlags; NSEventModifierFlags nsFlags = event.modifierFlags;
@ -69,37 +76,71 @@ inline KeyModifiers get_modifiers_from_nsevent(NSEvent* event)
if (nsFlags & NSControlKeyMask) modifiers |= kKeyCtrlModifier; if (nsFlags & NSControlKeyMask) modifiers |= kKeyCtrlModifier;
if (nsFlags & NSAlternateKeyMask) modifiers |= kKeyAltModifier; if (nsFlags & NSAlternateKeyMask) modifiers |= kKeyAltModifier;
if (nsFlags & NSCommandKeyMask) modifiers |= kKeyCmdModifier; if (nsFlags & NSCommandKeyMask) modifiers |= kKeyCmdModifier;
if (she::is_key_pressed(kKeySpace)) modifiers |= kKeySpaceModifier; if (osx_is_key_pressed(kKeySpace)) modifiers |= kKeySpaceModifier;
return (KeyModifiers)modifiers; return (KeyModifiers)modifiers;
} }
inline int get_unicodechar_from_nsevent(NSEvent* event) // Based on code from:
// http://stackoverflow.com/questions/22566665/how-to-capture-unicode-from-key-events-without-an-nstextview
// http://stackoverflow.com/questions/12547007/convert-key-code-into-key-equivalent-string
// http://stackoverflow.com/questions/8263618/convert-virtual-key-code-to-unicode-string
//
// It includes a "translateDeadKeys" flag to avoid processing dead
// keys in case that we want to use key
CFStringRef get_unicode_from_key_code(NSEvent* event,
const bool translateDeadKeys)
{ {
int chr = 0; TISInputSourceRef inputSource = TISCopyCurrentKeyboardInputSource();
// TODO we should use "event.characters" for a new kind of event (Event::Char or something like that) CFDataRef keyLayoutData = (CFDataRef)TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData);
NSString* chars = event.charactersIgnoringModifiers; const UCKeyboardLayout* keyLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(keyLayoutData);
if (chars && chars.length >= 1) {
chr = [chars characterAtIndex:0]; UInt32 deadKeyState = (translateDeadKeys ? g_lastDeadKeyState: 0);
if (chr < 32) UniChar output[4];
chr = 0; UniCharCount length;
}
return chr; // Reference here:
// https://developer.apple.com/reference/coreservices/1390584-uckeytranslate?language=objc
UCKeyTranslate(
keyLayout,
event.keyCode,
kUCKeyActionDown,
((event.modifierFlags >> 16) & 0xFF),
LMGetKbdType(),
(translateDeadKeys ? 0: kUCKeyTranslateNoDeadKeysMask),
&deadKeyState,
sizeof(output) / sizeof(output[0]),
&length,
output);
if (translateDeadKeys)
g_lastDeadKeyState = deadKeyState;
CFRelease(inputSource);
return CFStringCreateWithCharacters(kCFAllocatorDefault, output, length);
} }
} // anonymous namespace } // anonymous namespace
namespace she { bool osx_is_key_pressed(KeyScancode scancode)
bool is_key_pressed(KeyScancode scancode)
{ {
if (scancode >= 0 && scancode < kKeyScancodes) if (scancode >= 0 && scancode < kKeyScancodes)
return pressed_keys[scancode]; return (g_pressedKeys[scancode] != 0);
else else
return false; return false;
} }
int osx_get_unicode_from_scancode(KeyScancode scancode)
{
if (scancode >= 0 && scancode < kKeyScancodes)
return g_pressedKeys[scancode];
else
return 0;
}
} // namespace she } // namespace she
using namespace she;
@implementation OSXView @implementation OSXView
- (id)initWithFrame:(NSRect)frameRect - (id)initWithFrame:(NSRect)frameRect
@ -167,17 +208,47 @@ bool is_key_pressed(KeyScancode scancode)
[super keyDown:event]; [super keyDown:event];
KeyScancode scancode = cocoavk_to_scancode(event.keyCode); KeyScancode scancode = cocoavk_to_scancode(event.keyCode);
if (scancode >= 0 && scancode < kKeyScancodes)
pressed_keys[scancode] = true;
Event ev; Event ev;
ev.setType(Event::KeyDown); ev.setType(Event::KeyDown);
ev.setScancode(scancode); ev.setScancode(scancode);
ev.setModifiers(get_modifiers_from_nsevent(event)); ev.setModifiers(get_modifiers_from_nsevent(event));
ev.setRepeat(event.ARepeat ? 1: 0); ev.setRepeat(event.ARepeat ? 1: 0);
ev.setUnicodeChar(get_unicodechar_from_nsevent(event)); ev.setUnicodeChar(0);
queue_event(ev); bool sendMsg = true;
CFStringRef strRef = get_unicode_from_key_code(event, false);
if (strRef) {
int length = CFStringGetLength(strRef);
if (length == 1)
ev.setUnicodeChar(CFStringGetCharacterAtIndex(strRef, 0));
CFRelease(strRef);
}
if (scancode >= 0 && scancode < kKeyScancodes)
g_pressedKeys[scancode] = (ev.unicodeChar() ? ev.unicodeChar(): 1);
if (g_translateDeadKeys) {
strRef = get_unicode_from_key_code(event, true);
if (strRef) {
int length = CFStringGetLength(strRef);
if (length > 0) {
sendMsg = false;
for (int i=0; i<length; ++i) {
ev.setUnicodeChar(CFStringGetCharacterAtIndex(strRef, i));
queue_event(ev);
}
g_lastDeadKeyState = 0;
}
else {
ev.setDeadKey(true);
}
CFRelease(strRef);
}
}
if (sendMsg)
queue_event(ev);
} }
- (void)keyUp:(NSEvent*)event - (void)keyUp:(NSEvent*)event
@ -186,14 +257,14 @@ bool is_key_pressed(KeyScancode scancode)
KeyScancode scancode = cocoavk_to_scancode(event.keyCode); KeyScancode scancode = cocoavk_to_scancode(event.keyCode);
if (scancode >= 0 && scancode < kKeyScancodes) if (scancode >= 0 && scancode < kKeyScancodes)
pressed_keys[scancode] = false; g_pressedKeys[scancode] = 0;
Event ev; Event ev;
ev.setType(Event::KeyUp); ev.setType(Event::KeyUp);
ev.setScancode(scancode); ev.setScancode(scancode);
ev.setModifiers(get_modifiers_from_nsevent(event)); ev.setModifiers(get_modifiers_from_nsevent(event));
ev.setRepeat(event.ARepeat ? 1: 0); ev.setRepeat(event.ARepeat ? 1: 0);
ev.setUnicodeChar(get_unicodechar_from_nsevent(event)); ev.setUnicodeChar(0);
queue_event(ev); queue_event(ev);
} }
@ -230,7 +301,7 @@ bool is_key_pressed(KeyScancode scancode)
((newFlags & flags[i]) != 0 ? Event::KeyDown: ((newFlags & flags[i]) != 0 ? Event::KeyDown:
Event::KeyUp)); Event::KeyUp));
pressed_keys[scancodes[i]] = ((newFlags & flags[i]) != 0); g_pressedKeys[scancodes[i]] = ((newFlags & flags[i]) != 0);
ev.setScancode(scancodes[i]); ev.setScancode(scancodes[i]);
ev.setModifiers(modifiers); ev.setModifiers(modifiers);
@ -517,4 +588,15 @@ bool is_key_pressed(KeyScancode scancode)
return NO; return NO;
} }
- (void)doCommandBySelector:(SEL)selector
{
// Do nothing (avoid beep pressing Escape key)
}
- (void)setTranslateDeadKeys:(BOOL)state
{
g_translateDeadKeys = (state ? true: false);
g_lastDeadKeyState = 0;
}
@end @end

View File

@ -24,15 +24,8 @@
namespace she { namespace she {
static System* g_instance; System* create_system_impl() {
return new SkiaSystem();
System* create_system() {
return g_instance = new SkiaSystem();
}
System* instance()
{
return g_instance;
} }
void error_message(const char* msg) void error_message(const char* msg)
@ -41,19 +34,11 @@ void error_message(const char* msg)
// TODO // TODO
} }
void clear_keyboard_buffer()
{
// Do nothing
}
} // namespace she } // namespace she
extern int app_main(int argc, char* argv[]); extern int app_main(int argc, char* argv[]);
#if _WIN32 #if _WIN32
extern int __argc;
extern wchar_t** __wargv;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow) { PWSTR lpCmdLine, int nCmdShow) {
int argc = __argc; int argc = __argc;

View File

@ -184,6 +184,11 @@ void SkiaDisplay::setLayout(const std::string& layout)
m_window.setLayout(layout); m_window.setLayout(layout);
} }
void SkiaDisplay::setTranslateDeadKeys(bool state)
{
m_window.setTranslateDeadKeys(state);
}
DisplayHandle SkiaDisplay::nativeHandle() DisplayHandle SkiaDisplay::nativeHandle()
{ {
return (DisplayHandle)m_window.handle(); return (DisplayHandle)m_window.handle();

View File

@ -60,6 +60,8 @@ public:
std::string getLayout() override; std::string getLayout() override;
void setLayout(const std::string& layout) override; void setLayout(const std::string& layout) override;
void setTranslateDeadKeys(bool state);
// Returns the HWND on Windows. // Returns the HWND on Windows.
DisplayHandle nativeHandle() override; DisplayHandle nativeHandle() override;

View File

@ -21,7 +21,8 @@
#elif __APPLE__ #elif __APPLE__
#include "she/osx/app.h" #include "she/osx/app.h"
#include "she/osx/event_queue.h" #include "she/osx/event_queue.h"
#define SkiaSystemBase CommonSystem #include "she/osx/system.h"
#define SkiaSystemBase OSXSystem
#else #else
#include "she/x11/event_queue.h" #include "she/x11/event_queue.h"
#define SkiaSystemBase CommonSystem #define SkiaSystemBase CommonSystem
@ -135,6 +136,15 @@ public:
return loadSurface(filename); return loadSurface(filename);
} }
void setTranslateDeadKeys(bool state) override {
if (m_defaultDisplay)
m_defaultDisplay->setTranslateDeadKeys(state);
#ifdef _WIN32
g_queue.setTranslateDeadKeys(state);
#endif
}
private: private:
SkiaDisplay* m_defaultDisplay; SkiaDisplay* m_defaultDisplay;
bool m_gpuAcceleration; bool m_gpuAcceleration;

View File

@ -1,5 +1,5 @@
// SHE library // SHE library
// Copyright (C) 2012-2015 David Capello // Copyright (C) 2012-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -46,6 +46,7 @@ public:
void updateWindow(const gfx::Rect& bounds); void updateWindow(const gfx::Rect& bounds);
std::string getLayout() { return ""; } std::string getLayout() { return ""; }
void setLayout(const std::string& layout) { } void setLayout(const std::string& layout) { }
void setTranslateDeadKeys(bool state);
void* handle(); void* handle();
private: private:

View File

@ -15,6 +15,7 @@
#include "gfx/size.h" #include "gfx/size.h"
#include "she/event.h" #include "she/event.h"
#include "she/event_queue.h" #include "she/event_queue.h"
#include "she/osx/view.h"
#include "she/osx/window.h" #include "she/osx/window.h"
#include "she/skia/skia_display.h" #include "she/skia/skia_display.h"
#include "she/skia/skia_surface.h" #include "she/skia/skia_surface.h"
@ -122,6 +123,11 @@ public:
[view displayIfNeeded]; [view displayIfNeeded];
} }
void setTranslateDeadKeys(bool state) {
OSXView* view = (OSXView*)m_window.contentView;
[view setTranslateDeadKeys:(state ? YES: NO)];
}
void* handle() { void* handle() {
return (__bridge void*)m_window; return (__bridge void*)m_window;
} }
@ -450,6 +456,12 @@ void SkiaWindow::updateWindow(const gfx::Rect& bounds)
m_impl->updateWindow(bounds); m_impl->updateWindow(bounds);
} }
void SkiaWindow::setTranslateDeadKeys(bool state)
{
if (m_impl)
m_impl->setTranslateDeadKeys(state);
}
void* SkiaWindow::handle() void* SkiaWindow::handle()
{ {
if (m_impl) if (m_impl)

View File

@ -44,6 +44,10 @@ public:
std::string getLayout() { return ""; } std::string getLayout() { return ""; }
void setLayout(const std::string& layout) { } void setLayout(const std::string& layout) { }
void setTranslateDeadKeys(bool state) {
// Do nothing
}
private: private:
void onExpose() override; void onExpose() override;

31
src/she/system.cpp Normal file
View File

@ -0,0 +1,31 @@
// SHE library
// Copyright (C) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "base/debug.h"
#include "she/system.h"
namespace she {
static System* g_system = nullptr;
System* create_system_impl(); // Defined on each back-end
System* create_system()
{
ASSERT(!g_system);
return g_system = create_system_impl();
}
System* instance()
{
return g_system;
}
} // namespace she

View File

@ -10,6 +10,7 @@
#include "gfx/fwd.h" #include "gfx/fwd.h"
#include "she/capabilities.h" #include "she/capabilities.h"
#include "she/keys.h"
#include <stdexcept> #include <stdexcept>
@ -49,6 +50,26 @@ namespace she {
virtual Surface* loadRgbaSurface(const char* filename) = 0; virtual Surface* loadRgbaSurface(const char* filename) = 0;
virtual Font* loadSpriteSheetFont(const char* filename, int scale = 1) = 0; virtual Font* loadSpriteSheetFont(const char* filename, int scale = 1) = 0;
virtual Font* loadTrueTypeFont(const char* filename, int height) = 0; virtual Font* loadTrueTypeFont(const char* filename, int height) = 0;
// Returns true if the the given scancode key is pressed/actived.
virtual bool isKeyPressed(KeyScancode scancode) = 0;
// Returns the active pressed modifiers.
virtual KeyModifiers keyModifiers() = 0;
// Returns the latest unicode character that activated the given
// scancode.
virtual int getUnicodeFromScancode(KeyScancode scancode) = 0;
// Clears the keyboard buffer (used only in the Allegro port).
// TODO (deprecated)
virtual void clearKeyboardBuffer() = 0;
// Indicates if you want to use dead keys or not. By default it's
// false, which behaves as regular shortcuts. You should set this
// to true when you're inside a text field in your app.
virtual void setTranslateDeadKeys(bool state) = 0;
}; };
System* create_system(); System* create_system();

Some files were not shown because too many files have changed in this diff Show More