Merge branch '1.0'

Conflicts:
	.gitmodules
	CMakeLists.txt
	src/CMakeLists.txt
	src/app/app.h
	src/app/app_menus.cpp
	src/app/commands/cmd_move_mask.cpp
	src/app/commands/cmd_rotate.cpp
	src/app/modules/gui.cpp
	src/doc/resize_image_tests.cpp
	src/ui/accelerator.cpp
	third_party/CMakeLists.txt
This commit is contained in:
David Capello 2014-10-30 01:06:27 -03:00
commit 39b8e034b5
73 changed files with 2387 additions and 3739 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "third_party/pixman"]
path = third_party/pixman
url = git@github.com:aseprite/pixman.git
[submodule "third_party/simpleini"]
path = third_party/simpleini
url = git@github.com:aseprite/simpleini.git

View File

@ -42,6 +42,7 @@ option(USE_SHARED_LIBPNG "Use your installed copy of libpng" off)
option(USE_SHARED_LIBLOADPNG "Use your installed copy of libloadpng" off)
option(USE_SHARED_TINYXML "Use your installed copy of tinyxml" off)
option(USE_SHARED_GTEST "Use your installed copy of gtest" off)
option(USE_SHARED_PIXMAN "Use your installed copy of pixman" 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_UPDATER "Enable automatic check for updates" on)
@ -88,6 +89,7 @@ set(LIBJPEG_DIR ${CMAKE_SOURCE_DIR}/third_party/jpeg)
set(LIBPNG_DIR ${CMAKE_SOURCE_DIR}/third_party/libpng)
set(LOADPNG_DIR ${CMAKE_SOURCE_DIR}/third_party/loadpng)
set(MONGOOSE_DIR ${CMAKE_SOURCE_DIR}/third_party/mongoose)
set(PIXMAN_DIR ${CMAKE_SOURCE_DIR}/third_party/pixman)
set(SIMPLEINI_DIR ${CMAKE_SOURCE_DIR}/third_party/simpleini)
set(TINYXML_DIR ${CMAKE_SOURCE_DIR}/third_party/tinyxml)
set(ZLIB_DIR ${CMAKE_SOURCE_DIR}/third_party/zlib)

View File

@ -2,7 +2,7 @@
<!-- ASE menus, tools and keyboard shortcuts -->
<gui version="1.0.6-dev">
<!-- Keyboard shortcuts -->
<keyboard>
<keyboard version="1">
<!-- Keyboard shortcuts for commands (menu options) -->
<commands>
@ -51,6 +51,7 @@
<key command="ConfigureTools" shortcut="C" />
<key command="Options" shortcut="Ctrl+K" mac="Cmd+," />
<key command="Options" shortcut="Ctrl+Shift+O" mac="Cmd+Shift+O" /> <!-- TODO remove this shortcut in v1.1 -->
<key command="KeyboardShortcuts" shortcut="Ctrl+Alt+Shift+K" mac="Cmd+Alt+Shift+K" />
<!-- Sprite -->
<key command="SpriteProperties" shortcut="Ctrl+P" mac="Cmd+P" />
<!-- Layer -->
@ -88,6 +89,7 @@
<key command="SplitEditorHorizontally" shortcut="Ctrl+3" mac="Cmd+3" />
<key command="Preview" shortcut="F8" />
<key command="ShowGrid" shortcut="Shift+G" />
<key command="ShowPixelGrid" shortcut="Alt+Shift+G" />
<key command="SnapToGrid" shortcut="Shift+S" />
<key command="ShowOnionSkin" shortcut="F3" />
<key command="Timeline" shortcut="Tab">
@ -344,8 +346,8 @@
<key tool="hand" shortcut="Space" />
</quicktools>
<!-- Special keyboard shortcuts for the sprite editor -->
<spriteeditor>
<!-- Special keyboard shortcuts for specific actions -->
<actions>
<!-- When you drag-and-drop the selection, pressing this
keyboard shortcut you can copy instead of move -->
<key action="CopySelection" shortcut="Ctrl" />
@ -369,7 +371,7 @@
<!-- Modifiers for selection tool -->
<key action="AddSelection" shortcut="Shift" />
<key action="SubtractSelection" shortcut="Alt" />
</spriteeditor>
</actions>
</keyboard>
@ -435,6 +437,7 @@
</menu>
<separator />
<item command="ConfigureTools" text="Tool&amp;s..." />
<item command="KeyboardShortcuts" text="&amp;Keyboard Shortcuts..." />
<item command="Options" text="Pre&amp;ferences..." />
</menu>
<menu text="&amp;Sprite">
@ -549,6 +552,7 @@
<item command="SplitEditorVertically" text="Split &amp;Vertically" />
<item command="SplitEditorHorizontally" text="Split &amp;Horizontally" />
<separator />
<item command="ShowPixelGrid" text="Show &amp;Pixel Grid" />
<item command="ShowGrid" text="Show &amp;Grid" />
<item command="SnapToGrid" text="&amp;Snap to Grid" />
<item command="GridSettings" text="Gri&amp;d Settings" />

View File

@ -0,0 +1,35 @@
<!-- Aseprite -->
<!-- Copyright (C) 2001-2014 by David Capello -->
<gui>
<window id="keyboard_shortcuts" text="Keyboard Shortcuts">
<hbox>
<vbox expansive="true">
<hbox>
<label text="Section:" />
<combobox id="section" expansive="true" />
</hbox>
<view id="menus_view" expansive="true">
<listbox id="menus" />
</view>
<view id="commands_view" expansive="true">
<listbox id="commands" />
</view>
<view id="tools_view" expansive="true">
<listbox id="tools" />
</view>
<view id="actions_view" expansive="true">
<listbox id="actions" />
</view>
</vbox>
<vbox>
<button text="&amp;OK" closewindow="true" id="ok" magnet="true" width="60" />
<button text="&amp;Cancel" closewindow="true" />
<separator horizontal="true" />
<button text="&amp;Import" id="import_button" />
<button text="&amp;Export" id="export_button" />
<separator horizontal="true" />
<button text="&amp;Reset" id="reset_button" />
</vbox>
</hbox>
</window>
</gui>

View File

@ -0,0 +1,36 @@
<!-- Aseprite -->
<!-- Copyright (C) 2001-2014 by David Capello -->
<gui>
<window id="select_accelerator" text="Keyboard Shortcut">
<vbox expansive="true">
<grid columns="3" expansive="true">
<label text="Key:" />
<hbox id="key_placeholder" expansive="true" />
<button text="Clear" id="clear_button" width="60" />
<label text="Modifiers:" />
<hbox cell_hspan="2">
<check text="Ctrl" id="ctrl" />
<check text="Cmd" id="cmd" />
<check text="Alt" id="alt" />
<check text="Shift" id="shift" />
<check text="Space" id="space" />
</hbox>
<label text="Assigned to:" />
<label text="" id="assigned_to" cell_hspan="2" />
</grid>
<separator horizontal="true" />
<box horizontal="true">
<boxfiller />
<box horizontal="true" homogeneous="true">
<button text="OK" id="ok_button" magnet="true" width="60" />
<button text="Cancel" id="cancel_button" />
</box>
</box>
</vbox>
</window>
</gui>

View File

@ -134,6 +134,18 @@ else()
include_directories(${LOADPNG_DIR})
endif()
if(USE_SHARED_PIXMAN)
find_library(LIBPIXMAN_LIBRARY NAMES pixman)
find_path(LIBPIXMAN_INCLUDE_DIR NAMES pixman.h)
set(libs3rdparty ${libs3rdparty} ${LIBPIXMAN_LIBRARY})
include_directories(${LIBPIXMAN_INCLUDE_DIR})
else()
set(libs3rdparty ${libs3rdparty} pixman)
include_directories(${PIXMAN_DIR}/pixman)
include_directories(${CMAKE_BINARY_DIR})
endif()
set(libs3rdparty simpleini ${libs3rdparty})
include_directories(${SIMPLEINI_DIR})
@ -319,7 +331,7 @@ function(find_tests dir dependencies)
endfunction()
find_tests(base base-lib ${sys_libs})
find_tests(gfx gfx-lib base-lib ${sys_libs})
find_tests(gfx gfx-lib base-lib ${libs3rdparty} ${sys_libs})
find_tests(doc doc-lib gfx-lib base-lib ${libs3rdparty} ${sys_libs})
find_tests(css css-lib gfx-lib base-lib ${libs3rdparty} ${sys_libs})
find_tests(ui ui-lib she gfx-lib base-lib ${libs3rdparty} ${sys_libs})

View File

@ -44,6 +44,7 @@ add_library(app-lib
commands/cmd_grid.cpp
commands/cmd_import_sprite_sheet.cpp
commands/cmd_invert_mask.cpp
commands/cmd_keyboard_shortcuts.cpp
commands/cmd_launch.cpp
commands/cmd_layer_from_background.cpp
commands/cmd_layer_properties.cpp
@ -185,6 +186,7 @@ add_library(app-lib
ui/file_list.cpp
ui/file_selector.cpp
ui/hex_color_entry.cpp
ui/keyboard_shortcuts.cpp
ui/main_menu_bar.cpp
ui/main_window.cpp
ui/mini_editor.cpp
@ -194,6 +196,7 @@ add_library(app-lib
ui/palettes_listbox.cpp
ui/popup_window_pin.cpp
ui/resources_listbox.cpp
ui/select_accelerator.cpp
ui/skin/button_icon_impl.cpp
ui/skin/skin_part.cpp
ui/skin/skin_property.cpp

View File

@ -54,6 +54,7 @@
#include "app/ui/document_view.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/editor_view.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "app/ui/tabs.h"
@ -326,7 +327,8 @@ App::~App()
delete m_legacy;
delete m_modules;
// Destroy the loaded gui.xml file.
// Destroy the loaded gui.xml data.
delete KeyboardShortcuts::instance();
delete GuiXml::instance();
m_instance = NULL;

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -29,12 +29,6 @@
#include <string>
#include <vector>
namespace ui {
class MenuBar;
class Widget;
class Window;
}
namespace doc {
class Layer;
}
@ -108,7 +102,7 @@ namespace app {
void app_rebuild_documents_tabs();
PixelFormat app_get_current_pixel_format();
void app_default_statusbar_message();
int app_get_color_to_clear_layer(Layer* layer);
int app_get_color_to_clear_layer(doc::Layer* layer);
} // namespace app

View File

@ -1,5 +1,5 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -28,13 +28,15 @@
#include "app/commands/params.h"
#include "app/console.h"
#include "app/gui_xml.h"
#include "app/modules/gui.h"
#include "app/recent_files.h"
#include "app/resource_finder.h"
#include "app/tools/tool_box.h"
#include "app/ui/app_menuitem.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/util/filetoks.h"
#include "base/bind.h"
#include "base/fs.h"
#include "base/path.h"
#include "ui/ui.h"
@ -74,9 +76,8 @@ void AppMenus::reload()
TiXmlHandle handle(doc);
const char* path = GuiXml::instance()->filename();
/**************************************************/
/* load menus */
/**************************************************/
////////////////////////////////////////
// Load menus
PRINTF(" - Loading menus from \"%s\"...\n", path);
@ -94,127 +95,25 @@ void AppMenus::reload()
m_celPopupMenu.reset(loadMenuById(handle, "cel_popup"));
m_celMovementPopupMenu.reset(loadMenuById(handle, "cel_movement_popup"));
/**************************************************/
/* load keyboard shortcuts for commands */
/**************************************************/
////////////////////////////////////////
// Load keyboard shortcuts for commands
PRINTF(" - Loading commands keyboard shortcuts from \"%s\"...\n", path);
// <gui><keyboard><commands><key>
TiXmlElement* xmlKey = handle
.FirstChild("gui")
.FirstChild("keyboard")
.FirstChild("commands")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* command_name = xmlKey->Attribute("command");
const char* command_key = getShortcut(xmlKey);
.FirstChild("keyboard").ToElement();
if (command_name && command_key) {
Command* command = CommandsModule::instance()->getCommandByName(command_name);
if (command) {
// Read context
KeyContext keycontext = KeyContext::Any;
const char* keycontextstr = xmlKey->Attribute("context");
if (keycontextstr) {
if (strcmp(keycontextstr, "Selection") == 0)
keycontext = KeyContext::Selection;
else if (strcmp(keycontextstr, "Normal") == 0)
keycontext = KeyContext::Normal;
}
KeyboardShortcuts::instance()->clear();
KeyboardShortcuts::instance()->importFile(xmlKey, KeySource::Original);
// Read params
Params params;
TiXmlElement* xmlParam = xmlKey->FirstChildElement("param");
while (xmlParam) {
const char* param_name = xmlParam->Attribute("name");
const char* param_value = xmlParam->Attribute("value");
if (param_name && param_value)
params.set(param_name, param_value);
xmlParam = xmlParam->NextSiblingElement();
}
bool first_shortcut =
(get_accel_to_execute_command(command_name, &params) == NULL);
PRINTF(" - Shortcut for command `%s' <%s>\n", command_name, command_key);
// add the keyboard shortcut to the command
Accelerator* accel =
add_keyboard_shortcut_to_execute_command(command_key, command_name, &params, keycontext);
// add the shortcut to the menuitems with this
// command (this is only visual, the "manager_msg_proc"
// is the only one that process keyboard shortcuts)
if (first_shortcut)
applyShortcutToMenuitemsWithCommand(m_rootMenu, command, &params, accel);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load keyboard shortcuts for tools
PRINTF(" - Loading tools keyboard shortcuts from \"%s\"...\n", path);
// <gui><keyboard><tools><key>
xmlKey = handle
.FirstChild("gui")
.FirstChild("keyboard")
.FirstChild("tools")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = getShortcut(xmlKey);
if (tool_id && tool_key) {
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
if (tool) {
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
add_keyboard_shortcut_to_change_tool(tool_key, tool);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load keyboard shortcuts for quicktools
// <gui><keyboard><quicktools><key>
xmlKey = handle
.FirstChild("gui")
.FirstChild("keyboard")
.FirstChild("quicktools")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = getShortcut(xmlKey);
if (tool_id && tool_key) {
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
if (tool) {
PRINTF(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key);
add_keyboard_shortcut_to_quicktool(tool_key, tool);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load special keyboard shortcuts for sprite editor customization
// <gui><keyboard><spriteeditor>
xmlKey = handle
.FirstChild("gui")
.FirstChild("keyboard")
.FirstChild("spriteeditor")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_action = xmlKey->Attribute("action");
const char* tool_key = getShortcut(xmlKey);
if (tool_action && tool_key) {
PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key);
add_keyboard_shortcut_to_spriteeditor(tool_key, tool_action);
}
xmlKey = xmlKey->NextSiblingElement();
// Load user settings
{
ResourceFinder rf;
rf.includeUserDir("user.aseprite-keys");
std::string fn = rf.getFirstOrCreateDefault();
if (base::is_file(fn))
KeyboardShortcuts::instance()->importFile(fn, KeySource::UserDefined);
}
}
@ -379,7 +278,12 @@ Widget* AppMenus::createInvalidVersionMenuitem()
return menuitem;
}
void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command *command, Params* params, Accelerator* accel)
void AppMenus::applyShortcutToMenuitemsWithCommand(Command* command, Params* params, Key* key)
{
applyShortcutToMenuitemsWithCommand(m_rootMenu, command, params, key);
}
void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Key* key)
{
UI_FOREACH_WIDGET(menu->getChildren(), it) {
Widget* child = *it;
@ -396,32 +300,14 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu, Command *command,
base::string_to_lower(command->short_name())) &&
((mi_params && *mi_params == *params) ||
(Params() == *params))) {
// Set the accelerator to be shown in this menu-item
menuitem->setAccel(new Accelerator(*accel));
// Set the keyboard shortcut to be shown in this menu-item
menuitem->setKey(key);
}
if (Menu* submenu = menuitem->getSubmenu())
applyShortcutToMenuitemsWithCommand(submenu, command, params, accel);
applyShortcutToMenuitemsWithCommand(submenu, command, params, key);
}
}
}
const char* AppMenus::getShortcut(TiXmlElement* elem)
{
const char* shortcut = NULL;
#if defined ALLEGRO_WINDOWS
if (!shortcut) shortcut = elem->Attribute("win");
#elif defined ALLEGRO_MACOSX
if (!shortcut) shortcut = elem->Attribute("mac");
#elif defined ALLEGRO_UNIX
if (!shortcut) shortcut = elem->Attribute("linux");
#endif
if (!shortcut)
shortcut = elem->Attribute("shortcut");
return shortcut;
}
} // namespace app

View File

@ -28,11 +28,8 @@
class TiXmlElement;
class TiXmlHandle;
namespace ui {
class Accelerator;
}
namespace app {
class Key;
class Command;
class Params;
@ -59,13 +56,14 @@ namespace app {
Menu* getCelPopupMenu() { return m_celPopupMenu; }
Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu; }
void applyShortcutToMenuitemsWithCommand(Command* command, Params* params, Key* key);
private:
Menu* loadMenuById(TiXmlHandle& handle, const char *id);
Menu* convertXmlelemToMenu(TiXmlElement* elem);
Widget* convertXmlelemToMenuitem(TiXmlElement* elem);
Widget* createInvalidVersionMenuitem();
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Accelerator* accel);
const char* getShortcut(TiXmlElement* elem);
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, Params* params, Key* key);
base::UniquePtr<Menu> m_rootMenu;
MenuItem* m_recentListMenuitem;

View File

@ -25,7 +25,7 @@
#include "app/find_widget.h"
#include "app/ini_file.h"
#include "app/load_widget.h"
#include "app/modules/gui.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "ui/ui.h"
@ -74,19 +74,14 @@ void AdvancedModeCommand::onExecute(Context* context)
if (oldMode == MainWindow::NormalMode &&
get_config_bool("AdvancedMode", "Warning", true)) {
Accelerator* accel = get_accel_to_execute_command(short_name());
if (accel != NULL) {
char warning[1024];
char buf[1024];
Key* key = KeyboardShortcuts::instance()->command(short_name());
if (!key->accels().empty()) {
base::UniquePtr<Window> window(app::load_widget<Window>("advanced_mode.xml", "advanced_mode_warning"));
Widget* warning_label = app::find_widget<Widget>(window, "warning_label");
Widget* donot_show = app::find_widget<Widget>(window, "donot_show");
strcpy(warning, "You can back pressing the \"%s\" key.");
std::sprintf(buf, warning, accel->toString().c_str());
warning_label->setText(buf);
warning_label->setTextf("You can go back pressing \"%s\" key.",
key->accels().front().toString().c_str());
window->openWindowInForeground();

View File

@ -48,7 +48,7 @@ private:
CancelCommand::CancelCommand()
: Command("Cancel",
"Cancel",
"Cancel Current Operation",
CmdUIOnlyFlag)
, m_type(NoOp)
{

View File

@ -48,6 +48,7 @@ public:
protected:
void onLoadParams(Params* params);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
};
ChangeBrushCommand::ChangeBrushCommand()
@ -96,6 +97,30 @@ void ChangeBrushCommand::onExecute(Context* context)
}
}
std::string ChangeBrushCommand::onGetFriendlyName() const
{
std::string text = "Brush";
switch (m_change) {
case None:
break;
case IncrementSize:
text += ": Increment Size";
break;
case DecrementSize:
text += ": Decrement Size";
break;
case IncrementAngle:
text += ": Increment Angle";
break;
case DecrementAngle:
text += ": Decrement Angle";
break;
}
return text;
}
Command* CommandFactory::createChangeBrushCommand()
{
return new ChangeBrushCommand;

View File

@ -50,6 +50,7 @@ public:
protected:
void onLoadParams(Params* params);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
};
ChangeColorCommand::ChangeColorCommand()
@ -108,6 +109,29 @@ void ChangeColorCommand::onExecute(Context* context)
colorbar->setFgColor(color);
}
std::string ChangeColorCommand::onGetFriendlyName() const
{
std::string text = "Color";
switch (m_change) {
case None:
return text;
case IncrementIndex:
text += ": Increment";
break;
case DecrementIndex:
text += ": Decrement";
break;
}
if (m_background)
text += " Background Index";
else
text += " Foreground Index";
return text;
}
Command* CommandFactory::createChangeColorCommand()
{
return new ChangeColorCommand;

View File

@ -49,7 +49,7 @@ protected:
DeveloperConsoleCommand::DeveloperConsoleCommand()
: Command("DeveloperConsole",
"DeveloperConsole",
"Developer Console",
CmdUIOnlyFlag)
{
m_devConsole = NULL;

View File

@ -188,6 +188,23 @@ void FlipCommand::onExecute(Context* context)
update_screen_for_document(document);
}
std::string FlipCommand::onGetFriendlyName() const
{
std::string text = "Flip";
if (m_flipMask)
text += " Selection";
else
text += " Canvas";
if (m_flipType == doc::algorithm::FlipHorizontal)
text += " Horizontal";
else
text += " Vertical";
return text;
}
Command* CommandFactory::createFlipCommand()
{
return new FlipCommand;

View File

@ -36,6 +36,7 @@ namespace app {
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
private:
bool m_flipMask;

View File

@ -56,7 +56,7 @@ class GotoFirstFrameCommand : public GotoCommand {
public:
GotoFirstFrameCommand()
: GotoCommand("GotoFirstFrame",
"Goto First Frame") { }
"Go to First Frame") { }
Command* clone() const override { return new GotoFirstFrameCommand(*this); }
protected:
@ -69,7 +69,7 @@ class GotoPreviousFrameCommand : public GotoCommand {
public:
GotoPreviousFrameCommand()
: GotoCommand("GotoPreviousFrame",
"Goto Previous Frame") { }
"Go to Previous Frame") { }
Command* clone() const override { return new GotoPreviousFrameCommand(*this); }
protected:
@ -86,7 +86,7 @@ protected:
class GotoNextFrameCommand : public GotoCommand {
public:
GotoNextFrameCommand() : GotoCommand("GotoNextFrame",
"Goto Next Frame") { }
"Go to Next Frame") { }
Command* clone() const override { return new GotoNextFrameCommand(*this); }
protected:
@ -102,7 +102,7 @@ protected:
class GotoLastFrameCommand : public GotoCommand {
public:
GotoLastFrameCommand() : GotoCommand("GotoLastFrame",
"Goto Last Frame") { }
"Go to Last Frame") { }
Command* clone() const override { return new GotoLastFrameCommand(*this); }
protected:
@ -114,7 +114,7 @@ protected:
class GotoFrameCommand : public GotoCommand {
public:
GotoFrameCommand() : GotoCommand("GotoFrame",
"Goto Frame")
"Go to Frame")
, m_frame(0) { }
Command* clone() const override { return new GotoFrameCommand(*this); }

View File

@ -59,7 +59,7 @@ protected:
GotoPreviousLayerCommand::GotoPreviousLayerCommand()
: GotoCommand("GotoPreviousLayer",
"Goto Previous Layer",
"Go to Previous Layer",
CmdUIOnlyFlag)
{
}
@ -101,7 +101,7 @@ protected:
GotoNextLayerCommand::GotoNextLayerCommand()
: GotoCommand("GotoNextLayer",
"Goto Next Layer",
"Go to Next Layer",
CmdUIOnlyFlag)
{
}

View File

@ -39,7 +39,7 @@ protected:
GotoNextTabCommand::GotoNextTabCommand()
: Command("GotoNextTab",
"Goto Next Tab",
"Go to Next Tab",
CmdUIOnlyFlag)
{
}
@ -60,7 +60,7 @@ protected:
GotoPreviousTabCommand::GotoPreviousTabCommand()
: Command("GotoPreviousTab",
"Goto Previous tab",
"Go to Previous tab",
CmdRecordableFlag)
{
}

View File

@ -65,6 +65,33 @@ protected:
}
};
class ShowPixelGridCommand : public Command {
public:
ShowPixelGridCommand()
: Command("ShowPixelGrid",
"Show Pixel Grid",
CmdUIOnlyFlag)
{
}
Command* clone() const override { return new ShowPixelGridCommand(*this); }
protected:
bool onChecked(Context* context)
{
IDocumentSettings* docSettings = context->settings()->getDocumentSettings(context->activeDocument());
return docSettings->getPixelGridVisible();
}
void onExecute(Context* context)
{
IDocumentSettings* docSettings = context->settings()->getDocumentSettings(context->activeDocument());
docSettings->setPixelGridVisible(docSettings->getPixelGridVisible() ? false: true);
}
};
class SnapToGridCommand : public Command {
public:
SnapToGridCommand()
@ -155,6 +182,11 @@ Command* CommandFactory::createShowGridCommand()
return new ShowGridCommand;
}
Command* CommandFactory::createShowPixelGridCommand()
{
return new ShowPixelGridCommand;
}
Command* CommandFactory::createSnapToGridCommand()
{
return new SnapToGridCommand;

View File

@ -0,0 +1,511 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/context.h"
#include "app/file_selector.h"
#include "app/modules/gui.h"
#include "app/resource_finder.h"
#include "app/tools/tool.h"
#include "app/ui/app_menuitem.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/select_accelerator.h"
#include "app/ui/skin/skin_theme.h"
#include "base/bind.h"
#include "base/fs.h"
#include "base/path.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/paint_event.h"
#include "ui/preferred_size_event.h"
#include "ui/resize_event.h"
#include "generated_keyboard_shortcuts.h"
#define KEYBOARD_FILENAME_EXTENSION "aseprite-keys"
namespace app {
using namespace ui;
using namespace skin;
static int g_sep = 0;
class KeyItem : public ListItem {
public:
KeyItem(const std::string& text, Key* key, AppMenuItem* menuitem, int level)
: ListItem(text)
, m_key(key)
, m_keyOrig(key ? new Key(*key): NULL)
, m_menuitem(menuitem)
, m_level(level)
, m_changeButton(NULL)
, m_deleteButton(NULL)
, m_addButton(NULL)
, m_hotAccel(-1) {
this->border_width.t = this->border_width.b = 0;
}
~KeyItem() {
destroyButtons();
}
void restoreKeys() {
if (m_key && m_keyOrig)
*m_key = *m_keyOrig;
if (m_menuitem && !m_keyOrig)
m_menuitem->setKey(NULL);
}
private:
void onChangeAccel(int index) {
Accelerator origAccel = m_key->accels()[index];
SelectAccelerator window(origAccel);
window.openWindowInForeground();
if (window.isModified()) {
m_key->disableAccel(origAccel);
m_key->add(window.accel(), KeySource::UserDefined);
}
getRoot()->layout();
}
void onDeleteAccel(int index)
{
if (Alert::show("Warning"
"<<Do you really want to delete this keyboard shortcut?"
"||&Yes||&No") != 1)
return;
m_key->disableAccel(m_key->accels()[index]);
getRoot()->layout();
}
void onAddAccel() {
ui::Accelerator accel;
SelectAccelerator window(accel);
window.openWindowInForeground();
if (window.isModified()) {
if (!m_key) {
ASSERT(m_menuitem);
if (!m_menuitem)
return;
m_key = app::KeyboardShortcuts::instance()->command(
m_menuitem->getCommand()->short_name(),
m_menuitem->getParams());
m_menuitem->setKey(m_key);
}
m_key->add(window.accel(), KeySource::UserDefined);
}
getRoot()->layout();
}
void onPreferredSize(PreferredSizeEvent& ev) override {
gfx::Size size = getTextSize();
size.w = this->border_width.l + size.w + this->border_width.r;
size.h = this->border_width.t + size.h + this->border_width.b
+ 4*jguiscale();
if (m_key && !m_key->accels().empty()) {
size_t combos = m_key->accels().size();
if (combos > 1)
size.h *= combos;
}
ev.setPreferredSize(size);
}
void onPaint(PaintEvent& ev) override {
Graphics* g = ev.getGraphics();
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
gfx::Rect bounds = getClientBounds();
gfx::Color fg, bg;
if (isSelected()) {
fg = theme->getColor(ThemeColor::ListItemSelectedText);
bg = theme->getColor(ThemeColor::ListItemSelectedFace);
}
else {
fg = theme->getColor(ThemeColor::ListItemNormalText);
bg = theme->getColor(ThemeColor::ListItemNormalFace);
}
g->fillRect(bg, bounds);
bounds.shrink(getBorder());
g->drawUIString(getText(), fg, bg,
gfx::Point(
bounds.x + m_level*16 * jguiscale(),
bounds.y + 2*jguiscale()));
if (m_key && !m_key->accels().empty()) {
std::string buf;
int y = bounds.y;
int dh = getTextSize().h + 4*jguiscale();
int i = 0;
for (const Accelerator& accel : m_key->accels()) {
if (i != m_hotAccel || !m_changeButton) {
g->drawString(accel.toString(), fg, bg,
gfx::Point(bounds.x + g_sep, y + 2*jguiscale()));
}
y += dh;
++i;
}
}
}
void onResize(ResizeEvent& ev) override {
ListItem::onResize(ev);
destroyButtons();
}
bool onProcessMessage(Message* msg) override {
switch (msg->type()) {
case kMouseLeaveMessage: {
m_hotAccel = -1;
destroyButtons();
invalidate();
break;
}
case kMouseMoveMessage: {
gfx::Rect bounds = getBounds();
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
int hotAccel = -1;
const Accelerators* accels = (m_key ? &m_key->accels() : NULL);
int y = bounds.y;
int dh = getTextSize().h + 4*jguiscale();
int maxi = (accels && accels->size() > 1 ? accels->size(): 1);
for (int i=0; i<maxi; ++i, y += dh) {
int w = Graphics::measureUIStringLength(
(accels && i < (int)accels->size() ? (*accels)[i].toString().c_str(): ""),
getFont());
gfx::Rect itemBounds(bounds.x + g_sep, y, w, dh);
if (mouseMsg->position().y >= bounds.y &&
mouseMsg->position().y < bounds.y+bounds.h) {
itemBounds = itemBounds.enlarge(
gfx::Border(
4*jguiscale(), 0,
6*jguiscale(), 1*jguiscale()));
if (accels && i < (int)accels->size() &&
mouseMsg->position().y >= itemBounds.y &&
mouseMsg->position().y < itemBounds.y+itemBounds.h) {
hotAccel = i;
if (!m_changeButton) {
m_changeButton = new Button("");
m_changeButton->Click.connect(Bind<void>(&KeyItem::onChangeAccel, this, i));
setup_mini_look(m_changeButton);
addChild(m_changeButton);
}
if (!m_deleteButton) {
m_deleteButton = new Button("");
m_deleteButton->Click.connect(Bind<void>(&KeyItem::onDeleteAccel, this, i));
setup_mini_look(m_deleteButton);
addChild(m_deleteButton);
}
m_changeButton->setBgColor(gfx::ColorNone);
m_changeButton->setBounds(itemBounds);
m_changeButton->setText((*accels)[i].toString());
const char* label = "x";
m_deleteButton->setBgColor(gfx::ColorNone);
m_deleteButton->setBounds(gfx::Rect(
itemBounds.x + itemBounds.w + 2*jguiscale(),
itemBounds.y,
Graphics::measureUIStringLength(
label, getFont()) + 4*jguiscale(),
itemBounds.h));
m_deleteButton->setText(label);
invalidate();
}
if (i == 0 && (!m_menuitem || m_menuitem->getCommand())) {
if (!m_addButton) {
m_addButton = new Button("");
m_addButton->Click.connect(Bind<void>(&KeyItem::onAddAccel, this));
setup_mini_look(m_addButton);
addChild(m_addButton);
}
itemBounds.w = 8*jguiscale() + Graphics::measureUIStringLength("Add", getFont());
itemBounds.x -= itemBounds.w + 2*jguiscale();
m_addButton->setBgColor(gfx::ColorNone);
m_addButton->setBounds(itemBounds);
m_addButton->setText("Add");
invalidate();
}
}
}
if (m_hotAccel != hotAccel) {
if (hotAccel == -1)
destroyButtons();
m_hotAccel = hotAccel;
invalidate();
}
break;
}
}
return ListItem::onProcessMessage(msg);
}
void destroyButtons() {
delete m_changeButton;
delete m_deleteButton;
delete m_addButton;
m_changeButton = NULL;
m_deleteButton = NULL;
m_addButton = NULL;
}
Key* m_key;
Key* m_keyOrig;
AppMenuItem* m_menuitem;
int m_level;
ui::Accelerators m_newAccels;
ui::Button* m_changeButton;
ui::Button* m_deleteButton;
ui::Button* m_addButton;
int m_hotAccel;
};
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
public:
KeyboardShortcutsWindow() {
setAutoRemap(false);
section()->addItem("Menus");
section()->addItem("Commands");
section()->addItem("Tools");
section()->addItem("Action Modifiers");
section()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
importButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onImport, this));
exportButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onExport, this));
resetButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onReset, this));
fillAllLists();
}
void restoreKeys() {
for (KeyItem* keyItem : m_allKeyItems) {
keyItem->restoreKeys();
}
}
private:
void deleteAllKeyItems() {
while (menus()->getLastChild())
menus()->removeChild(menus()->getLastChild());
while (commands()->getLastChild())
commands()->removeChild(commands()->getLastChild());
while (tools()->getLastChild())
tools()->removeChild(tools()->getLastChild());
while (actions()->getLastChild())
actions()->removeChild(actions()->getLastChild());
for (KeyItem* keyItem : m_allKeyItems) {
delete keyItem;
}
m_allKeyItems.clear();
}
void fillAllLists() {
deleteAllKeyItems();
// Load keyboard shortcuts
fillList(this->menus(), AppMenus::instance()->getRootMenu(), 0);
for (Key* key : *app::KeyboardShortcuts::instance()) {
std::string text = key->triggerString();
if (key->keycontext() == KeyContext::Selection)
text += " (w/selection)";
KeyItem* keyItem = new KeyItem(text, key, NULL, 0);
ListBox* listBox = NULL;
switch (key->type()) {
case KeyType::Command:
listBox = this->commands();
break;
case KeyType::Tool:
case KeyType::Quicktool: {
listBox = this->tools();
break;
}
case KeyType::Action:
listBox = this->actions();
break;
}
ASSERT(listBox);
if (listBox) {
m_allKeyItems.push_back(keyItem);
listBox->addChild(keyItem);
}
}
this->commands()->sortItems();
this->tools()->sortItems();
this->actions()->sortItems();
onSectionChange();
}
void onSectionChange() {
int section = this->section()->getSelectedItemIndex();
menusView()->setVisible(section == 0);
commandsView()->setVisible(section == 1);
toolsView()->setVisible(section == 2);
actionsView()->setVisible(section == 3);
layout();
}
void onImport() {
std::string filename = app::show_file_selector("Import Keyboard Shortcuts", "",
KEYBOARD_FILENAME_EXTENSION);
if (filename.empty())
return;
app::KeyboardShortcuts::instance()->importFile(filename.c_str(), KeySource::UserDefined);
fillAllLists();
layout();
}
void onExport() {
again:
std::string filename = app::show_file_selector("Export Keyboard Shortcuts", "",
KEYBOARD_FILENAME_EXTENSION);
if (!filename.empty()) {
if (base::is_file(filename)) {
int ret = Alert::show("Warning<<File exists, overwrite it?<<%s||&Yes||&No||&Cancel",
base::get_file_name(filename).c_str());
if (ret == 2)
goto again;
else if (ret != 1)
return;
}
app::KeyboardShortcuts::instance()->exportFile(filename.c_str());
}
}
void onReset() {
if (Alert::show("Warning"
"<<Do you want to restore all keyboard shortcuts"
"<<to their original default settings?"
"||&Yes||&No") == 1) {
app::KeyboardShortcuts::instance()->reset();
layout();
}
}
void fillList(ListBox* listbox, Menu* menu, int level) {
for (Widget* child : menu->getChildren()) {
if (AppMenuItem* menuItem = dynamic_cast<AppMenuItem*>(child)) {
if (menuItem == AppMenus::instance()->getRecentListMenuitem())
continue;
KeyItem* keyItem = new KeyItem(
menuItem->getText().c_str(),
menuItem->getKey(), menuItem, level);
listbox->addChild(keyItem);
if (menuItem->hasSubmenu())
fillList(listbox, menuItem->getSubmenu(), level+1);
}
}
}
std::vector<KeyItem*> m_allKeyItems;
};
class KeyboardShortcutsCommand : public Command {
public:
KeyboardShortcutsCommand();
Command* clone() const override { return new KeyboardShortcutsCommand(*this); }
protected:
void onExecute(Context* context);
};
KeyboardShortcutsCommand::KeyboardShortcutsCommand()
: Command("KeyboardShortcuts",
"Keyboard Shortcuts",
CmdUIOnlyFlag)
{
}
void KeyboardShortcutsCommand::onExecute(Context* context)
{
KeyboardShortcutsWindow window;
window.setBounds(gfx::Rect(0, 0, ui::display_w()*3/4, ui::display_h()*3/4));
g_sep = window.getBounds().w / 2;
window.centerWindow();
window.setVisible(true);
window.openWindowInForeground();
if (window.getKiller() == window.ok()) {
// Save keyboard shortcuts in configuration file
{
ResourceFinder rf;
rf.includeUserDir("user." KEYBOARD_FILENAME_EXTENSION);
std::string fn = rf.getFirstOrCreateDefault();
KeyboardShortcuts::instance()->exportFile(fn);
}
}
else {
window.restoreKeys();
}
}
Command* CommandFactory::createKeyboardShortcutsCommand()
{
return new KeyboardShortcutsCommand;
}
} // namespace app

View File

@ -32,6 +32,7 @@
#include "app/ui/editor/editor.h"
#include "app/undo_transaction.h"
#include "app/undoers/set_mask_position.h"
#include "base/convert_to.h"
#include "doc/mask.h"
#include "doc/sprite.h"
#include "ui/view.h"
@ -146,6 +147,65 @@ void MoveMaskCommand::onExecute(Context* context)
}
}
std::string MoveMaskCommand::onGetFriendlyName() const
{
std::string text = "Move";
switch (m_target) {
case Boundaries: {
text += " Selection Boundaries";
break;
}
case Content: {
text += " Selection Content";
break;
}
}
text += " " + base::convert_to<std::string>(m_quantity);
switch (m_units) {
case Pixel:
text += " pixel";
break;
case TileWidth:
text += " horizontal tile";
break;
case TileHeight:
text += " vertical tile";
break;
case ZoomedPixel:
text += " zoomed pixel";
break;
case ZoomedTileWidth:
text += " zoomed horizontal tile";
break;
case ZoomedTileHeight:
text += " zoomed vertical tile";
break;
case ViewportWidth:
text += " viewport width";
break;
case ViewportHeight:
text += " viewport height";
break;
}
if (m_quantity != 1)
text += "s";
switch (m_direction) {
case Left: text += " left"; break;
case Right: text += " right"; break;
case Up: text += " up"; break;
case Down: text += " down"; break;
}
return text;
}
Command* CommandFactory::createMoveMaskCommand()
{
return new MoveMaskCommand;

View File

@ -48,6 +48,7 @@ namespace app {
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
private:
Target m_target;

View File

@ -29,7 +29,6 @@
namespace app {
using namespace ui;
using namespace gfx;
class ShowOnionSkinCommand : public Command {

View File

@ -159,7 +159,7 @@ private:
PaletteEditorCommand::PaletteEditorCommand()
: Command("PaletteEditor",
"PaletteEditor",
"Palette Editor",
CmdRecordableFlag)
{
m_open = true;

View File

@ -28,10 +28,10 @@
#include "app/context.h"
#include "app/modules/editors.h"
#include "app/modules/gfx.h"
#include "app/modules/gui.h"
#include "app/settings/document_settings.h"
#include "app/settings/settings.h"
#include "app/ui/editor/editor.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/status_bar.h"
#include "app/util/render.h"
#include "doc/conversion_she.h"
@ -127,7 +127,8 @@ protected:
case kKeyDownMessage: {
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
Command* command = NULL;
get_command_from_key_message(msg, &command, NULL);
KeyboardShortcuts::instance()
->getCommandFromKeyMessage(msg, &command, NULL);
// Change frame
if (command != NULL &&

View File

@ -33,6 +33,7 @@
#include "app/ui/timeline.h"
#include "app/undo_transaction.h"
#include "app/util/range_utils.h"
#include "base/convert_to.h"
#include "doc/cel.h"
#include "doc/image.h"
#include "doc/mask.h"
@ -51,6 +52,7 @@ protected:
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
private:
bool m_flipMask;
@ -233,6 +235,20 @@ void RotateCommand::onExecute(Context* context)
update_screen_for_document(reader.document());
}
std::string RotateCommand::onGetFriendlyName() const
{
std::string text = "Rotate";
if (m_flipMask)
text += " Selection";
else
text += " Sprite";
text += " " + base::convert_to<std::string>(m_angle) + "\xc2\xb0";
return text;
}
Command* CommandFactory::createRotateCommand()
{
return new RotateCommand;

View File

@ -27,6 +27,7 @@
#include "app/settings/document_settings.h"
#include "app/settings/settings.h"
#include "app/ui/editor/editor.h"
#include "base/convert_to.h"
#include "ui/view.h"
namespace app {
@ -52,6 +53,7 @@ protected:
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
private:
Direction m_direction;
@ -142,6 +144,49 @@ void ScrollCommand::onExecute(Context* context)
current_editor->setEditorScroll(scroll.x+dx, scroll.y+dy, true);
}
std::string ScrollCommand::onGetFriendlyName() const
{
std::string text = "Scroll " + base::convert_to<std::string>(m_quantity);
switch (m_units) {
case Pixel:
text += " pixel";
break;
case TileWidth:
text += " horizontal tile";
break;
case TileHeight:
text += " vertical tile";
break;
case ZoomedPixel:
text += " zoomed pixel";
break;
case ZoomedTileWidth:
text += " zoomed horizontal tile";
break;
case ZoomedTileHeight:
text += " zoomed vertical tile";
break;
case ViewportWidth:
text += " viewport width";
break;
case ViewportHeight:
text += " viewport height";
break;
}
if (m_quantity != 1)
text += "s";
switch (m_direction) {
case Left: text += " left"; break;
case Right: text += " right"; break;
case Up: text += " up"; break;
case Down: text += " down"; break;
}
return text;
}
Command* CommandFactory::createScrollCommand()
{
return new ScrollCommand;

View File

@ -37,7 +37,7 @@ protected:
SwitchColorsCommand::SwitchColorsCommand()
: Command("SwitchColors",
"SwitchColors",
"Switch Colors",
CmdUIOnlyFlag)
{
}

View File

@ -24,6 +24,7 @@
#include "app/commands/params.h"
#include "app/modules/editors.h"
#include "app/ui/editor/editor.h"
#include "base/convert_to.h"
namespace app {
@ -38,6 +39,7 @@ protected:
void onLoadParams(Params* params);
bool onEnabled(Context* context);
void onExecute(Context* context);
std::string onGetFriendlyName() const;
private:
Action m_action;
@ -98,6 +100,25 @@ void ZoomCommand::onExecute(Context* context)
current_editor->setEditorZoom(zoom);
}
std::string ZoomCommand::onGetFriendlyName() const
{
std::string text = "Zoom";
switch (m_action) {
case In:
text += " in";
break;
case Out:
text += " out";
break;
case Set:
text += " " + base::convert_to<std::string>(m_percentage) + "%";
break;
}
return text;
}
Command* CommandFactory::createZoomCommand()
{
return new ZoomCommand;

View File

@ -37,6 +37,11 @@ Command::~Command()
{
}
std::string Command::friendlyName() const
{
return onGetFriendlyName();
}
void Command::loadParams(Params* params)
{
onLoadParams(params);
@ -101,4 +106,9 @@ void Command::onExecute(Context* context)
// Do nothing
}
std::string Command::onGetFriendlyName() const
{
return m_friendly_name;
}
} // namespace app

View File

@ -21,6 +21,7 @@
#pragma once
#include "app/commands/command_factory.h"
#include <string>
namespace app {
class Context;
@ -44,7 +45,7 @@ namespace app {
virtual Command* clone() const { return new Command(*this); }
const char* short_name() const { return m_short_name; }
const char* friendly_name() const { return m_friendly_name; }
std::string friendlyName() const;
void loadParams(Params* params);
bool isEnabled(Context* context);
@ -56,6 +57,7 @@ namespace app {
virtual bool onEnabled(Context* context);
virtual bool onChecked(Context* context);
virtual void onExecute(Context* context);
virtual std::string onGetFriendlyName() const;
};
} // namespace app

View File

@ -61,6 +61,7 @@ FOR_EACH_COMMAND(GridSettings)
FOR_EACH_COMMAND(ImportSpriteSheet)
FOR_EACH_COMMAND(InvertColor)
FOR_EACH_COMMAND(InvertMask)
FOR_EACH_COMMAND(KeyboardShortcuts)
FOR_EACH_COMMAND(Launch)
FOR_EACH_COMMAND(LayerFromBackground)
FOR_EACH_COMMAND(LayerProperties)
@ -102,6 +103,7 @@ FOR_EACH_COMMAND(Scroll)
FOR_EACH_COMMAND(SetPalette)
FOR_EACH_COMMAND(ShowGrid)
FOR_EACH_COMMAND(ShowOnionSkin)
FOR_EACH_COMMAND(ShowPixelGrid)
FOR_EACH_COMMAND(SnapToGrid)
FOR_EACH_COMMAND(SplitEditorHorizontally)
FOR_EACH_COMMAND(SplitEditorVertically)

View File

@ -26,58 +26,58 @@
namespace app {
class Params {
std::map<std::string, std::string> m_params;
public:
typedef std::map<std::string, std::string> Map;
typedef Map::iterator iterator;
typedef Map::const_iterator const_iterator;
iterator begin() { return m_params.begin(); }
iterator end() { return m_params.end(); }
const_iterator begin() const { return m_params.begin(); }
const_iterator end() const { return m_params.end(); }
Params() { }
Params(const Params& copy) : m_params(copy.m_params) { }
virtual ~Params() { }
Params* clone()
{
Params* clone() const {
return new Params(*this);
}
bool empty() const
{
bool empty() const {
return m_params.empty();
}
bool has_param(const char* name) const
{
bool has_param(const char* name) const {
return m_params.find(name) != m_params.end();
}
bool operator==(const Params& params) const
{
bool operator==(const Params& params) const {
return m_params == params.m_params;
}
bool operator!=(const Params& params) const
{
bool operator!=(const Params& params) const {
return m_params != params.m_params;
}
std::string& set(const char* name, const char* value)
{
std::string& set(const char* name, const char* value) {
return m_params[name] = value;
}
std::string& get(const char* name)
{
std::string& get(const char* name) {
return m_params[name];
}
template<typename T>
T get_as(const char* name)
{
T get_as(const char* name) {
std::istringstream stream(m_params[name]);
T value;
stream >> value;
return value;
}
private:
Map m_params;
};
} // namespace app

View File

@ -36,6 +36,7 @@
#include "app/tools/ink.h"
#include "app/tools/tool_box.h"
#include "app/ui/editor/editor.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_menu_bar.h"
#include "app/ui/main_menu_bar.h"
#include "app/ui/main_window.h"
@ -65,14 +66,6 @@
#include <windows.h>
#endif
#define SPRITEDITOR_ACTION_COPYSELECTION "CopySelection"
#define SPRITEDITOR_ACTION_SNAPTOGRID "SnapToGrid"
#define SPRITEDITOR_ACTION_ANGLESNAP "AngleSnap"
#define SPRITEDITOR_ACTION_MAINTAINASPECTRATIO "MaintainAspectRatio"
#define SPRITEDITOR_ACTION_LOCKAXIS "LockAxis"
#define SPRITEDITOR_ACTION_ADDSEL "AddSelection"
#define SPRITEDITOR_ACTION_SUBSEL "SubtractSelection"
namespace app {
using namespace gfx;
@ -92,38 +85,6 @@ static struct {
//////////////////////////////////////////////////////////////////////
struct Shortcut {
enum class Type {
ExecuteCommand,
ChangeTool,
EditorQuicktool,
SpriteEditor
};
Accelerator* accel;
Type type;
Command* command;
KeyContext keycontext;
tools::Tool* tool;
std::string action;
Params* params;
Shortcut(Type type);
~Shortcut();
void add_shortcut(const char* shortcut_string);
bool is_pressed(Message* msg);
bool is_pressed_from_key_array();
};
static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params);
static Shortcut* get_keyboard_shortcut_for_tool(tools::Tool* tool);
static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool);
static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name);
//////////////////////////////////////////////////////////////////////
class CustomizedGuiManager : public Manager
, public LayoutIO
{
@ -141,8 +102,6 @@ static she::Clipboard* main_clipboard = NULL;
static CustomizedGuiManager* manager = NULL;
static Theme* ase_theme = NULL;
static std::vector<Shortcut*>* shortcuts = NULL;
// Default GUI screen configuration
static int screen_scaling;
@ -152,25 +111,9 @@ static void reload_default_font();
static void load_gui_config(int& w, int& h, bool& maximized);
static void save_gui_config();
static KeyContext get_current_keycontext()
{
app::Context* ctx = UIContext::instance();
DocumentLocation location = ctx->activeLocation();
Document* doc = location.document();
if (doc &&
doc->isMaskVisible() &&
ctx->settings()->getCurrentTool()->getInk(0)->isSelection())
return KeyContext::Selection;
else
return KeyContext::Normal;
}
// Initializes GUI.
int init_module_gui()
{
shortcuts = new std::vector<Shortcut*>;
int w, h;
bool maximized;
load_gui_config(w, h, maximized);
@ -230,13 +173,6 @@ void exit_module_gui()
{
save_gui_config();
// destroy shortcuts
ASSERT(shortcuts != NULL);
for (Shortcut* shortcut : *shortcuts)
delete shortcut;
delete shortcuts;
shortcuts = NULL;
delete manager;
// Now we can destroy theme
@ -463,295 +399,6 @@ CheckBox* check_button_new(const char *text, int b1, int b2, int b3, int b4)
return widget;
}
//////////////////////////////////////////////////////////////////////
// Keyboard shortcuts
//////////////////////////////////////////////////////////////////////
Accelerator* add_keyboard_shortcut_to_execute_command(const char* shortcut_string,
const char* command_name, Params* params, KeyContext keyContext)
{
Shortcut* shortcut = get_keyboard_shortcut_for_command(command_name, params);
if (!shortcut) {
shortcut = new Shortcut(Shortcut::Type::ExecuteCommand);
shortcut->command = CommandsModule::instance()->getCommandByName(command_name);
shortcut->params = params ? params->clone(): new Params;
shortcut->keycontext = keyContext;
shortcuts->push_back(shortcut);
}
shortcut->add_shortcut(shortcut_string);
return shortcut->accel;
}
Accelerator* add_keyboard_shortcut_to_change_tool(const char* shortcut_string, tools::Tool* tool)
{
Shortcut* shortcut = get_keyboard_shortcut_for_tool(tool);
if (!shortcut) {
shortcut = new Shortcut(Shortcut::Type::ChangeTool);
shortcut->tool = tool;
shortcuts->push_back(shortcut);
}
shortcut->add_shortcut(shortcut_string);
return shortcut->accel;
}
Accelerator* add_keyboard_shortcut_to_quicktool(const char* shortcut_string, tools::Tool* tool)
{
Shortcut* shortcut = get_keyboard_shortcut_for_quicktool(tool);
if (!shortcut) {
shortcut = new Shortcut(Shortcut::Type::EditorQuicktool);
shortcut->tool = tool;
shortcuts->push_back(shortcut);
}
shortcut->add_shortcut(shortcut_string);
return shortcut->accel;
}
Accelerator* add_keyboard_shortcut_to_spriteeditor(const char* shortcut_string, const char* action_name)
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(action_name);
if (!shortcut) {
shortcut = new Shortcut(Shortcut::Type::SpriteEditor);
shortcut->action = action_name;
shortcuts->push_back(shortcut);
}
shortcut->add_shortcut(shortcut_string);
return shortcut->accel;
}
bool get_command_from_key_message(Message* msg, Command** command, Params** params)
{
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->type == Shortcut::Type::ExecuteCommand &&
shortcut->is_pressed(msg)) {
if (command) *command = shortcut->command;
if (params) *params = shortcut->params;
return true;
}
}
return false;
}
Accelerator* get_accel_to_execute_command(const char* command_name, Params* params)
{
Shortcut* shortcut = get_keyboard_shortcut_for_command(command_name, params);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_change_tool(tools::Tool* tool)
{
Shortcut* shortcut = get_keyboard_shortcut_for_tool(tool);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_copy_selection()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_COPYSELECTION);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_snap_to_grid()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_SNAPTOGRID);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_angle_snap()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_ANGLESNAP);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_maintain_aspect_ratio()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_MAINTAINASPECTRATIO);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_lock_axis()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_LOCKAXIS);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_add_selection()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_ADDSEL);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
Accelerator* get_accel_to_subtract_selection()
{
Shortcut* shortcut = get_keyboard_shortcut_for_spriteeditor(SPRITEDITOR_ACTION_SUBSEL);
if (shortcut)
return shortcut->accel;
else
return NULL;
}
tools::Tool* get_selected_quicktool(tools::Tool* currentTool)
{
if (currentTool && currentTool->getInk(0)->isSelection()) {
Accelerator* copyselection_accel = get_accel_to_copy_selection();
if (copyselection_accel && copyselection_accel->checkFromAllegroKeyArray())
return NULL;
}
tools::ToolBox* toolbox = App::instance()->getToolBox();
// Iterate over all tools
for (tools::ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Shortcut* shortcut = get_keyboard_shortcut_for_quicktool(*it);
// Collect all tools with the pressed keyboard-shortcut
if (shortcut && shortcut->is_pressed_from_key_array()) {
return *it;
}
}
return NULL;
}
Shortcut::Shortcut(Shortcut::Type type)
{
this->type = type;
this->accel = new Accelerator;
this->command = NULL;
this->keycontext = KeyContext::Any;
this->tool = NULL;
this->params = NULL;
}
Shortcut::~Shortcut()
{
delete params;
delete accel;
}
void Shortcut::add_shortcut(const char* shortcut_string)
{
this->accel->addKeysFromString(shortcut_string);
}
bool Shortcut::is_pressed(Message* msg)
{
bool res = false;
if (accel) {
res = accel->check(msg->keyModifiers(),
static_cast<KeyMessage*>(msg)->scancode(),
static_cast<KeyMessage*>(msg)->unicodeChar());
if (res &&
keycontext != KeyContext::Any &&
keycontext != get_current_keycontext()) {
res = false;
}
}
return res;
}
bool Shortcut::is_pressed_from_key_array()
{
bool res = false;
if (accel) {
res = accel->checkFromAllegroKeyArray();
if (res &&
keycontext != KeyContext::Any &&
keycontext != get_current_keycontext()) {
res = false;
}
}
return res;
}
static Shortcut* get_keyboard_shortcut_for_command(const char* command_name, Params* params)
{
Command* command = CommandsModule::instance()->getCommandByName(command_name);
if (!command)
return NULL;
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->type == Shortcut::Type::ExecuteCommand &&
shortcut->command == command &&
((!params && shortcut->params->empty()) ||
(params && *shortcut->params == *params))) {
return shortcut;
}
}
return NULL;
}
static Shortcut* get_keyboard_shortcut_for_tool(tools::Tool* tool)
{
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->type == Shortcut::Type::ChangeTool &&
shortcut->tool == tool) {
return shortcut;
}
}
return NULL;
}
static Shortcut* get_keyboard_shortcut_for_quicktool(tools::Tool* tool)
{
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->type == Shortcut::Type::EditorQuicktool &&
shortcut->tool == tool) {
return shortcut;
}
}
return NULL;
}
static Shortcut* get_keyboard_shortcut_for_spriteeditor(const char* action_name)
{
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->type == Shortcut::Type::SpriteEditor &&
shortcut->action == action_name) {
return shortcut;
}
}
return NULL;
}
// Manager event handler.
bool CustomizedGuiManager::onProcessMessage(Message* msg)
{
@ -802,26 +449,24 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
break;
}
for (Shortcut* shortcut : *shortcuts) {
if (shortcut->is_pressed(msg)) {
for (const Key* key : *KeyboardShortcuts::instance()) {
if (key->isPressed(msg)) {
// Cancel menu-bar loops (to close any popup menu)
App::instance()->getMainWindow()->getMenuBar()->cancelMenuLoop();
switch (shortcut->type) {
switch (key->type()) {
case Shortcut::Type::ChangeTool: {
case KeyType::Tool: {
tools::Tool* current_tool = UIContext::instance()->settings()->getCurrentTool();
tools::Tool* select_this_tool = shortcut->tool;
tools::Tool* select_this_tool = key->tool();
tools::ToolBox* toolbox = App::instance()->getToolBox();
std::vector<tools::Tool*> possibles;
// Iterate over all tools
for (tools::ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Shortcut* shortcut = get_keyboard_shortcut_for_tool(*it);
// Collect all tools with the pressed keyboard-shortcut
if (shortcut && shortcut->is_pressed(msg))
possibles.push_back(*it);
// Collect all tools with the pressed keyboard-shortcut
for (tools::Tool* tool : *toolbox) {
Key* key = KeyboardShortcuts::instance()->tool(tool);
if (key && key->isPressed(msg))
possibles.push_back(tool);
}
if (possibles.size() >= 2) {
@ -852,8 +497,8 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
return true;
}
case Shortcut::Type::ExecuteCommand: {
Command* command = shortcut->command;
case KeyType::Command: {
Command* command = key->command();
// Commands are executed only when the main window is
// the current window running at foreground.
@ -868,16 +513,17 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
else if (child->isDesktop() && child == App::instance()->getMainWindow()) {
// OK, so we can execute the command represented
// by the pressed-key in the message...
UIContext::instance()->executeCommand(command, shortcut->params);
UIContext::instance()->executeCommand(
command, key->params());
return true;
}
}
break;
}
case Shortcut::Type::EditorQuicktool: {
case KeyType::Quicktool: {
// Do nothing, it is used in the editor through the
// get_selected_quicktool() function.
// KeyboardShortcuts::getCurrentQuicktool() function.
break;
}

View File

@ -22,10 +22,7 @@
#include "app/ui/skin/skin_property.h"
#include "base/exception.h"
#include "ui/accelerator.h"
#include "ui/base.h"
#include <list>
#include <string>
namespace ui {
class ButtonBase;
@ -45,12 +42,6 @@ namespace app {
class Tool;
}
enum class KeyContext {
Any,
Normal,
Selection,
};
int init_module_gui();
void exit_module_gui();
@ -78,29 +69,6 @@ namespace app {
ui::CheckBox* check_button_new(const char* text, int b1, int b2, int b3, int b4);
//////////////////////////////////////////////////////////////////////
// Keyboard shortcuts
ui::Accelerator* add_keyboard_shortcut_to_execute_command(const char* shortcut,
const char* command_name, Params* params, KeyContext keyContext);
ui::Accelerator* add_keyboard_shortcut_to_change_tool(const char* shortcut, tools::Tool* tool);
ui::Accelerator* add_keyboard_shortcut_to_quicktool(const char* shortcut, tools::Tool* tool);
ui::Accelerator* add_keyboard_shortcut_to_spriteeditor(const char* shortcut, const char* action_name);
bool get_command_from_key_message(ui::Message* msg, Command** command, Params** params);
ui::Accelerator* get_accel_to_execute_command(const char* command, Params* params = NULL);
ui::Accelerator* get_accel_to_change_tool(tools::Tool* tool);
ui::Accelerator* get_accel_to_copy_selection();
ui::Accelerator* get_accel_to_snap_to_grid();
ui::Accelerator* get_accel_to_angle_snap();
ui::Accelerator* get_accel_to_maintain_aspect_ratio();
ui::Accelerator* get_accel_to_lock_axis();
ui::Accelerator* get_accel_to_add_selection();
ui::Accelerator* get_accel_to_subtract_selection();
tools::Tool* get_selected_quicktool(tools::Tool* currentTool);
} // namespace app
#endif

View File

@ -272,10 +272,10 @@ void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, R
break;
}
Rect outsideBounds = outside.getBounds();
Rect outsideBounds = outside.bounds();
if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0);
if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h)));
int x1 = outside.getBounds().x;
int x1 = outside.bounds().x;
while (true) {
Region in_sprite;
@ -283,7 +283,7 @@ void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, R
outside.createSubtraction(outside, in_sprite);
dirty_area.createUnion(dirty_area, in_sprite);
outsideBounds = outside.getBounds();
outsideBounds = outside.bounds();
if (outsideBounds.isEmpty())
break;
else if (outsideBounds.x+outsideBounds.w > w)

View File

@ -25,9 +25,12 @@
#include "app/commands/command.h"
#include "app/commands/params.h"
#include "app/modules/gui.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui_context.h"
#include "ui/accelerator.h"
#include "ui/menu.h"
#include "ui/message.h"
#include "ui/preferred_size_event.h"
#include "ui/widget.h"
#include <stdarg.h>
@ -38,8 +41,9 @@ namespace app {
using namespace ui;
AppMenuItem::AppMenuItem(const char* text, Command* command, Params* params)
AppMenuItem::AppMenuItem(const char* text, Command* command, const Params* params)
: MenuItem(text)
, m_key(NULL)
, m_command(command)
, m_params(params ? params->clone(): NULL)
{
@ -82,6 +86,31 @@ bool AppMenuItem::onProcessMessage(Message* msg)
return MenuItem::onProcessMessage(msg);
}
void AppMenuItem::onPreferredSize(PreferredSizeEvent& ev)
{
gfx::Size size(0, 0);
if (hasText()) {
size.w =
+ this->border_width.l
+ getTextWidth()
+ (inBar() ? this->child_spacing/4: this->child_spacing)
+ this->border_width.r;
size.h =
+ this->border_width.t
+ getTextHeight()
+ this->border_width.b;
if (m_key && !m_key->accels().empty()) {
size.w += Graphics::measureUIStringLength(
m_key->accels().front().toString().c_str(), getFont());
}
}
ev.setPreferredSize(size);
}
void AppMenuItem::onClick()
{
MenuItem::onClick();

View File

@ -23,6 +23,7 @@
#include "ui/menu.h"
namespace app {
class Key;
class Command;
class Params;
@ -33,17 +34,22 @@ namespace app {
// used to check the availability of the command).
class AppMenuItem : public ui::MenuItem {
public:
AppMenuItem(const char* text, Command* command, Params* params);
AppMenuItem(const char* text, Command* command, const Params* params);
~AppMenuItem();
Key* getKey() { return m_key; }
void setKey(Key* key) { m_key = key; }
Command* getCommand() { return m_command; }
Params* getParams() { return m_params; }
protected:
bool onProcessMessage(ui::Message* msg) override;
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
void onClick() override;
private:
Key* m_key;
Command* m_command;
Params* m_params;
};

View File

@ -24,11 +24,11 @@
#include "app/app.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/ui/editor/editor.h"
#include "app/ui/editor/editor_customization_delegate.h"
#include "app/ui/editor/editor_view.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/mini_editor.h"
#include "app/ui/workspace.h"
@ -77,61 +77,42 @@ public:
// EditorCustomizationDelegate implementation
tools::Tool* getQuickTool(tools::Tool* currentTool) override {
return get_selected_quicktool(currentTool);
return KeyboardShortcuts::instance()
->getCurrentQuicktool(currentTool);
}
bool isCopySelectionKeyPressed() override {
Accelerator* accel = get_accel_to_copy_selection();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::CopySelection);
}
bool isSnapToGridKeyPressed() override {
Accelerator* accel = get_accel_to_snap_to_grid();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::SnapToGrid);
}
bool isAngleSnapKeyPressed() override {
Accelerator* accel = get_accel_to_angle_snap();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::AngleSnap);
}
bool isMaintainAspectRatioKeyPressed() override {
Accelerator* accel = get_accel_to_maintain_aspect_ratio();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::MaintainAspectRatio);
}
bool isLockAxisKeyPressed() override {
Accelerator* accel = get_accel_to_lock_axis();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::LockAxis);
}
bool isAddSelectionPressed() override {
Accelerator* accel = get_accel_to_add_selection();
if (accel)
return accel->checkFromAllegroKeyArray();
else
return false;
return isKeyActionPressed(KeyAction::AddSelection);
}
bool isSubtractSelectionPressed() override {
Accelerator* accel = get_accel_to_subtract_selection();
if (accel)
return accel->checkFromAllegroKeyArray();
return isKeyActionPressed(KeyAction::SubtractSelection);
}
private:
bool isKeyActionPressed(KeyAction action) {
if (Key* key = KeyboardShortcuts::instance()->action(action))
return key->checkFromAllegroKeyArray();
else
return false;
}

View File

@ -25,13 +25,13 @@
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/modules/gui.h"
#include "app/tools/controller.h"
#include "app/tools/ink.h"
#include "app/tools/tool.h"
#include "app/tools/tool_loop.h"
#include "app/tools/tool_loop_manager.h"
#include "app/ui/editor/editor.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui_context.h"
#include "doc/blend.h"
#include "ui/message.h"
@ -178,7 +178,8 @@ bool DrawingState::onKeyDown(Editor* editor, KeyMessage* msg)
Command* command = NULL;
Params* params = NULL;
if (get_command_from_key_message(msg, &command, &params)) {
if (KeyboardShortcuts::instance()
->getCommandFromKeyMessage(msg, &command, &params)) {
// We accept zoom commands.
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
UIContext::instance()->executeCommand(command, params);

View File

@ -411,9 +411,11 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in
}
she::Surface* tmp(she::instance()->createRgbaSurface(width, height));
convert_image_to_surface(rendered, m_sprite->getPalette(m_frame),
tmp, 0, 0, 0, 0, width, height);
g->blit(tmp, 0, 0, dest_x, dest_y, width, height);
if (tmp->nativeHandle()) {
convert_image_to_surface(rendered, m_sprite->getPalette(m_frame),
tmp, 0, 0, 0, 0, width, height);
g->blit(tmp, 0, 0, dest_x, dest_y, width, height);
}
tmp->dispose();
}
}

View File

@ -28,7 +28,6 @@
#include "app/commands/cmd_move_mask.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/modules/gui.h"
#include "app/settings/settings.h"
#include "app/tools/ink.h"
#include "app/tools/tool.h"
@ -38,6 +37,7 @@
#include "app/ui/editor/pixels_movement.h"
#include "app/ui/editor/standby_state.h"
#include "app/ui/editor/transform_handles.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/status_bar.h"
#include "app/ui_context.h"
@ -326,7 +326,8 @@ bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
else {
Command* command = NULL;
Params* params = NULL;
if (get_command_from_key_message(msg, &command, &params)) {
if (KeyboardShortcuts::instance()
->getCommandFromKeyMessage(msg, &command, &params)) {
// We accept zoom commands.
if (strcmp(command->short_name(), CommandId::Zoom) == 0) {
UIContext::instance()->executeCommand(command, params);

View File

@ -265,7 +265,7 @@ public:
void updateDirtyArea() override
{
m_dirtyBounds = m_dirtyBounds.createUnion(m_dirtyArea.getBounds());
m_dirtyBounds = m_dirtyBounds.createUnion(m_dirtyArea.bounds());
m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea);
}

View File

@ -0,0 +1,589 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/keyboard_shortcuts.h"
#include "app/app.h"
#include "app/app_menus.h"
#include "app/commands/command.h"
#include "app/commands/commands.h"
#include "app/commands/params.h"
#include "app/document.h"
#include "app/document_location.h"
#include "app/settings/settings.h"
#include "app/tools/ink.h"
#include "app/tools/tool.h"
#include "app/tools/tool_box.h"
#include "app/ui_context.h"
#include "app/xml_document.h"
#include "app/xml_exception.h"
#include "ui/accelerator.h"
#include "ui/message.h"
#include <algorithm>
#define XML_KEYBOARD_FILE_VERSION "1"
namespace {
static struct {
const char* name;
const char* userfriendly;
app::KeyAction action;
} actions[] = {
{ "CopySelection" , "Copy Selection" , app::KeyAction::CopySelection },
{ "SnapToGrid" , "Snap To Grid" , app::KeyAction::SnapToGrid },
{ "AngleSnap" , "Angle Snap" , app::KeyAction::AngleSnap },
{ "MaintainAspectRatio" , "Maintain Aspect Ratio", app::KeyAction::MaintainAspectRatio },
{ "LockAxis" , "Lock Axis" , app::KeyAction::LockAxis },
{ "AddSelection" , "Add Selection" , app::KeyAction::AddSelection },
{ "SubtractSelection" , "Subtract Selection" , app::KeyAction::SubtractSelection },
{ NULL , NULL , app::KeyAction::None }
};
const char* get_shortcut(TiXmlElement* elem)
{
const char* shortcut = NULL;
#if defined ALLEGRO_WINDOWS
if (!shortcut) shortcut = elem->Attribute("win");
#elif defined ALLEGRO_MACOSX
if (!shortcut) shortcut = elem->Attribute("mac");
#elif defined ALLEGRO_UNIX
if (!shortcut) shortcut = elem->Attribute("linux");
#endif
if (!shortcut)
shortcut = elem->Attribute("shortcut");
return shortcut;
}
std::string get_user_friendly_string_for_keyaction(app::KeyAction action)
{
for (int c=0; actions[c].name; ++c) {
if (action == actions[c].action)
return actions[c].userfriendly;
}
return "";
}
} // anonymous namespace
namespace base {
template<> app::KeyAction convert_to(const std::string& from) {
app::KeyAction action = app::KeyAction::None;
for (int c=0; actions[c].name; ++c) {
if (from == actions[c].name)
return actions[c].action;
}
return action;
}
template<> std::string convert_to(const app::KeyAction& from) {
for (int c=0; actions[c].name; ++c) {
if (from == actions[c].action)
return actions[c].name;
}
return "";
}
} // namespace base
namespace app {
using namespace ui;
Key::Key(Command* command, const Params* params, KeyContext keyContext)
: m_type(KeyType::Command)
, m_useUsers(false)
, m_keycontext(keyContext)
, m_command(command)
, m_params(params ? params->clone(): NULL)
{
}
Key::Key(KeyType type, tools::Tool* tool)
: m_type(type)
, m_useUsers(false)
, m_keycontext(KeyContext::Any)
, m_tool(tool)
{
}
Key::Key(KeyAction action)
: m_type(KeyType::Action)
, m_useUsers(false)
, m_keycontext(KeyContext::Any)
, m_action(action)
{
}
void Key::setUserAccels(const Accelerators& accels)
{
m_useUsers = true;
m_users = accels;
}
void Key::add(const ui::Accelerator& accel, KeySource source)
{
Accelerators* accels = &m_accels;
if (source == KeySource::UserDefined) {
if (!m_useUsers) {
m_useUsers = true;
m_users = m_accels;
}
accels = &m_users;
KeyboardShortcuts::instance()->disableAccel(accel);
}
accels->push_back(accel);
}
bool Key::isPressed(Message* msg) const
{
ASSERT(dynamic_cast<KeyMessage*>(msg) != NULL);
for (const Accelerator& accel : accels()) {
if (accel.check(msg->keyModifiers(),
static_cast<KeyMessage*>(msg)->scancode(),
static_cast<KeyMessage*>(msg)->unicodeChar()) &&
(m_keycontext == KeyContext::Any ||
m_keycontext == KeyboardShortcuts::instance()->getCurrentKeyContext())) {
return true;
}
}
return false;
}
bool Key::checkFromAllegroKeyArray()
{
for (const Accelerator& accel : this->accels()) {
if (accel.checkFromAllegroKeyArray())
return true;
}
return false;
}
bool Key::hasAccel(const ui::Accelerator& accel) const
{
return (std::find(accels().begin(), accels().end(), accel) != accels().end());
}
void Key::disableAccel(const ui::Accelerator& accel)
{
if (!m_useUsers) {
m_useUsers = true;
m_users = m_accels;
}
Accelerators::iterator it = std::find(m_users.begin(), m_users.end(), accel);
if (it != m_users.end())
m_users.erase(it);
}
void Key::reset()
{
m_users.clear();
m_useUsers = false;
}
std::string Key::triggerString() const
{
switch (m_type) {
case KeyType::Command:
if (m_params)
m_command->loadParams(m_params);
return m_command->friendlyName();
case KeyType::Tool:
case KeyType::Quicktool: {
std::string text = m_tool->getText();
if (m_type == KeyType::Quicktool)
text += " (quick)";
return text;
}
case KeyType::Action:
return get_user_friendly_string_for_keyaction(m_action);
}
return "Unknown";
}
KeyboardShortcuts* KeyboardShortcuts::instance()
{
static KeyboardShortcuts* singleton = NULL;
if (!singleton)
singleton = new KeyboardShortcuts();
return singleton;
}
KeyboardShortcuts::KeyboardShortcuts()
{
}
KeyboardShortcuts::~KeyboardShortcuts()
{
clear();
}
void KeyboardShortcuts::clear()
{
for (Key* key : m_keys) {
delete key;
}
m_keys.clear();
}
void KeyboardShortcuts::importFile(TiXmlElement* rootElement, KeySource source)
{
// <keyboard><commands><key>
TiXmlHandle handle(rootElement);
TiXmlElement* xmlKey = handle
.FirstChild("commands")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* command_name = xmlKey->Attribute("command");
const char* command_key = get_shortcut(xmlKey);
if (command_name && command_key) {
Command* command = CommandsModule::instance()->getCommandByName(command_name);
if (command) {
// Read context
KeyContext keycontext = KeyContext::Any;
const char* keycontextstr = xmlKey->Attribute("context");
if (keycontextstr) {
if (strcmp(keycontextstr, "Selection") == 0)
keycontext = KeyContext::Selection;
else if (strcmp(keycontextstr, "Normal") == 0)
keycontext = KeyContext::Normal;
}
// Read params
Params params;
TiXmlElement* xmlParam = xmlKey->FirstChildElement("param");
while (xmlParam) {
const char* param_name = xmlParam->Attribute("name");
const char* param_value = xmlParam->Attribute("value");
if (param_name && param_value)
params.set(param_name, param_value);
xmlParam = xmlParam->NextSiblingElement();
}
PRINTF(" - Shortcut for command `%s' <%s>\n", command_name, command_key);
// add the keyboard shortcut to the command
Key* key = this->command(command_name, &params, keycontext);
if (key) {
key->add(Accelerator(command_key), source);
// Add the shortcut to the menuitems with this
// command (this is only visual, the "manager_msg_proc"
// is the only one that process keyboard shortcuts)
if (key->accels().size() == 1) {
AppMenus::instance()->applyShortcutToMenuitemsWithCommand(
command, &params, key);
}
}
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load keyboard shortcuts for tools
// <gui><keyboard><tools><key>
xmlKey = handle
.FirstChild("tools")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = get_shortcut(xmlKey);
if (tool_id && tool_key) {
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
if (tool) {
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);
Key* key = this->tool(tool);
if (key)
key->add(Accelerator(tool_key), source);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load keyboard shortcuts for quicktools
// <gui><keyboard><quicktools><key>
xmlKey = handle
.FirstChild("quicktools")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_id = xmlKey->Attribute("tool");
const char* tool_key = get_shortcut(xmlKey);
if (tool_id && tool_key) {
tools::Tool* tool = App::instance()->getToolBox()->getToolById(tool_id);
if (tool) {
PRINTF(" - Shortcut for quicktool `%s': <%s>\n", tool_id, tool_key);
Key* key = this->quicktool(tool);
if (key)
key->add(Accelerator(tool_key), source);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
// Load special keyboard shortcuts for sprite editor customization
// <gui><keyboard><spriteeditor>
xmlKey = handle
.FirstChild("actions")
.FirstChild("key").ToElement();
while (xmlKey) {
const char* tool_action = xmlKey->Attribute("action");
const char* tool_key = get_shortcut(xmlKey);
if (tool_action && tool_key) {
PRINTF(" - Shortcut for sprite editor `%s': <%s>\n", tool_action, tool_key);
KeyAction action = base::convert_to<KeyAction, std::string>(tool_action);
if (action != KeyAction::None) {
Key* key = this->action(action);
if (key)
key->add(Accelerator(tool_key), source);
}
}
xmlKey = xmlKey->NextSiblingElement();
}
}
void KeyboardShortcuts::importFile(const std::string& filename, KeySource source)
{
XmlDocumentRef doc = app::open_xml(filename);
TiXmlHandle handle(doc);
TiXmlElement* xmlKey = handle.FirstChild("keyboard").ToElement();
importFile(xmlKey, source);
}
void KeyboardShortcuts::exportFile(const std::string& filename)
{
XmlDocumentRef doc(new TiXmlDocument());
TiXmlElement keyboard("keyboard");
TiXmlElement commands("commands");
TiXmlElement tools("tools");
TiXmlElement quicktools("quicktools");
TiXmlElement actions("actions");
keyboard.SetAttribute("version", XML_KEYBOARD_FILE_VERSION);
exportKeys(commands, KeyType::Command);
exportKeys(tools, KeyType::Tool);
exportKeys(quicktools, KeyType::Quicktool);
exportKeys(actions, KeyType::Action);
keyboard.InsertEndChild(commands);
keyboard.InsertEndChild(tools);
keyboard.InsertEndChild(quicktools);
keyboard.InsertEndChild(actions);
doc->InsertEndChild(keyboard);
save_xml(doc, filename);
}
void KeyboardShortcuts::exportKeys(TiXmlElement& parent, KeyType type)
{
for (Key* key : m_keys) {
// Save only user defined accelerators.
if (key->type() != type || key->userAccels().empty())
continue;
for (const ui::Accelerator& accel : key->userAccels()) {
TiXmlElement elem("key");
switch (key->type()) {
case KeyType::Command:
elem.SetAttribute("command", key->command()->short_name());
if (key->params()) {
for (const auto& param : *key->params()) {
if (param.second.empty())
continue;
TiXmlElement paramElem("param");
paramElem.SetAttribute("name", param.first.c_str());
paramElem.SetAttribute("value", param.second.c_str());
elem.InsertEndChild(paramElem);
}
}
break;
case KeyType::Tool:
case KeyType::Quicktool:
elem.SetAttribute("tool", key->tool()->getId().c_str());
break;
case KeyType::Action:
elem.SetAttribute("action",
base::convert_to<std::string>(key->action()).c_str());
break;
}
elem.SetAttribute("shortcut", accel.toString().c_str());
parent.InsertEndChild(elem);
}
}
}
void KeyboardShortcuts::reset()
{
for (Key* key : m_keys)
key->reset();
}
Key* KeyboardShortcuts::command(const char* commandName,
Params* params, KeyContext keyContext)
{
Command* command = CommandsModule::instance()->getCommandByName(commandName);
if (!command)
return NULL;
for (Key* key : m_keys) {
if (key->type() == KeyType::Command &&
key->keycontext() == keyContext &&
key->command() == command &&
((!params && key->params()->empty()) ||
(params && *key->params() == *params))) {
return key;
}
}
Key* key = new Key(command, params, keyContext);
m_keys.push_back(key);
return key;
}
Key* KeyboardShortcuts::tool(tools::Tool* tool)
{
for (Key* key : m_keys) {
if (key->type() == KeyType::Tool &&
key->tool() == tool) {
return key;
}
}
Key* key = new Key(KeyType::Tool, tool);
m_keys.push_back(key);
return key;
}
Key* KeyboardShortcuts::quicktool(tools::Tool* tool)
{
for (Key* key : m_keys) {
if (key->type() == KeyType::Quicktool &&
key->tool() == tool) {
return key;
}
}
Key* key = new Key(KeyType::Quicktool, tool);
m_keys.push_back(key);
return key;
}
Key* KeyboardShortcuts::action(KeyAction action)
{
for (Key* key : m_keys) {
if (key->type() == KeyType::Action &&
key->action() == action) {
return key;
}
}
Key* key = new Key(action);
m_keys.push_back(key);
return key;
}
void KeyboardShortcuts::disableAccel(const ui::Accelerator& accel)
{
for (Key* key : m_keys) {
if (key->hasAccel(accel))
key->disableAccel(accel);
}
}
KeyContext KeyboardShortcuts::getCurrentKeyContext()
{
app::Context* ctx = UIContext::instance();
DocumentLocation location = ctx->activeLocation();
Document* doc = location.document();
if (doc &&
doc->isMaskVisible() &&
ctx->settings()->getCurrentTool()->getInk(0)->isSelection())
return KeyContext::Selection;
else
return KeyContext::Normal;
}
bool KeyboardShortcuts::getCommandFromKeyMessage(Message* msg, Command** command, Params** params)
{
for (Key* key : m_keys) {
if (key->type() == KeyType::Command && key->isPressed(msg)) {
if (command) *command = key->command();
if (params) *params = key->params();
return true;
}
}
return false;
}
tools::Tool* KeyboardShortcuts::getCurrentQuicktool(tools::Tool* currentTool)
{
if (currentTool && currentTool->getInk(0)->isSelection()) {
Key* key = action(KeyAction::CopySelection);
if (key && key->checkFromAllegroKeyArray())
return NULL;
}
tools::ToolBox* toolbox = App::instance()->getToolBox();
// Iterate over all tools
for (tools::Tool* tool : *toolbox) {
Key* key = quicktool(tool);
// Collect all tools with the pressed keyboard-shortcut
if (key && key->checkFromAllegroKeyArray()) {
return tool;
}
}
return NULL;
}
} // namespace app

View File

@ -0,0 +1,175 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_UI_KEYBOARD_SHORTCUTS_H_INCLUDED
#define APP_UI_KEYBOARD_SHORTCUTS_H_INCLUDED
#pragma once
#include "base/convert_to.h"
#include "base/disable_copying.h"
#include "ui/accelerator.h"
#include <vector>
class TiXmlElement;
namespace ui {
class Message;
}
namespace app {
class Command;
class Params;
namespace tools {
class Tool;
}
enum class KeyContext {
Any,
Normal,
Selection,
};
enum class KeySource {
Original,
UserDefined
};
enum class KeyType {
Command,
Tool,
Quicktool,
Action,
};
enum class KeyAction {
None,
CopySelection,
SnapToGrid,
AngleSnap,
MaintainAspectRatio,
LockAxis,
AddSelection,
SubtractSelection,
};
class Key {
public:
Key(Command* command, const Params* params, KeyContext keyContext);
Key(KeyType type, tools::Tool* tool);
explicit Key(KeyAction action);
KeyType type() const { return m_type; }
const ui::Accelerators& accels() const {
return (m_useUsers ? m_users: m_accels);
}
const ui::Accelerators& origAccels() const { return m_accels; }
const ui::Accelerators& userAccels() const { return m_users; }
void setUserAccels(const ui::Accelerators& accels);
void add(const ui::Accelerator& accel, KeySource source);
bool isPressed(ui::Message* msg) const;
bool checkFromAllegroKeyArray();
bool hasAccel(const ui::Accelerator& accel) const;
void disableAccel(const ui::Accelerator& accel);
// Resets user accelerators to the original ones.
void reset();
// for KeyType::Command
Command* command() const { return m_command; }
Params* params() const { return m_params; }
KeyContext keycontext() const { return m_keycontext; }
// for KeyType::Tool or Quicktool
tools::Tool* tool() const { return m_tool; }
// for KeyType::Action
KeyAction action() const { return m_action; }
std::string triggerString() const;
private:
KeyType m_type;
ui::Accelerators m_accels;
ui::Accelerators m_users;
bool m_useUsers;
KeyContext m_keycontext;
// for KeyType::Command
Command* m_command;
Params* m_params;
// for KeyType::Tool or Quicktool
tools::Tool* m_tool;
// for KeyType::Action
KeyAction m_action;
};
class KeyboardShortcuts {
public:
typedef std::vector<Key*> Keys;
typedef Keys::iterator iterator;
typedef Keys::const_iterator const_iterator;
static KeyboardShortcuts* instance();
~KeyboardShortcuts();
iterator begin() { return m_keys.begin(); }
iterator end() { return m_keys.end(); }
const_iterator begin() const { return m_keys.begin(); }
const_iterator end() const { return m_keys.end(); }
void clear();
void importFile(TiXmlElement* rootElement, KeySource source);
void importFile(const std::string& filename, KeySource source);
void exportFile(const std::string& filename);
void reset();
Key* command(const char* commandName,
Params* params = NULL, KeyContext keyContext = KeyContext::Any);
Key* tool(tools::Tool* tool);
Key* quicktool(tools::Tool* tool);
Key* action(KeyAction action);
void disableAccel(const ui::Accelerator& accel);
KeyContext getCurrentKeyContext();
bool getCommandFromKeyMessage(ui::Message* msg, Command** command, Params** params);
tools::Tool* getCurrentQuicktool(tools::Tool* currentTool);
private:
KeyboardShortcuts();
void exportKeys(TiXmlElement& parent, KeyType type);
Keys m_keys;
DISABLE_COPYING(KeyboardShortcuts);
};
} // namespace app
namespace base {
template<> app::KeyAction convert_to(const std::string& from);
template<> std::string convert_to(const app::KeyAction& from);
} // namespace base
#endif

View File

@ -0,0 +1,182 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/select_accelerator.h"
#include "app/ui/keyboard_shortcuts.h"
#include "base/bind.h"
#include "base/signal.h"
#include <cctype>
namespace app {
using namespace ui;
class SelectAccelerator::KeyField : public ui::Entry {
public:
KeyField(const Accelerator& accel) : ui::Entry(256, "") {
setExpansive(true);
setFocusMagnet(true);
setAccel(accel);
}
void setAccel(const Accelerator& accel) {
m_accel = accel;
updateText();
}
Signal1<void, const ui::Accelerator*> AccelChange;
protected:
bool onProcessMessage(Message* msg) override {
switch (msg->type()) {
case kKeyDownMessage:
if (hasFocus() && !isReadOnly()) {
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
KeyModifiers modifiers = keymsg->keyModifiers();
if (keymsg->scancode() == kKeySpace)
modifiers = (KeyModifiers)(modifiers & ~kKeySpaceModifier);
m_accel = Accelerator(
modifiers,
keymsg->scancode(),
keymsg->unicodeChar() > 32 ?
std::tolower(keymsg->unicodeChar()): 0);
updateText();
AccelChange(&m_accel);
return true;
}
break;
}
return Entry::onProcessMessage(msg);
}
void updateText() {
setText(
Accelerator(
kKeyNoneModifier,
m_accel.scancode(),
m_accel.unicodeChar()).toString().c_str());
}
Accelerator m_accel;
};
SelectAccelerator::SelectAccelerator(const ui::Accelerator& accel)
: m_keyField(new KeyField(accel))
, m_accel(accel)
, m_modified(false)
{
updateModifiers();
updateAssignedTo();
keyPlaceholder()->addChild(m_keyField);
alt()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyAltModifier, alt()));
cmd()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyCmdModifier, cmd()));
ctrl()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyCtrlModifier, ctrl()));
shift()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeyShiftModifier, shift()));
space()->Click.connect(Bind<void>(&SelectAccelerator::onModifierChange, this, kKeySpaceModifier, space()));
m_keyField->AccelChange.connect(&SelectAccelerator::onAccelChange, this);
clearButton()->Click.connect(Bind<void>(&SelectAccelerator::onClear, this));
okButton()->Click.connect(Bind<void>(&SelectAccelerator::onOK, this));
cancelButton()->Click.connect(Bind<void>(&SelectAccelerator::onCancel, this));
}
void SelectAccelerator::onModifierChange(KeyModifiers modifier, CheckBox* checkbox)
{
bool state = (checkbox->isSelected());
KeyModifiers modifiers = m_accel.modifiers();
KeyScancode scancode = m_accel.scancode();
int unicodeChar = m_accel.unicodeChar();
modifiers = (KeyModifiers)((modifiers & ~modifier) | (state ? modifier : 0));
if (modifiers == kKeySpaceModifier && scancode == kKeySpace)
modifiers = kKeyNoneModifier;
m_accel = Accelerator(modifiers, scancode, unicodeChar);
m_keyField->setAccel(m_accel);
updateAssignedTo();
}
void SelectAccelerator::onAccelChange(const ui::Accelerator* accel)
{
m_accel = *accel;
updateModifiers();
updateAssignedTo();
}
void SelectAccelerator::onClear()
{
m_accel = Accelerator(kKeyNoneModifier, kKeyNil, 0);
m_keyField->setAccel(m_accel);
updateModifiers();
updateAssignedTo();
m_keyField->requestFocus();
}
void SelectAccelerator::onOK()
{
m_modified = (m_origAccel != m_accel);
closeWindow(NULL);
}
void SelectAccelerator::onCancel()
{
closeWindow(NULL);
}
void SelectAccelerator::updateModifiers()
{
alt()->setSelected(m_accel.modifiers() & kKeyAltModifier ? true: false);
ctrl()->setSelected(m_accel.modifiers() & kKeyCtrlModifier ? true: false);
shift()->setSelected(m_accel.modifiers() & kKeyShiftModifier ? true: false);
space()->setSelected(m_accel.modifiers() & kKeySpaceModifier ? true: false);
#if __APPLE__
cmd()->setSelected(m_accel.modifiers() & kKeyCmdModifier ? true: false);
#else
cmd()->setVisible(false);
#endif
}
void SelectAccelerator::updateAssignedTo()
{
std::string res = "None";
for (Key* key : *KeyboardShortcuts::instance()) {
if (key->hasAccel(m_accel)) {
res = key->triggerString();
break;
}
}
assignedTo()->setText(res);
}
} // namespace app

View File

@ -0,0 +1,55 @@
/* Aseprite
* Copyright (C) 2001-2014 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_UI_SELECT_ACCELERATOR_H_INCLUDED
#define APP_UI_SELECT_ACCELERATOR_H_INCLUDED
#pragma once
#include "ui/accelerator.h"
#include "generated_select_accelerator.h"
namespace app {
class SelectAccelerator : public app::gen::SelectAccelerator {
public:
explicit SelectAccelerator(const ui::Accelerator& accelerator);
bool isModified() const { return m_modified; }
const ui::Accelerator& accel() const { return m_accel; }
private:
void onModifierChange(ui::KeyModifiers modifier, ui::CheckBox* checkbox);
void onAccelChange(const ui::Accelerator* accel);
void onClear();
void onOK();
void onCancel();
void updateModifiers();
void updateAssignedTo();
class KeyField;
KeyField* m_keyField;
ui::Accelerator m_origAccel;
ui::Accelerator m_accel;
bool m_modified;
};
} // namespace app
#endif

View File

@ -23,6 +23,8 @@
#include "app/ini_file.h"
#include "app/modules/gui.h"
#include "app/resource_finder.h"
#include "app/ui/app_menuitem.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/skin/button_icon_impl.h"
#include "app/ui/skin/skin_property.h"
#include "app/ui/skin/skin_slider_property.h"
@ -1244,7 +1246,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
{
int scale = jguiscale();
Graphics* g = ev.getGraphics();
MenuItem* widget = static_cast<MenuItem*>(ev.getSource());
AppMenuItem* widget = static_cast<AppMenuItem*>(ev.getSource());
gfx::Rect bounds = widget->getClientBounds();
gfx::Color fg, bg;
int c, bar;
@ -1326,13 +1328,13 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
}
}
// Draw the keyboard shortcut
else if (widget->getAccel()) {
else if (widget->getKey() && !widget->getKey()->accels().empty()) {
int old_align = widget->getAlign();
pos = bounds;
pos.w -= widget->child_spacing/4;
std::string buf = widget->getAccel()->toString();
std::string buf = widget->getKey()->accels().front().toString();
widget->setAlign(JI_RIGHT | JI_MIDDLE);
drawTextString(g, buf.c_str(), fg, ColorNone, widget, pos, 0);

View File

@ -33,6 +33,7 @@
#include "app/tools/tool.h"
#include "app/ui/color_button.h"
#include "app/ui/editor/editor.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/status_bar.h"
@ -362,10 +363,10 @@ void StatusBar::showTool(int msecs, tools::Tool* tool)
std::string text = tool->getText();
// Tool shortcut
Accelerator* accel = get_accel_to_change_tool(tool);
if (accel) {
Key* key = KeyboardShortcuts::instance()->tool(tool);
if (key && !key->accels().empty()) {
text += ", Shortcut: ";
text += accel->toString();
text += key->accels().front().toString();
}
// Set text

View File

@ -27,9 +27,9 @@
#include "app/commands/commands.h"
#include "app/modules/editors.h"
#include "app/modules/gfx.h"
#include "app/modules/gui.h"
#include "app/settings/settings.h"
#include "app/tools/tool_box.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/mini_editor.h"
#include "app/ui/skin/skin_theme.h"
@ -542,10 +542,10 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
}
// Tool shortcut
Accelerator* accel = get_accel_to_change_tool(tool);
if (accel) {
Key* key = KeyboardShortcuts::instance()->tool(tool);
if (key && !key->accels().empty()) {
tooltip += "\n\nShortcut: ";
tooltip += accel->toString();
tooltip += key->accels().front().toString();
}
}
else if (group_index == ConfigureToolIndex) {

View File

@ -46,4 +46,14 @@ XmlDocumentRef open_xml(const std::string& filename)
return doc;
}
void save_xml(XmlDocumentRef doc, const std::string& filename)
{
FileHandle file(open_file(filename, "wb"));
if (!file)
throw Exception("Error loading file: " + filename);
if (!doc->SaveFile(file))
throw XmlException(doc);
}
} // namespace app

View File

@ -32,6 +32,7 @@ namespace app {
typedef SharedPtr<TiXmlDocument> XmlDocumentRef;
XmlDocumentRef open_xml(const std::string& filename);
void save_xml(XmlDocumentRef doc, const std::string& filename);
} // namespace app

View File

@ -10,16 +10,15 @@
#include <gtest/gtest.h>
#include "doc/algorithm/resize_image.h"
#include "doc/color.h"
#include "doc/image.h"
#include "doc/algorithm/resize_image.h"
#include "doc/primitives.h"
using namespace std;
using namespace doc;
/***************************
* Test dat
*/
// Test data
// Base image
color_t test_image_base_3x3[9] =
@ -67,43 +66,27 @@ Image* create_image_from_data(PixelFormat format, color_t* data, int width, int
return new_image;
}
// Simple pixel to pixel image comparison
bool compare_images(Image* a, Image* b)
{
for (int y = 0; y < a->height(); y++) {
for (int x = 0; x < a->width(); x++) {
if (!(a->getPixel(x, y) == b->getPixel(x, y)))
return false;
}
}
return true;
}
TEST(ResizeImage, NearestNeighborInterp)
{
Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3);
Image* dst_expected = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_nearest, 9, 9);
Image* dst = Image::create(IMAGE_RGB, 9, 9);
// Pre-rendered test image for comparison
Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_nearest, 9, 9);
algorithm::resize_image(src, dst, algorithm::RESIZE_METHOD_NEAREST_NEIGHBOR, NULL, NULL);
ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!";
ASSERT_EQ(0, count_diff_between_images(dst, dst_expected));
}
#if 0 // TODO complete this test
TEST(ResizeImage, BilinearInterpRGBType)
{
Image* src = create_image_from_data(IMAGE_RGB, test_image_base_3x3, 3, 3);
Image* dst_expected = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_bilinear, 9, 9);
Image* dst = Image::create(IMAGE_RGB, 9, 9);
// Pre-rendered test image for comparison
Image* test_dst = create_image_from_data(IMAGE_RGB, test_image_scaled_9x9_bilinear, 9, 9);
algorithm::resize_image(src, dst, algorithm::RESIZE_METHOD_BILINEAR, NULL, NULL);
ASSERT_TRUE(compare_images(dst, test_dst)) << "resize_image() result does not match test image!";
ASSERT_EQ(0, count_diff_between_images(dst, dst_expected));
}
#endif

View File

@ -2,3 +2,5 @@
*Copyright (C) 2001-2014 David Capello*
> Distributed under [MIT license](LICENSE.txt)
The gfx::Region class depends on pixman library.

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,8 @@
#include "config.h"
#endif
#include <pixman.h>
#include "gfx/region.h"
#include "gfx/point.h"
#include <limits>
@ -17,45 +19,17 @@
#include <limits.h>
#include <string.h>
#include <stdio.h>
// Anonymous namespace to include pixman-region.c. Macros doesn't respect
// namespaces but anyway they are defined inside it just for reference
// (to know that they are needed only for pixman-region.c).
namespace {
#define PREFIX(x) pixman_region32##x
#define PIXMAN_EXPORT
#define _pixman_log_error(x, y) while (0) { }
#define critical_if_fail assert
typedef int64_t overflow_int_t;
typedef gfx::details::Box box_type_t;
typedef gfx::details::RegionData region_data_type_t;
typedef gfx::details::Region region_type_t;
typedef bool pixman_bool_t;
#ifndef UINT32_MAX
#define UINT32_MAX std::numeric_limits<uint32_t>::max()
#endif
#define PIXMAN_REGION_MAX std::numeric_limits<int>::max()
#define PIXMAN_REGION_MIN std::numeric_limits<int>::min()
typedef gfx::Region::Overlap pixman_region_overlap_t;
const gfx::Region::Overlap PIXMAN_REGION_OUT = gfx::Region::Out;
const gfx::Region::Overlap PIXMAN_REGION_IN = gfx::Region::In;
const gfx::Region::Overlap PIXMAN_REGION_PART = gfx::Region::Part;
pixman_bool_t
PREFIX(_union)(region_type_t *new_reg,
region_type_t *reg1,
region_type_t *reg2);
#include "gfx/pixman/pixman-region.c"
}
namespace gfx {
inline Rect to_rect(const pixman_box32& extends)
{
return Rect(
extends.x1, extends.y1,
extends.x2 - extends.x1,
extends.y2 - extends.y1);
}
Region::Region()
{
pixman_region32_init(&m_region);
@ -83,7 +57,7 @@ Region::~Region()
Region& Region::operator=(const Rect& rect)
{
if (!rect.isEmpty()) {
box_type_t box = { rect.x, rect.y, rect.x2(), rect.y2() };
pixman_box32 box = { rect.x, rect.y, rect.x2(), rect.y2() };
pixman_region32_reset(&m_region, &box);
}
else
@ -100,28 +74,28 @@ Region& Region::operator=(const Region& copy)
Region::iterator Region::begin()
{
iterator it;
it.m_ptr = PIXREGION_RECTS(&m_region);
it.m_ptr = pixman_region32_rectangles(&m_region, NULL);
return it;
}
Region::iterator Region::end()
{
iterator it;
it.m_ptr = PIXREGION_RECTS(&m_region) + PIXREGION_NUMRECTS(&m_region);
it.m_ptr = pixman_region32_rectangles(&m_region, NULL) + size();
return it;
}
Region::const_iterator Region::begin() const
{
const_iterator it;
it.m_ptr = PIXREGION_RECTS(&m_region);
it.m_ptr = pixman_region32_rectangles(&m_region, NULL);
return it;
}
Region::const_iterator Region::end() const
{
const_iterator it;
it.m_ptr = PIXREGION_RECTS(&m_region) + PIXREGION_NUMRECTS(&m_region);
it.m_ptr = pixman_region32_rectangles(&m_region, NULL) + size();
return it;
}
@ -130,14 +104,14 @@ bool Region::isEmpty() const
return pixman_region32_not_empty(&m_region) ? false: true;
}
Rect Region::getBounds() const
Rect Region::bounds() const
{
return m_region.extents;
return to_rect(*pixman_region32_extents(&m_region));
}
size_t Region::size() const
{
return PIXREGION_NUMRECTS(&m_region);
return pixman_region32_n_rects(&m_region);
}
void Region::clear()
@ -180,20 +154,20 @@ bool Region::contains(const PointT<int>& pt) const
Region::Overlap Region::contains(const Rect& rect) const
{
box_type_t box = { rect.x, rect.y, rect.x2(), rect.y2() };
return pixman_region32_contains_rectangle(&m_region, &box);
pixman_box32 box = { rect.x, rect.y, rect.x2(), rect.y2() };
return (Region::Overlap)pixman_region32_contains_rectangle(&m_region, &box);
}
Rect Region::operator[](int i)
{
assert(i >= 0 && i < PIXREGION_NUMRECTS(&m_region));
return Rect(PIXREGION_RECTS(&m_region)[i]);
assert(i >= 0 && i < (int)size());
return to_rect(pixman_region32_rectangles(&m_region, NULL)[i]);
}
const Rect Region::operator[](int i) const
{
assert(i >= 0 && i < PIXREGION_NUMRECTS(&m_region));
return Rect(PIXREGION_RECTS(&m_region)[i]);
assert(i >= 0 && i < (int)size());
return to_rect(pixman_region32_rectangles(&m_region, NULL)[i]);
}
} // namespace gfx

View File

@ -20,24 +20,22 @@ namespace gfx {
namespace details {
#ifdef PIXMAN_VERSION_MAJOR
typedef struct pixman_box32 Box;
typedef struct pixman_region32 Region;
#else
struct Box {
int x1, y1, x2, y2;
int32_t x1, y1, x2, y2;
operator Rect() const {
return Rect(x1, y1, x2-x1, y2-y1);
}
};
struct RegionData {
long size;
long numRects;
// From here this struct has an array of rectangles (Box[size])
};
struct Region {
Box extents;
RegionData* data;
void* data;
};
#endif
template<typename T>
class RegionIterator : public std::iterator<std::forward_iterator_tag, T> {
@ -83,7 +81,7 @@ namespace gfx {
const_iterator end() const;
bool isEmpty() const;
Rect getBounds() const;
Rect bounds() const;
size_t size() const;
void clear();

View File

@ -4,6 +4,10 @@
// 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 <gtest/gtest.h>
#include "gfx/region.h"
@ -52,12 +56,12 @@ TEST(Region, Equal)
{
Region a;
a = Rect(2, 3, 4, 5);
EXPECT_EQ(Rect(2, 3, 4, 5), a.getBounds());
EXPECT_EQ(Rect(2, 3, 4, 5), a.bounds());
EXPECT_EQ(Rect(2, 3, 4, 5), a[0]);
EXPECT_FALSE(a.isEmpty());
a = Rect(6, 7, 8, 9);
EXPECT_EQ(Rect(6, 7, 8, 9), a.getBounds());
EXPECT_EQ(Rect(6, 7, 8, 9), a.bounds());
EXPECT_EQ(Rect(6, 7, 8, 9), a[0]);
Region b;
@ -80,8 +84,8 @@ TEST(Region, Union)
{
Region a(Rect(2, 3, 4, 5));
Region b(Rect(6, 3, 4, 5));
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(a, b).getBounds());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(b, a).getBounds());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(a, b).bounds());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(b, a).bounds());
ASSERT_EQ(1, Region().createUnion(a, b).size());
ASSERT_EQ(1, Region().createUnion(b, a).size());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(a, b)[0]);

View File

@ -93,8 +93,10 @@ namespace she {
}
~Alleg4Surface() {
if (m_destroy & DestroyHandle)
destroy_bitmap(m_bmp);
if (m_destroy & DestroyHandle) {
if (m_bmp)
destroy_bitmap(m_bmp);
}
}
// Surface implementation

View File

@ -23,26 +23,28 @@
namespace ui {
void Accelerator::addKey(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
Accelerator::Accelerator()
: m_modifiers(kKeyNoneModifier)
, m_scancode(kKeyNil)
, m_unicodeChar(0)
{
KeyCombo key;
key.modifiers = modifiers;
key.scancode = scancode;
key.unicodeChar = unicodeChar;
m_combos.push_back(key);
}
void Accelerator::addKeysFromString(const std::string& str)
Accelerator::Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
: m_modifiers(modifiers)
, m_scancode(scancode)
, m_unicodeChar(unicodeChar)
{
KeyModifiers modifiers = kKeyNoneModifier;
KeyScancode scancode = kKeyNil;
int unicodeChar = 0;
}
Accelerator::Accelerator(const std::string& str)
: m_modifiers(kKeyNoneModifier)
, m_scancode(kKeyNil)
, m_unicodeChar(0)
{
// Special case: plus sign
if (str == "+") {
addKey(kKeyNoneModifier, kKeyNil, '+');
m_unicodeChar = '+';
return;
}
@ -51,137 +53,158 @@ void Accelerator::addKeysFromString(const std::string& str)
for (std::string tok : tokens) {
tok = base::string_to_lower(tok);
if (scancode == kKeySpace) {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeySpaceModifier);
scancode = kKeyNil;
if (m_scancode == kKeySpace) {
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeySpaceModifier);
m_scancode = kKeyNil;
}
// Modifiers
if (tok == "shift") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyShiftModifier);
}
else if (tok == "alt") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyAltModifier);
}
else if (tok == "ctrl") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCtrlModifier);
}
else if (tok == "cmd") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
m_modifiers = (KeyModifiers)((int)m_modifiers | (int)kKeyCmdModifier);
}
// Scancode
// word with one character
// Word with one character
else if (tok.size() == 1) {
if ((tok[0] >= 'a') && (tok[0] <= 'z')) {
unicodeChar = tok[0];
m_unicodeChar = tok[0];
}
else {
unicodeChar = tok[0];
m_unicodeChar = tok[0];
}
if ((tok[0] >= 'a') && (tok[0] <= 'z'))
scancode = (KeyScancode)((int)kKeyA + tolower(tok[0]) - 'a');
m_scancode = (KeyScancode)((int)kKeyA + std::tolower(tok[0]) - 'a');
else if ((tok[0] >= '0') && (tok[0] <= '9'))
scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
m_scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
else {
switch (tok[0]) {
case '~': scancode = kKeyTilde; break;
case '-': scancode = kKeyMinus; break;
case '=': scancode = kKeyEquals; break;
case '[': scancode = kKeyOpenbrace; break;
case ']': scancode = kKeyClosebrace; break;
case ';': scancode = kKeyColon; break;
case '\'': scancode = kKeyQuote; break;
case '\\': scancode = kKeyBackslash; break;
case ',': scancode = kKeyComma; break;
case '.': scancode = kKeyStop; break;
case '/': scancode = kKeySlash; break;
case '*': scancode = kKeyAsterisk; break;
case '~': m_scancode = kKeyTilde; break;
case '-': m_scancode = kKeyMinus; break;
case '=': m_scancode = kKeyEquals; break;
case '[': m_scancode = kKeyOpenbrace; break;
case ']': m_scancode = kKeyClosebrace; break;
case ';': m_scancode = kKeyColon; break;
case '\'': m_scancode = kKeyQuote; break;
case '\\': m_scancode = kKeyBackslash; break;
case ',': m_scancode = kKeyComma; break;
case '.': m_scancode = kKeyStop; break;
case '/': m_scancode = kKeySlash; break;
case '*': m_scancode = kKeyAsterisk; break;
}
}
}
/* other ones */
// Other ones
else {
/* F1, F2, ..., F11, F12 */
// F1, F2, ..., F11, F12
if (tok[0] == 'f' && (tok.size() <= 3)) {
int num = strtol(tok.c_str()+1, NULL, 10);
if ((num >= 1) && (num <= 12))
scancode = (KeyScancode)((int)kKeyF1 + num - 1);
m_scancode = (KeyScancode)((int)kKeyF1 + num - 1);
}
else if ((tok == "escape") || (tok == "esc"))
scancode = kKeyEsc;
m_scancode = kKeyEsc;
else if (tok == "backspace")
scancode = kKeyBackspace;
m_scancode = kKeyBackspace;
else if (tok == "tab")
scancode = kKeyTab;
m_scancode = kKeyTab;
else if (tok == "enter")
scancode = kKeyEnter;
m_scancode = kKeyEnter;
else if (tok == "space")
scancode = kKeySpace;
m_scancode = kKeySpace;
else if ((tok == "insert") || (tok == "ins"))
scancode = kKeyInsert;
m_scancode = kKeyInsert;
else if ((tok == "delete") || (tok == "del"))
scancode = kKeyDel;
m_scancode = kKeyDel;
else if (tok == "home")
scancode = kKeyHome;
m_scancode = kKeyHome;
else if (tok == "end")
scancode = kKeyEnd;
m_scancode = kKeyEnd;
else if ((tok == "page up") || (tok == "pgup"))
scancode = kKeyPageUp;
m_scancode = kKeyPageUp;
else if ((tok == "page down") || (tok == "pgdn"))
scancode = kKeyPageDown;
m_scancode = kKeyPageDown;
else if (tok == "left")
scancode = kKeyLeft;
m_scancode = kKeyLeft;
else if (tok == "right")
scancode = kKeyRight;
m_scancode = kKeyRight;
else if (tok == "up")
scancode = kKeyUp;
m_scancode = kKeyUp;
else if (tok == "down")
scancode = kKeyDown;
m_scancode = kKeyDown;
else if (tok == "0 pad")
scancode = kKey0Pad;
m_scancode = kKey0Pad;
else if (tok == "1 pad")
scancode = kKey1Pad;
m_scancode = kKey1Pad;
else if (tok == "2 pad")
scancode = kKey2Pad;
m_scancode = kKey2Pad;
else if (tok == "3 pad")
scancode = kKey3Pad;
m_scancode = kKey3Pad;
else if (tok == "4 pad")
scancode = kKey4Pad;
m_scancode = kKey4Pad;
else if (tok == "5 pad")
scancode = kKey5Pad;
m_scancode = kKey5Pad;
else if (tok == "6 pad")
scancode = kKey6Pad;
m_scancode = kKey6Pad;
else if (tok == "7 pad")
scancode = kKey7Pad;
m_scancode = kKey7Pad;
else if (tok == "8 pad")
scancode = kKey8Pad;
m_scancode = kKey8Pad;
else if (tok == "9 pad")
scancode = kKey9Pad;
m_scancode = kKey9Pad;
else if (tok == "slash pad")
scancode = kKeySlashPad;
m_scancode = kKeySlashPad;
else if (tok == "asterisk")
scancode = kKeyAsterisk;
m_scancode = kKeyAsterisk;
else if (tok == "minus pad")
scancode = kKeyMinusPad;
m_scancode = kKeyMinusPad;
else if (tok == "plus pad")
scancode = kKeyPlusPad;
m_scancode = kKeyPlusPad;
else if (tok == "del pad")
scancode = kKeyDelPad;
m_scancode = kKeyDelPad;
else if (tok == "enter pad")
scancode = kKeyEnterPad;
m_scancode = kKeyEnterPad;
}
}
addKey(modifiers, scancode, unicodeChar);
}
std::string Accelerator::KeyCombo::toString()
bool Accelerator::operator==(const Accelerator& other) const
{
if (m_modifiers != other.m_modifiers)
return false;
if (m_scancode == other.m_scancode) {
if (m_scancode != kKeyNil)
return true;
else if (m_unicodeChar != 0)
return (std::tolower(m_unicodeChar) == std::tolower(other.m_unicodeChar));
}
return false;
}
bool Accelerator::isEmpty() const
{
return
(m_modifiers == kKeyNoneModifier &&
m_scancode == kKeyNil &&
m_unicodeChar == 0);
}
std::string Accelerator::toString() const
{
// Same order that Allegro scancodes
static const char *table[] = {
static const char* table[] = {
NULL,
"A",
"B",
@ -286,34 +309,29 @@ std::string Accelerator::KeyCombo::toString()
"KEY_COLON2",
"Kanji",
};
static size_t table_size = sizeof(table) / sizeof(table[0]);
std::string buf;
// Shifts
if (this->modifiers & kKeyCtrlModifier) buf += "Ctrl+";
if (this->modifiers & kKeyCmdModifier) buf += "Cmd+";
if (this->modifiers & kKeyAltModifier) buf += "Alt+";
if (this->modifiers & kKeyShiftModifier) buf += "Shift+";
if (this->modifiers & kKeySpaceModifier) buf += "Space+";
if (m_modifiers & kKeyCtrlModifier) buf += "Ctrl+";
if (m_modifiers & kKeyCmdModifier) buf += "Cmd+";
if (m_modifiers & kKeyAltModifier) buf += "Alt+";
if (m_modifiers & kKeyShiftModifier) buf += "Shift+";
if (m_modifiers & kKeySpaceModifier) buf += "Space+";
// Key
if (this->unicodeChar)
buf += (wchar_t)toupper(this->unicodeChar);
else if (this->scancode)
buf += table[this->scancode];
if (m_unicodeChar)
buf += (wchar_t)toupper(m_unicodeChar);
else if (m_scancode && m_scancode > 0 && m_scancode < (int)table_size)
buf += table[m_scancode];
else if (!buf.empty() && buf[buf.size()-1] == '+')
buf.erase(buf.size()-1);
return buf;
}
std::string Accelerator::toString()
{
ASSERT(!m_combos.empty());
return m_combos.front().toString();
}
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const
{
#ifdef REPORT_KEYS
char buf[256];
@ -360,7 +378,7 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
}
// For any other legal Unicode code
else if (unicodeChar >= ' ') {
unicodeChar = tolower(unicodeChar);
unicodeChar = std::tolower(unicodeChar);
/* without shift (because characters like '*' can be trigger with
"Shift+8", so we don't want "Shift+*") */
@ -372,40 +390,29 @@ bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicod
#endif
#ifdef REPORT_KEYS
{
base::UniquePtr<Accelerator> a2(new Accelerator);
a2->addKey(modifiers, scancode, unicodeChar);
buf2 = a2->getString();
}
printf("%3d==%3d %3d==%3d %s==%s ",
m_scancode, scancode,
m_unicodeChar, unicodeChar,
toString().c_str(),
Accelerator(modifiers, scancode, unicodeChar).toString().c_str());
#endif
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
it != end; ++it) {
if ((m_modifiers == modifiers) &&
((m_scancode != kKeyNil && m_scancode == scancode) ||
(m_unicodeChar && m_unicodeChar == unicodeChar))) {
#ifdef REPORT_KEYS
printf("%3d==%3d %3d==%3d %s==%s ",
it->scancode, scancode, it->unicodeChar, unicodeChar,
it->getString().c_str(), buf2.c_str();
#endif
if ((it->modifiers == modifiers) &&
((it->scancode != kKeyNil && it->scancode == scancode) ||
(it->unicodeChar && it->unicodeChar == unicodeChar))) {
#ifdef REPORT_KEYS
printf("true\n");
#endif
return true;
}
#ifdef REPORT_KEYS
printf("false\n");
printf("true\n");
#endif
return true;
}
#ifdef REPORT_KEYS
printf("false\n");
#endif
return false;
}
bool Accelerator::checkFromAllegroKeyArray()
bool Accelerator::checkFromAllegroKeyArray() const
{
KeyModifiers modifiers = kKeyNoneModifier;
@ -416,14 +423,8 @@ bool Accelerator::checkFromAllegroKeyArray()
if (she::is_key_pressed(kKeyAlt) ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
if (she::is_key_pressed(kKeyCommand) ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
it != end; ++it) {
if ((it->scancode == 0 || she::is_key_pressed(it->scancode)) &&
(it->modifiers == modifiers)) {
return true;
}
}
return false;
return ((m_scancode == 0 || she::is_key_pressed(m_scancode)) &&
(m_modifiers == modifiers));
}
} // namespace ui

View File

@ -15,33 +15,36 @@
namespace ui {
class Accelerator
{
class Accelerator {
public:
void addKey(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
Accelerator();
Accelerator(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
// Convert string like "Ctrl+Q" or "Alt+X" into an accelerator.
explicit Accelerator(const std::string& str);
// Adds keys from strings like "Ctrl+Q" or "Alt+X"
void addKeysFromString(const std::string& str);
bool isEmpty() const;
std::string toString() const;
bool isEmpty() const { return m_combos.empty(); }
std::string toString();
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar) const;
bool checkFromAllegroKeyArray() const;
bool check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar);
bool checkFromAllegroKeyArray();
bool operator==(const Accelerator& other) const;
bool operator!=(const Accelerator& other) const {
return !operator==(other);
}
KeyModifiers modifiers() const { return m_modifiers; }
KeyScancode scancode() const { return m_scancode; }
int unicodeChar() const { return m_unicodeChar; }
private:
struct KeyCombo {
KeyModifiers modifiers;
KeyScancode scancode;
int unicodeChar;
std::string toString();
};
typedef std::vector<KeyCombo> KeyCombos;
KeyCombos m_combos;
KeyModifiers m_modifiers;
KeyScancode m_scancode;
int m_unicodeChar;
};
typedef std::vector<Accelerator> Accelerators;
} // namespace ui
#endif

View File

@ -104,7 +104,7 @@ size_t ListBox::getItemsCount() const
return getChildren().size();
}
/* setup the scroll to center the selected item in the viewport */
// Setup the scroll to center the selected item in the viewport
void ListBox::centerScroll()
{
View* view = View::getView(this);
@ -121,6 +121,23 @@ void ListBox::centerScroll()
}
}
inline bool sort_by_text(Widget* a, Widget* b) {
return a->getText() < b->getText();
}
void ListBox::sortItems()
{
WidgetsList widgets = getChildren();
std::sort(widgets.begin(), widgets.end(), &sort_by_text);
// Remove all children and add then again.
while (!getChildren().empty())
removeChild(getChildren().back());
for (Widget* child : widgets)
addChild(child);
}
bool ListBox::onProcessMessage(Message* msg)
{
switch (msg->type()) {

View File

@ -15,8 +15,7 @@ namespace ui {
class ListItem;
class ListBox : public Widget
{
class ListBox : public Widget {
public:
ListBox();
@ -29,6 +28,7 @@ namespace ui {
size_t getItemsCount() const;
void centerScroll();
void sortItems();
Signal0<void> ChangeSelectedItem;
Signal0<void> DoubleClickItem;

View File

@ -195,7 +195,6 @@ void MenuBar::setExpandOnMouseover(bool state)
MenuItem::MenuItem(const std::string& text)
: Widget(kMenuItemWidget)
{
m_accel = NULL;
m_highlighted = false;
m_submenu = NULL;
m_submenu_menubox = NULL;
@ -206,11 +205,7 @@ MenuItem::MenuItem(const std::string& text)
MenuItem::~MenuItem()
{
if (m_accel)
delete m_accel;
if (m_submenu)
delete m_submenu;
delete m_submenu;
}
Menu* MenuBox::getMenu()
@ -233,11 +228,6 @@ Menu* MenuItem::getSubmenu()
return m_submenu;
}
Accelerator* MenuItem::getAccel()
{
return m_accel;
}
void MenuBox::setMenu(Menu* menu)
{
if (Menu* oldMenu = getMenu())
@ -262,21 +252,6 @@ void MenuItem::setSubmenu(Menu* menu)
}
}
/**
* Changes the keyboard shortcuts (accelerators) for the specified
* widget (a menu-item).
*
* @warning The specified @a accel will be freed automatically when
* the menu-item is deleted.
*/
void MenuItem::setAccel(Accelerator* accel)
{
if (m_accel)
delete m_accel;
m_accel = accel;
}
bool MenuItem::isHighlighted() const
{
return m_highlighted;
@ -911,10 +886,6 @@ void MenuItem::onPreferredSize(PreferredSizeEvent& ev)
+ this->border_width.t
+ getTextHeight()
+ this->border_width.b;
if (m_accel && !m_accel->isEmpty()) {
size.w += Graphics::measureUIStringLength(m_accel->toString().c_str(), getFont());
}
}
ev.setPreferredSize(size);

View File

@ -15,7 +15,6 @@
namespace ui {
class Accelerator;
class MenuItem;
class Timer;
struct MenuBaseData;
@ -104,9 +103,6 @@ namespace ui {
Menu* getSubmenu();
void setSubmenu(Menu* submenu);
Accelerator* getAccel();
void setAccel(Accelerator* accel);
bool isHighlighted() const;
void setHighlighted(bool state);
@ -133,15 +129,15 @@ namespace ui {
virtual void onPreferredSize(PreferredSizeEvent& ev) override;
virtual void onClick();
private:
bool inBar();
private:
void openSubmenu(bool select_first);
void closeSubmenu(bool last_of_close_chain);
void startTimer();
void stopTimer();
void executeClick();
Accelerator* m_accel; // Hot-key
bool m_highlighted; // Is it highlighted?
Menu* m_submenu; // The sub-menu
MenuBox* m_submenu_menubox; // The opened menubox for this menu-item

View File

@ -44,4 +44,8 @@ if(ENABLE_WEBSERVER)
add_subdirectory(mongoose)
endif()
if(NOT USE_SHARED_PIXMAN)
add_subdirectory(pixman-cmake)
endif()
add_subdirectory(simpleini)

1
third_party/pixman vendored Submodule

@ -0,0 +1 @@
Subproject commit 87eea99e443b389c978cf37efc52788bf03a0ee0

52
third_party/pixman-cmake/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,52 @@
# Copyright (C) 2014 by David Capello
add_definitions(-DHAVE_CONFIG_H)
if(UNIX OR APPLE)
add_definitions(-DHAVE_PTHREADS)
endif()
set(PIXMAN_VERSION_MAJOR 0)
set(PIXMAN_VERSION_MINOR 32)
set(PIXMAN_VERSION_MICRO 6)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/../pixman/pixman/pixman-version.h.in"
"${CMAKE_BINARY_DIR}/pixman-version.h")
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../pixman/pixman
${CMAKE_BINARY_DIR})
add_library(pixman
../pixman/pixman/pixman.c
../pixman/pixman/pixman-access.c
../pixman/pixman/pixman-access-accessors.c
../pixman/pixman/pixman-bits-image.c
../pixman/pixman/pixman-combine32.c
../pixman/pixman/pixman-combine-float.c
../pixman/pixman/pixman-conical-gradient.c
../pixman/pixman/pixman-filter.c
../pixman/pixman/pixman-x86.c
../pixman/pixman/pixman-mips.c
../pixman/pixman/pixman-arm.c
../pixman/pixman/pixman-ppc.c
../pixman/pixman/pixman-edge.c
../pixman/pixman/pixman-edge-accessors.c
../pixman/pixman/pixman-fast-path.c
../pixman/pixman/pixman-glyph.c
../pixman/pixman/pixman-general.c
../pixman/pixman/pixman-gradient-walker.c
../pixman/pixman/pixman-image.c
../pixman/pixman/pixman-implementation.c
../pixman/pixman/pixman-linear-gradient.c
../pixman/pixman/pixman-matrix.c
../pixman/pixman/pixman-noop.c
../pixman/pixman/pixman-radial-gradient.c
../pixman/pixman/pixman-region16.c
../pixman/pixman/pixman-region32.c
../pixman/pixman/pixman-solid-fill.c
../pixman/pixman/pixman-timer.c
../pixman/pixman/pixman-trap.c
../pixman/pixman/pixman-utils.c)

1
third_party/pixman-cmake/config.h vendored Normal file
View File

@ -0,0 +1 @@
#define PACKAGE "pixman"

View File

@ -0,0 +1,50 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Author: Carl D. Worth <cworth@cworth.org>
*/
#ifndef PIXMAN_VERSION_H__
#define PIXMAN_VERSION_H__
#ifndef PIXMAN_H__
# error pixman-version.h should only be included by pixman.h
#endif
#define PIXMAN_VERSION_MAJOR @PIXMAN_VERSION_MAJOR@
#define PIXMAN_VERSION_MINOR @PIXMAN_VERSION_MINOR@
#define PIXMAN_VERSION_MICRO @PIXMAN_VERSION_MICRO@
#define PIXMAN_VERSION_STRING "@PIXMAN_VERSION_MAJOR@.@PIXMAN_VERSION_MINOR@.@PIXMAN_VERSION_MICRO@"
#define PIXMAN_VERSION_ENCODE(major, minor, micro) ( \
((major) * 10000) \
+ ((minor) * 100) \
+ ((micro) * 1))
#define PIXMAN_VERSION PIXMAN_VERSION_ENCODE( \
PIXMAN_VERSION_MAJOR, \
PIXMAN_VERSION_MINOR, \
PIXMAN_VERSION_MICRO)
#endif /* PIXMAN_VERSION_H__ */