- All tools stuff refactored in various files/components.

- Added classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape, ToolIntertwine, ToolBox, etc.
- Added ToolLoopManager.
- Removed old src/modules/tools.cpp.
- Added ISettings and UISettingsImpl, adding the tools settings (onion skinning, grid, tiled mode, etc.).
- Added App::PenSizeBeforeChange, PenSizeAfterChange, CurrentToolChange signals.
- Renamed Context::get_bg/fg_color to getBg/FgColor.
- Refactored Brush class to Pen and added PenType.
- Renamed tiled_t to TiledMode.
- get_config_rect now uses the new Rect class imported from Vaca instead of old jrect.
- Added default_skin.xml to load tool icons.
- Added pen preview in Editor::cursor stuff.
- Added Editor::decorators.

Note: This big patch is from some time ago. I did my best to pre-commit other small changes before this big one.
This commit is contained in:
David Capello 2010-03-07 17:47:45 -02:00
parent ef51fd59ea
commit cb97884026
76 changed files with 5693 additions and 824 deletions

View File

@ -1,3 +1,10 @@
2010-03-07 David Capello <davidcapello@gmail.com>
* src/tools: All tools stuff refactored in various files/components. Added
classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape,
ToolIntertwine, ToolBox, etc.
(Removed old src/modules/tools.cpp)
2010-01-29 David Capello <davidcapello@gmail.com>
* src/app.cpp (Modules): A lot of modules converted to classes.

View File

@ -5,9 +5,19 @@ NEWS
0.8
---
+ IMPORTANT USER INTERFACE CHANGES!
- Now you zoom using the mouse wheel without pressing Alt key.
- Now tools are grouped.
- New ASE skin created by Ilija Melentijevic.
+ New tools: Lasso, Polygonal Lasso, Magic Wand, Eyedropper (as
an independet tool instead of Alt+click shortcut), Hand, Move,
(Filled) Countour, and (Filled) Polygon.
+ Now the editor cursor displays pen preview (Ilija Melentijevic
idea, like Animator Pro).
+ Added support to zoom when you are drawing (e.g. you can use the
wheel mouse when you are drawing a polygon or a long line).
+ Added support to resize and maximize the main window (only in
Windows platform).
+ New ASE skin created by Ilija Melentijevic.
0.7.2
-----

View File

@ -1,6 +1,28 @@
Refactoring
-----------
- editors_ -> Editors class widget
- rename core/cfg.h to cfg_file.h
- convert all widgets to classes:
+ match Jinete design with Vaca library (Vaca Fusion)
+ move all functions (jwidget_*) to methods in Widget class.
+ the same for each widget (e.g. jbutton_* to Button widget)
+ AppHooks to Vaca::Signals
+ Convert all JI_SIGNAL to Vaca::Signals
- all member functions should be named verbNoun instead of verb_noun or noun_verb.
- all functions to handle an object should be converted to member functions:
- e.g. jwidget_set_text -> Widget::setText
High priority work
------------------
+ Selection tools do not have "move" functionality incorporated yet as we talked (they just add/subtract selection)
+ The following tools do not work: spray, eraser, blur, jumble, eyedropper, scroll, move.
+ You cannot cancel trace pressing the other mouse button
+ "shade" drawing mode
+ A lot of tool configurations are not working (grid, tiled, opacity)
+ Improve polygon tool (and polygon lasso)
- Fix paste behavior:
+ paste when there are no images (create one image or put the
clipboard as the layer's image)
@ -8,9 +30,6 @@ High priority work
trasformation embedded in the editor
+ Ctrl+T should transform the current cel
- fix bilinear: when getpixel have alpha = 0 get a neighbor color.
- Ctrl+X / Ctrl+C / Ctrl+V should Cut/Copy/Paste in jentries.
- fix problems with tiled mode XY in drawing corners (I cannot
reproduce the exact scenario).
- fix sliders in Tools Configuration, they are too big
for small resolutions.
- rewrite palette-editor to edit multiple-palettes.
@ -24,7 +43,6 @@ High priority work
Shift+G and Shift+S should update it
- when press Plus/Minus pad in the editor and the configuration tool
window is active, the slider of the "Brush Size" must be updated.
- add a consistent error handling.
- add two DrawClick2:
- DrawClick2FreeHand
- DrawClick2Shape
@ -33,10 +51,6 @@ High priority work
- add "size" to GUI font (for TTF fonts);
- layer movement between sets in animation-editor;
+ add all the "set" stuff again;
- options to change the curve type (in curedit.c);
- gaussian blur;
- RGB and HSV effects;
- color-curve stock;
- fix algo_ellipsefill;
- view_tiled() should support animation playback (partial support:
with left and right keys).
@ -47,14 +61,11 @@ Wish-list
- dacap wish-list:
+ added starred file-items in the file-selector.
+ add AseContext structure to handle the current state of the
application (and hook changes in the context/options).
+ the commands should be enabled/disabled/checked by the current
context state
+ the commands should use a new ase/ API and not the raster/ low-level
- "raster/Undoable" is the beginning
+ the dependencies should be:
commands/ -> ase/ -> raster/ -> jinete/
+ consistent error handling (now I'm using exception).
- manuq wish-list:
+ layer-with-constant-cel
- Mateusz Czaplinski ideas:

View File

@ -55,7 +55,6 @@
<key command="invert_mask" shortcut="Ctrl+Shift+I" />
<!-- view -->
<key command="refresh" shortcut="F5" />
<key command="advanced_mode" shortcut="A" />
<key command="make_unique_editor" shortcut="Ctrl+1" />
<key command="split_editor_vertically" shortcut="Ctrl+2" />
<key command="split_editor_horizontally" shortcut="Ctrl+3" />
@ -76,12 +75,6 @@
<key command="options" shortcut="Ctrl+Shift+O" />
<!-- others -->
<key command="eyedropper" shortcut="I">
<param name="target" value="background" />
</key>
<key command="eyedropper" shortcut="Shift+I">
<param name="target" value="foreground" />
</key>
<key command="switch_colors" shortcut="X" />
<key command="change_color" shortcut="9">
<param name="target" value="foreground" />
@ -110,18 +103,35 @@
</commands>
<tools>
<key tool="rectangular_marquee" shortcut="M" />
<key tool="eraser" shortcut="E" />
<key tool="elliptical_marquee" shortcut="M" />
<key tool="lasso" shortcut="Q" />
<key tool="polygonal_lasso" shortcut="Q" />
<key tool="magic_wand" shortcut="W" />
<key tool="pencil" shortcut="B" />
<key tool="brush" shortcut="B" />
<key tool="spray" shortcut="S" />
<key tool="eraser" shortcut="E" />
<key tool="eyedropper" shortcut="I" />
<key tool="hand" shortcut="H" />
<key tool="move" shortcut="V" />
<key tool="zoom" shortcut="Z" />
<key tool="paint_bucket" shortcut="G" />
<key tool="line" shortcut="L" />
<key tool="curve" shortcut="V" />
<key tool="curve" shortcut="P" />
<key tool="rectangle" shortcut="U" />
<key tool="ellipse" shortcut="O" />
<key tool="filled_rectangle" shortcut="U" />
<key tool="ellipse" shortcut="U" />
<key tool="filled_ellipse" shortcut="U" />
<key tool="contour" shortcut="D" />
<key tool="polygon" shortcut="D" />
<key tool="blur" shortcut="R" />
<key tool="jumble" shortcut="J" />
<key tool="jumble" shortcut="R" />
</tools>
</keyboard>
@ -359,5 +369,215 @@
<pixelscale factor="4" label="x4 (huge)" />
</resolutions>
<!-- tools -->
<tools>
<group id="selection_tools" text="Selection Tools">
<tool id="rectangular_marquee"
text="Rectangular Marquee Tool"
fill="always"
ink="selection"
controller="two_points"
pointshape="pixel"
intertwine="as_rectangles"
tracepolicy="last"
/>
<tool id="elliptical_marquee"
text="Elliptical Marquee Tool"
fill="always"
ink="selection"
controller="two_points"
pointshape="pixel"
intertwine="as_ellipses"
tracepolicy="last"
/>
<tool id="lasso"
text="Lasso Tool"
fill="always"
ink="selection"
controller="freehand"
pointshape="pixel"
intertwine="as_lines"
tracepolicy="accumulative"
/>
<tool id="polygonal_lasso"
text="Polygonal Lasso Tool"
fill="always"
ink="selection"
controller="point_by_point"
pointshape="pixel"
intertwine="as_lines"
tracepolicy="last"
/>
<tool id="magic_wand"
text="Magic Wand Tool"
fill="always"
ink="selection"
controller="one_point"
pointshape="floodfill"
tracepolicy="accumulative"
/>
</group>
<group id="pencil_tools" text="Pencil Tools">
<tool id="pencil"
text="Pencil Tool"
ink="paint"
controller="freehand"
pointshape="pen"
intertwine="as_lines"
tracepolicy="accumulative"
/>
<tool id="spray"
text="Spray Tool"
ink="paint"
controller="freehand"
pointshape="spray"
tracepolicy="accumulative"
/>
</group>
<group id="helpers" text="Helpers">
<tool id="eraser"
text="Eraser Tool"
ink_left="eraser"
ink_right="replace_fg_with_bg"
controller="freehand"
pointshape="pen"
intertwine="as_lines"
tracepolicy="accumulative"
default_pen_size="8"
/>
<tool id="eyedropper"
text="Eyedropper Tool"
ink_left="pick_fg"
ink_right="pick_bg"
controller="freehand"
pointshape="pixel"
/>
<tool id="hand"
text="Hand Tool"
ink="scroll"
controller="freehand"
/>
<tool id="move"
text="Move Tool"
ink="move"
controller="freehand"
/>
</group>
<group id="paint_bucket" text="Paint Bucket Tool">
<tool id="paint_bucket"
text="Paint Bucket Tool"
ink="paint"
controller="one_point"
pointshape="floodfill"
tracepolicy="accumulative"
/>
</group>
<group id="perfect_traces" text="Perfect Traces">
<tool id="line"
text="Line Tool"
ink="paint"
controller="two_points"
pointshape="pen"
intertwine="as_lines"
tracepolicy="last"
/>
<tool id="curve"
text="Curve Tool"
ink="paint"
controller="four_points"
pointshape="pen"
intertwine="as_bezier"
tracepolicy="last"
/>
</group>
<group id="shapes" text="Shapes">
<tool id="rectangle"
text="Rectangle Tool"
fill="optional"
ink="paint"
controller="two_points"
pointshape="pen"
intertwine="as_rectangles"
tracepolicy="last"
/>
<tool id="filled_rectangle"
text="Filled Rectangle Tool"
fill="always"
ink="paint"
controller="two_points"
pointshape="pen"
intertwine="as_rectangles"
tracepolicy="last"
/>
<tool id="ellipse"
text="Ellipse Tool"
fill="optional"
ink="paint"
controller="two_points"
pointshape="pen"
intertwine="as_ellipses"
tracepolicy="last"
/>
<tool id="filled_ellipse"
text="Filled Ellipse Tool"
fill="always"
ink="paint"
controller="two_points"
pointshape="pen"
intertwine="as_ellipses"
tracepolicy="last"
/>
</group>
<group id="contours" text="Contours">
<tool id="contour"
text="Contour Tool"
fill="always"
ink="paint"
controller="freehand"
pointshape="pen"
intertwine="as_lines"
tracepolicy="accumulative"
/>
<tool id="polygon"
text="Polygon Tool"
fill="always"
ink="paint"
controller="point_by_point"
pointshape="pen"
intertwine="as_lines"
tracepolicy="last"
/>
</group>
<group id="effects" text="Effects">
<tool id="blur"
text="Blur Tool"
ink="blur"
controller="freehand"
pointshape="pen"
intertwine="as_lines"
tracepolicy="accumulative"
default_pen_size="16"
/>
<tool id="jumble"
text="Jumble Tool"
ink="jumble"
controller="freehand"
pointshape="pen"
intertwine="as_lines"
tracepolicy="accumulative"
default_pen_size="16"
/>
</group>
</tools>
</gui>

View File

@ -6,7 +6,6 @@
<box horizontal="true" expansive="true">
<box vertical="true">
<separator text="General:" horizontal="true" left="true" />
<check text="Filled" name="filled" />
<box horizontal="true" childspacing="0">
<check text="Tiled" name="tiled" />
<check text="x" name="tiled_x" />
@ -14,14 +13,14 @@
</box>
<check text="Onionskin" name="onionskin" />
<separator text="Grid:" horizontal="true" left="true" />
<check text="Snap to Grid" name="use_grid" />
<check text="Snap to Grid" name="snap_to_grid" />
<check text="View Grid" name="view_grid" />
<button text="Set &amp;Grid" name="set_grid" />
<separator text="Cursor:" horizontal="true" left="true" />
<box name="cursor_color_box" /><!-- custom widget -->
</box>
<box vertical="true" expansive="true">
<separator text="Brush:" horizontal="true" left="true" />
<separator text="Pen:" horizontal="true" left="true" />
<box horizontal="true">
<box vertical="true" homogeneous="true">
<label text="Size:" />
@ -38,7 +37,7 @@
<box name="brush_preview_box" /><!-- custom widget -->
</box>
<separator text="Opacity:" horizontal="true" left="true" />
<slider min="0" max="255" name="glass_dirty" />
<slider min="0" max="255" name="opacity" />
<separator text="Spray:" horizontal="true" left="true" />
<box horizontal="true">
<box vertical="true" homogeneous="true">

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ASE Default Skin -->
<skin name="ASE Default Skin"
author="Ilija Melentijevic"
url="http://ilkke.blogspot.com/">
<tools>
<tool id="rectangular_marquee" x="144" y="0" w="16" h="16" />
<tool id="elliptical_marquee" x="160" y="0" w="16" h="16" />
<tool id="lasso" x="176" y="0" w="16" h="16" />
<tool id="polygonal_lasso" x="192" y="0" w="16" h="16" />
<tool id="magic_wand" x="208" y="0" w="16" h="16" />
<tool id="pencil" x="144" y="16" w="16" h="16" />
<tool id="spray" x="160" y="16" w="16" h="16" />
<tool id="eraser" x="144" y="32" w="16" h="16" />
<tool id="eyedropper" x="160" y="32" w="16" h="16" />
<tool id="hand" x="176" y="32" w="16" h="16" />
<tool id="move" x="192" y="32" w="16" h="16" />
<tool id="paint_bucket" x="144" y="48" w="16" h="16" />
<tool id="line" x="144" y="64" w="16" h="16" />
<tool id="curve" x="160" y="64" w="16" h="16" />
<tool id="rectangle" x="144" y="80" w="16" h="16" />
<tool id="filled_rectangle" x="160" y="80" w="16" h="16" />
<tool id="ellipse" x="176" y="80" w="16" h="16" />
<tool id="filled_ellipse" x="192" y="80" w="16" h="16" />
<tool id="contour" x="144" y="96" w="16" h="16" />
<tool id="polygon" x="160" y="96" w="16" h="16" />
<!--tool id="shade" x="144" y="112" w="16" h="16" /-->
<tool id="blur" x="160" y="112" w="16" h="16" />
<tool id="jumble" x="176" y="112" w="16" h="16" />
<tool id="configuration" x="144" y="128" w="16" h="16" />
</tools>
</skin>

Binary file not shown.

View File

@ -357,6 +357,29 @@ div.admonition-keyboard-shortcut p {
display: inline;
}
div.admonition-summary {
color: #1020ff;
border: 1px solid #2080ff;
background-color: #00ffff;
padding: 14px;
}
div.admonition-summary dl {
margin-top: 0px;
}
div.admonition-summary dd {
margin-left: 0px;
}
div.admonition-summary p.admonition-title {
border: 1px solid #2080ff;
background-color: #ffffff;
padding: 8px;
float: right;
margin-left: 14px;
}
div.admonition-summary p {
margin-top: 0px;
}
tt.literal {
background-color: #eee;
padding: 0px 4px;

View File

@ -4,7 +4,7 @@
:Author: David Capello
:Contact: davidcapello@gmail.com
:Date: November 2009
:Date: March 2010
.. contents::
@ -49,7 +49,7 @@ In this dialog you select:
With **RGB** images you can have an independent color for each pixel, in
this way each little pixel has its Red, Green, Blue and Alpha
(opacity) values. **Indexed** sprites have a special element associated:
a palette color (with a maximum of 256 colors), in this way each
a color palette (with a maximum of 256 colors), in this way each
pixel has a palette entry associated, if you change the palette
color, all pixels associated to that color will change their aspect.
@ -115,9 +115,9 @@ You have created a new sprite, now you want to draw. You need to know two things
``TODO screenshot a selected tab and the editor showing the sprite``
- With what you draw: there are various elements that are used when you draw in the sprite
- With what you draw: there are various elements that are used when you draw in the sprite:
tool, color, pen, and other configuration that modifies how you draw (e.g. snap to grid,
patterned mode, etc.).
tiled mode, fill or not the shape, etc.).
You will notice that a sprite is not just one image, it can have
frames and layers, so in next sections, the first point ("Where you
@ -129,7 +129,7 @@ To draw you can use one of the tools at the right of the screen:
``TODO screenshot of tool bar``
By default the `Pencil`_ tool is selected (if it is not selected, you
By default the `Pencil Tool`_ is selected (if it is not selected, you
can press the |pencil icon| icon to select it). The pencil is one of the most
basic tools: You press the left mouse button, hold it, drag the mouse
and then release the same button. This will draw a freehanded trace
@ -162,9 +162,18 @@ You can zoom using the ``mouse wheel`` or just pressing the numbers ``1``, ``2``
``3``, ``4``, ``5``, or ``6`` in the keyboard. When you zoom, the pixel above
the mouse cursor will be centered in the current editor.
You can zoom while you are drawing too.
Scrolling
=========
To scroll the image you can press the ``Space bar`` key (and keep it pressed) and
then drag the image with the mouse button.
When you are drawing you will notice that moving the mouse outside the
bounds of the editor will scroll the image to continue.
``TODO configuration about smooth/big step scroll``
Selecting
=========
@ -220,17 +229,186 @@ Current Editor
Tools
-------
Rectangle Selection
===================
Rectangular Marquee Tool
========================
Contour Selection
=================
With this tool you can select rectangular regions in the sprite. You
select a rectangular portion of sprite pressing left mouse button,
moving the mouse, and finally releasing the same button. If you repeat this same
operation over and over again you can add more rectangles to the
selected area. If you move the mouse over the selected region, you can drag-and-drop
this portion of sprite using the left mouse button.
Magic Wand
Using the right mouse button you can substract rectangles from selection.
.. admonition:: Summary
**Left button**: Outside the selection adds rectangles;
inside the selection *drag-and-drop* it.
**Right button**: Subtracts rectangles from selection.
Lasso Tool
==========
Pencil
======
.. admonition:: Summary
**Left button**: Outside the selection adds contours;
inside the selection *drag-and-drop* it.
**Right button**: Subtracts contours from selection.
Polygonal Lasso Tool
====================
.. admonition:: Summary
**Left button**: Outside the selection adds polygons;
inside the selection *drag-and-drop* it.
**Right button**: Subtracts polygons from selection.
Magic Wand Tool
===============
.. admonition:: Summary
**Left button**: Select the adjacent region of clicked color.
Pencil Tool
===========
.. admonition:: Summary
**Left button**: Paint a freehanded trace with foreground color.
**Right button**: Paint a freehanded trace with background color.
Spray Tool
==========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Eraser Tool
===========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Eyedropper Tool
===============
.. admonition:: Summary
**Left button**: .
**Right button**: .
Hand Tool
=========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Move Tool
=========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Paint Bucket Tool
=================
.. admonition:: Summary
**Left button**: .
**Right button**: .
Line Tool
=========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Curve Tool
==========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Rectangle Tool
==============
.. admonition:: Summary
**Left button**: .
**Right button**: .
Ellipse Tool
============
.. admonition:: Summary
**Left button**: .
**Right button**: .
Contour Tool
============
.. admonition:: Summary
**Left button**: .
**Right button**: .
Polygon Tool
============
.. admonition:: Summary
**Left button**: .
**Right button**: .
Blur Tool
=========
.. admonition:: Summary
**Left button**: .
**Right button**: .
Jumble Tool
===========
.. admonition:: Summary
**Left button**: .
**Right button**: .
-------
Menus
@ -656,7 +834,6 @@ select, pick a color, etc. Available inks are:
- pick_bg
- scroll
- move
- shade
- blur
- jumble

View File

@ -112,6 +112,8 @@ VPATH = src \
src/modules \
src/raster \
src/raster/x86 \
src/settings \
src/tools \
src/util \
src/widgets \
src/widgets/editor \

View File

@ -172,12 +172,11 @@ COMMON_SOURCES = \
src/modules/recent.cpp \
src/modules/rootmenu.cpp \
src/modules/skinneable_theme.cpp \
src/modules/tools.cpp \
src/raster/algo.cpp \
src/raster/algofill.cpp \
src/raster/algo_polygon.cpp \
src/raster/blend.cpp \
src/raster/brush.cpp \
src/raster/pen.cpp \
src/raster/cel.cpp \
src/raster/dirty.cpp \
src/raster/gfxobj.cpp \
@ -191,6 +190,9 @@ COMMON_SOURCES = \
src/raster/sprite.cpp \
src/raster/stock.cpp \
src/raster/undo.cpp \
src/settings/ui_settings_impl.cpp \
src/tools/tool.cpp \
src/tools/toolbox.cpp \
src/util/autocrop.cpp \
src/util/boundary.cpp \
src/util/celmove.cpp \

View File

@ -154,6 +154,8 @@ VPATH = src \
src/modules \
src/raster \
src/raster/x86 \
src/settings \
src/tools \
src/util \
src/widgets \
src/widgets/editor \

View File

@ -28,6 +28,8 @@ $GCC $CFLAGS \
src/jinete/*.cpp \
src/modules/*.cpp \
src/raster/*.cpp \
src/settings/*.cpp \
src/tools/*.cpp \
src/util/*.cpp \
src/widgets/*.cpp \
src/widgets/editor/*.cpp \

View File

@ -77,6 +77,7 @@ ase_files="config.h \
data/jids/*.jid \
data/palettes/*.col \
data/skins/*.png \
data/skins/*.xml \
data/tips/*.pcx \
data/tips/tips.en \
docs/*.pdf \
@ -186,6 +187,7 @@ $1/data/aseicon.* \
$1/data/fonts/*.pcx \
$1/data/palettes/*.col \
$1/data/skins/*.png \
$1/data/skins/*.xml \
$1/data/tips/*.pcx \
$1/docs/*.pdf"
}

View File

@ -55,6 +55,7 @@
#include "raster/layer.h"
#include "raster/palette.h"
#include "raster/sprite.h"
#include "tools/toolbox.h"
#include "ui_context.h"
#include "util/boundary.h"
#include "util/recscr.h"
@ -81,6 +82,7 @@ public:
LoggerModule m_logger_module;
IntlModule m_intl_module;
FileSystemModule m_file_system_module;
ToolBox m_toolbox;
RasterModule m_raster;
CommandsModule m_commands_modules;
UIContext m_ui_context;
@ -121,6 +123,9 @@ App::App(int argc, char* argv[])
// create private implementation data
m_modules = new Modules(argc, argv);
m_legacy = new LegacyModules(ase_mode & MODE_GUI ? REQUIRE_INTERFACE: 0);
// init editor cursor
Editor::editor_cursor_init();
/* custom default palette? */
if (palette_filename) {
@ -330,6 +335,12 @@ App::~App()
}
}
ToolBox* App::get_toolbox()
{
assert(m_modules != NULL);
return &m_modules->m_toolbox;
}
/**
* Updates palette and redraw the screen.
*/

View File

@ -29,6 +29,7 @@ class Layer;
class LegacyModules;
class Params;
class Sprite;
class ToolBox;
class App
{
@ -47,9 +48,14 @@ public:
int run();
ToolBox* get_toolbox();
// App Signals
Vaca::Signal0<void> Exit;
Vaca::Signal0<void> PaletteChange;
Vaca::Signal0<void> PenSizeBeforeChange;
Vaca::Signal0<void> PenSizeAfterChange;
Vaca::Signal0<void> CurrentToolChange;
};

View File

@ -62,7 +62,7 @@ void BackgroundFromLayerCommand::execute(Context* context)
// each frame of the layer to be converted as `Background' must be
// cleared using the selected background color in the color-bar
int bgcolor = context->get_bg_color();
int bgcolor = context->getBgColor();
bgcolor = fixup_color_for_background(sprite->imgtype, bgcolor);
{

View File

@ -108,7 +108,7 @@ void CanvasSizeCommand::execute(Context* context)
{
Undoable undoable(sprite, "Canvas Size");
int bgcolor = context->get_bg_color();
int bgcolor = context->getBgColor();
undoable.crop_sprite(x1, y1, x2-x1, y2-y1, bgcolor);
undoable.commit();
}

View File

@ -25,21 +25,21 @@
#include "commands/command.h"
#include "app.h"
#include "ui_context.h"
#include "modules/editors.h"
#include "modules/gfx.h"
#include "modules/gui.h"
#include "modules/rootmenu.h"
#include "modules/tools.h"
#include "raster/brush.h"
#include "raster/pen.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
#include "ui_context.h"
#include "widgets/colbut.h"
#include "widgets/editor.h"
#include "widgets/groupbut.h"
#include "widgets/statebar.h"
#include "sprite_wrappers.h"
#include "settings/settings.h"
static Frame* window = NULL;
@ -49,13 +49,12 @@ static bool window_close_hook(JWidget widget, void *data);
static bool brush_size_slider_change_hook(JWidget widget, void *data);
static bool brush_angle_slider_change_hook(JWidget widget, void *data);
static bool brush_type_change_hook(JWidget widget, void *data);
static bool glass_dirty_slider_change_hook(JWidget widget, void *data);
static bool opacity_slider_change_hook(JWidget widget, void *data);
static bool spray_width_slider_change_hook(JWidget widget, void *data);
static bool air_speed_slider_change_hook(JWidget widget, void *data);
static bool filled_check_change_hook(JWidget widget, void *data);
static bool tiled_check_change_hook(JWidget widget, void *data);
static bool tiled_xy_check_change_hook(JWidget widget, void *data);
static bool use_grid_check_change_hook(JWidget widget, void *data);
static bool snap_to_grid_check_change_hook(JWidget widget, void *data);
static bool view_grid_check_change_hook(JWidget widget, void *data);
static bool set_grid_button_select_hook(JWidget widget, void *data);
static bool cursor_button_change_hook(JWidget widget, void *data);
@ -68,6 +67,55 @@ static void on_exit_delete_this_widget()
jwidget_free(window);
}
static void on_pen_size_after_change()
{
Widget* brush_size = window->findChild("brush_size");
Widget* brush_preview = window->findChild("brush_preview");
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
IToolSettings* tool_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool);
jslider_set_value(brush_size, tool_settings->getPen()->getSize());
// Regenerate the preview
brush_preview->dirty();
}
static void on_current_tool_change()
{
Widget* brush_size = window->findChild("brush_size");
Widget* brush_angle = window->findChild("brush_angle");
Widget* brush_type = window->findChild("brush_type");
Widget* brush_preview = window->findChild("brush_preview");
Widget* opacity = window->findChild("opacity");
Widget* spray_width = window->findChild("spray_width");
Widget* air_speed = window->findChild("air_speed");
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
IToolSettings* tool_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool);
jslider_set_value(opacity, tool_settings->getOpacity());
jslider_set_value(brush_size, tool_settings->getPen()->getSize());
jslider_set_value(brush_angle, tool_settings->getPen()->getAngle());
jslider_set_value(spray_width, tool_settings->getSprayWidth());
jslider_set_value(air_speed, tool_settings->getSpraySpeed());
group_button_select(brush_type, tool_settings->getPen()->getType());
// Regenerate the preview
brush_preview->dirty();
}
//////////////////////////////////////////////////////////////////////
class ConfigureTools : public Command
@ -89,8 +137,8 @@ ConfigureTools::ConfigureTools()
void ConfigureTools::execute(Context* context)
{
JWidget filled, tiled, tiled_x, tiled_y, use_grid, view_grid, set_grid;
JWidget brush_size, brush_angle, glass_dirty;
JWidget tiled, tiled_x, tiled_y, snap_to_grid, view_grid, set_grid;
JWidget brush_size, brush_angle, opacity;
JWidget spray_width, air_speed;
JWidget cursor_color, cursor_color_box;
JWidget brush_preview_box;
@ -111,16 +159,15 @@ void ConfigureTools::execute(Context* context)
try {
get_widgets(window,
"filled", &filled,
"tiled", &tiled,
"tiled_x", &tiled_x,
"tiled_y", &tiled_y,
"use_grid", &use_grid,
"snap_to_grid", &snap_to_grid,
"view_grid", &view_grid,
"set_grid", &set_grid,
"brush_size", &brush_size,
"brush_angle", &brush_angle,
"glass_dirty", &glass_dirty,
"opacity", &opacity,
"spray_width", &spray_width,
"air_speed", &air_speed,
"cursor_color_box", &cursor_color_box,
@ -136,7 +183,7 @@ void ConfigureTools::execute(Context* context)
/* cursor-color */
if (first_time) {
cursor_color = colorbutton_new(get_cursor_color(), IMAGE_INDEXED);
cursor_color = colorbutton_new(Editor::get_cursor_color(), IMAGE_INDEXED);
cursor_color->setName("cursor_color");
}
else {
@ -157,9 +204,16 @@ void ConfigureTools::execute(Context* context)
brush_preview = jwidget_find_name(window, "brush_preview");
}
// Current settings
ISettings* settings = UIContext::instance()->getSettings();
Tool* current_tool = settings->getCurrentTool();
IToolSettings* tool_settings = settings->getToolSettings(current_tool);
/* brush-type */
if (first_time) {
brush_type = group_button_new(3, 1, get_brush_type(),
PenType type = tool_settings->getPen()->getType();
brush_type = group_button_new(3, 1, type,
GFX_BRUSH_CIRCLE,
GFX_BRUSH_SQUARE,
GFX_BRUSH_LINE);
@ -167,23 +221,18 @@ void ConfigureTools::execute(Context* context)
brush_type->setName("brush_type");
}
else {
brush_type = jwidget_find_name(window, "brush_type");
brush_type = window->findChild("brush_type");
}
if (get_filled_mode()) jwidget_select(filled);
if (get_tiled_mode() != TILED_NONE) {
if (settings->getTiledMode() != TILED_NONE) {
jwidget_select(tiled);
if (get_tiled_mode() & TILED_X_AXIS) jwidget_select(tiled_x);
if (get_tiled_mode() & TILED_Y_AXIS) jwidget_select(tiled_y);
if (settings->getTiledMode() & TILED_X_AXIS) jwidget_select(tiled_x);
if (settings->getTiledMode() & TILED_Y_AXIS) jwidget_select(tiled_y);
}
if (get_use_grid()) jwidget_select(use_grid);
if (get_view_grid()) jwidget_select(view_grid);
jslider_set_value(brush_size, get_brush_size());
jslider_set_value(brush_angle, get_brush_angle());
jslider_set_value(glass_dirty, get_glass_dirty());
jslider_set_value(spray_width, get_spray_width());
jslider_set_value(air_speed, get_air_speed());
if (get_onionskin()) jwidget_select(check_onionskin);
if (settings->getSnapToGrid()) jwidget_select(snap_to_grid);
if (settings->getGridVisible()) jwidget_select(view_grid);
if (settings->getUseOnionskin()) jwidget_select(check_onionskin);
if (first_time) {
// Append children
@ -193,25 +242,29 @@ void ConfigureTools::execute(Context* context)
// Append hooks
window->Close.connect(Vaca::Bind<bool>(&window_close_hook, (JWidget)window, (void*)0));
HOOK(filled, JI_SIGNAL_CHECK_CHANGE, filled_check_change_hook, 0);
HOOK(tiled, JI_SIGNAL_CHECK_CHANGE, tiled_check_change_hook, 0);
HOOK(tiled_x, JI_SIGNAL_CHECK_CHANGE, tiled_xy_check_change_hook, (void*)TILED_X_AXIS);
HOOK(tiled_y, JI_SIGNAL_CHECK_CHANGE, tiled_xy_check_change_hook, (void*)TILED_Y_AXIS);
HOOK(use_grid, JI_SIGNAL_CHECK_CHANGE, use_grid_check_change_hook, 0);
HOOK(snap_to_grid, JI_SIGNAL_CHECK_CHANGE, snap_to_grid_check_change_hook, 0);
HOOK(view_grid, JI_SIGNAL_CHECK_CHANGE, view_grid_check_change_hook, 0);
HOOK(set_grid, JI_SIGNAL_BUTTON_SELECT, set_grid_button_select_hook, 0);
HOOK(brush_size, JI_SIGNAL_SLIDER_CHANGE, brush_size_slider_change_hook, brush_preview);
HOOK(brush_angle, JI_SIGNAL_SLIDER_CHANGE, brush_angle_slider_change_hook, brush_preview);
HOOK(brush_type, SIGNAL_GROUP_BUTTON_CHANGE, brush_type_change_hook, brush_preview);
HOOK(glass_dirty, JI_SIGNAL_SLIDER_CHANGE, glass_dirty_slider_change_hook, 0);
HOOK(opacity, JI_SIGNAL_SLIDER_CHANGE, opacity_slider_change_hook, 0);
HOOK(air_speed, JI_SIGNAL_SLIDER_CHANGE, air_speed_slider_change_hook, 0);
HOOK(spray_width, JI_SIGNAL_SLIDER_CHANGE, spray_width_slider_change_hook, 0);
HOOK(cursor_color, SIGNAL_COLORBUTTON_CHANGE, cursor_button_change_hook, 0);
HOOK(check_onionskin, JI_SIGNAL_CHECK_CHANGE, onionskin_check_change_hook, 0);
App::instance()->Exit.connect(&on_exit_delete_this_widget);
App::instance()->PenSizeAfterChange.connect(&on_pen_size_after_change);
App::instance()->CurrentToolChange.connect(&on_current_tool_change);
}
// Update current pen properties
on_current_tool_change();
// Default position
window->remap_window();
window->center_window();
@ -229,15 +282,31 @@ static bool brush_preview_msg_proc(JWidget widget, JMessage msg)
case JM_DRAW: {
BITMAP *bmp = create_bitmap(jrect_w(widget->rc),
jrect_h(widget->rc));
Brush *brush = get_brush();
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
IPenSettings* pen_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen();
assert(pen_settings != NULL);
Pen* pen = new Pen(pen_settings->getType(),
pen_settings->getSize(),
pen_settings->getAngle());
clear_to_color(bmp, makecol(0, 0, 0));
image_to_allegro(brush->image, bmp,
bmp->w/2 - brush->size/2,
bmp->h/2 - brush->size/2);
image_to_allegro(pen->get_image(), bmp,
bmp->w/2 - pen->get_size()/2,
bmp->h/2 - pen->get_size()/2);
blit(bmp, ji_screen, 0, 0, widget->rc->x1, widget->rc->y1,
bmp->w, bmp->h);
destroy_bitmap(bmp);
delete pen;
return true;
}
}
@ -258,62 +327,91 @@ static bool window_close_hook(JWidget widget, void *data)
static bool brush_size_slider_change_hook(JWidget widget, void *data)
{
set_brush_size(jslider_get_value(widget));
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen()
->setSize(jslider_get_value(widget));
jwidget_dirty((JWidget)data);
return false;
}
static bool brush_angle_slider_change_hook(JWidget widget, void *data)
{
set_brush_angle(jslider_get_value(widget));
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen()
->setAngle(jslider_get_value(widget));
jwidget_dirty((JWidget)data);
return false;
}
static bool brush_type_change_hook(JWidget widget, void *data)
{
int type = group_button_get_selected(widget);
PenType type = (PenType)group_button_get_selected(widget);
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen()
->setType(type);
set_brush_type(type);
jwidget_dirty((JWidget)data);
statusbar_set_text(app_get_statusbar(), 250,
"Brush type: %s",
type == BRUSH_CIRCLE ? "Circle":
type == BRUSH_SQUARE ? "Square":
type == BRUSH_LINE ? "Line": "Unknown");
"Pen shape: %s",
type == PEN_TYPE_CIRCLE ? "Circle":
type == PEN_TYPE_SQUARE ? "Square":
type == PEN_TYPE_LINE ? "Line": "Unknown");
return true;
}
static bool glass_dirty_slider_change_hook(JWidget widget, void *data)
static bool opacity_slider_change_hook(JWidget widget, void *data)
{
set_glass_dirty(jslider_get_value(widget));
ISettings* settings = UIContext::instance()->getSettings();
Tool* current_tool = settings->getCurrentTool();
settings->getToolSettings(current_tool)->setOpacity(jslider_get_value(widget));
return false;
}
static bool spray_width_slider_change_hook(JWidget widget, void *data)
{
set_spray_width(jslider_get_value(widget));
ISettings* settings = UIContext::instance()->getSettings();
Tool* current_tool = settings->getCurrentTool();
settings->getToolSettings(current_tool)->setSprayWidth(jslider_get_value(widget));
return false;
}
static bool air_speed_slider_change_hook(JWidget widget, void *data)
{
set_air_speed(jslider_get_value(widget));
return false;
}
static bool filled_check_change_hook(JWidget widget, void *data)
{
set_filled_mode(jwidget_is_selected(widget));
ISettings* settings = UIContext::instance()->getSettings();
Tool* current_tool = settings->getCurrentTool();
settings->getToolSettings(current_tool)->setSpraySpeed(jslider_get_value(widget));
return false;
}
static bool tiled_check_change_hook(JWidget widget, void *data)
{
bool flag = jwidget_is_selected(widget);
set_tiled_mode(flag ? TILED_BOTH: TILED_NONE);
UIContext::instance()->getSettings()->setTiledMode(flag ? TILED_BOTH: TILED_NONE);
widget->findSibling("tiled_x")->setSelected(flag);
widget->findSibling("tiled_y")->setSelected(flag);
return false;
@ -322,7 +420,7 @@ static bool tiled_check_change_hook(JWidget widget, void *data)
static bool tiled_xy_check_change_hook(JWidget widget, void *data)
{
int tiled_axis = (int)((size_t)data);
int tiled_mode = get_tiled_mode();
int tiled_mode = UIContext::instance()->getSettings()->getTiledMode();
if (jwidget_is_selected(widget))
tiled_mode |= tiled_axis;
@ -331,19 +429,19 @@ static bool tiled_xy_check_change_hook(JWidget widget, void *data)
widget->findSibling("tiled")->setSelected(tiled_mode != TILED_NONE);
set_tiled_mode((tiled_t)tiled_mode);
UIContext::instance()->getSettings()->setTiledMode((TiledMode)tiled_mode);
return false;
}
static bool use_grid_check_change_hook(JWidget widget, void *data)
static bool snap_to_grid_check_change_hook(JWidget widget, void *data)
{
set_use_grid(jwidget_is_selected(widget));
UIContext::instance()->getSettings()->setSnapToGrid(jwidget_is_selected(widget));
return false;
}
static bool view_grid_check_change_hook(JWidget widget, void *data)
{
set_view_grid(jwidget_is_selected(widget));
UIContext::instance()->getSettings()->setGridVisible(jwidget_is_selected(widget));
refresh_all_editors();
return false;
}
@ -355,14 +453,12 @@ static bool set_grid_button_select_hook(JWidget widget, void *data)
const CurrentSpriteReader sprite(UIContext::instance());
if (sprite && sprite->mask && sprite->mask->bitmap) {
JRect rect = jrect_new(sprite->mask->x,
sprite->mask->y,
sprite->mask->x+sprite->mask->w,
sprite->mask->y+sprite->mask->h);
set_grid(rect);
jrect_free(rect);
Rect bounds(sprite->mask->x, sprite->mask->y,
sprite->mask->w, sprite->mask->h);
if (get_view_grid())
UIContext::instance()->getSettings()->setGridBounds(bounds);
if (UIContext::instance()->getSettings()->getGridVisible())
refresh_all_editors();
}
else {
@ -381,13 +477,13 @@ static bool set_grid_button_select_hook(JWidget widget, void *data)
static bool cursor_button_change_hook(JWidget widget, void *data)
{
set_cursor_color(colorbutton_get_color(widget));
Editor::set_cursor_color(colorbutton_get_color(widget));
return true;
}
static bool onionskin_check_change_hook(JWidget widget, void *data)
{
set_onionskin(jwidget_is_selected(widget));
UIContext::instance()->getSettings()->setUseOnionskin(jwidget_is_selected(widget));
refresh_all_editors();
return false;
}

View File

@ -21,9 +21,10 @@
#include <allegro/unicode.h>
#include "commands/command.h"
#include "context.h"
#include "app.h"
#include "modules/editors.h"
#include "modules/tools.h"
#include "settings/settings.h"
#include "widgets/statebar.h"
//////////////////////////////////////////////////////////////////////
@ -44,12 +45,16 @@ public:
protected:
bool checked(Context* context)
{
return get_view_grid();
ISettings* settings = context->getSettings();
return settings->getGridVisible();
}
void execute(Context* context)
{
set_view_grid(get_view_grid() ? false: true);
ISettings* settings = context->getSettings();
settings->setGridVisible(settings->getGridVisible() ? false: true);
refresh_all_editors();
}
};
@ -72,19 +77,22 @@ public:
protected:
bool checked(Context* context)
{
return get_use_grid();
ISettings* settings = context->getSettings();
return settings->getSnapToGrid();
}
void execute(Context* context)
{
ISettings* settings = context->getSettings();
char buf[512];
set_use_grid(get_use_grid() ? false: true);
settings->setSnapToGrid(settings->getSnapToGrid() ? false: true);
refresh_all_editors();
usprintf(buf, _("Snap to grid: %s"),
get_use_grid() ? _("On"):
_("Off"));
settings->getSnapToGrid() ? _("On"):
_("Off"));
statusbar_set_text(app_get_statusbar(), 250, buf);
}

View File

@ -26,7 +26,6 @@
#include "modules/editors.h"
#include "modules/gui.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/palette.h"
#include "raster/sprite.h"
#include "widgets/editor.h"
@ -74,7 +73,7 @@ void PlayAnimationCommand::execute(Context* context)
CurrentSpriteWriter sprite(context);
int old_frame, msecs;
bool done = false;
bool onionskin = get_onionskin();
bool onionskin_state = context->getSettings()->getUseOnionskin();
Palette *oldpal, *newpal;
PALETTE rgbpal;
@ -82,7 +81,7 @@ void PlayAnimationCommand::execute(Context* context)
return;
// desactivate the onionskin
set_onionskin(false);
context->getSettings()->setUseOnionskin(false);
jmouse_hide();
@ -129,7 +128,8 @@ void PlayAnimationCommand::execute(Context* context)
gui_feedback();
}
set_onionskin(onionskin);
// restore onionskin flag
context->getSettings()->setUseOnionskin(onionskin_state);
/* if right-click or ESC */
if (mouse_b == 2 || (keypressed() && (readkey()>>8) == KEY_ESC))

View File

@ -29,7 +29,6 @@
#include "modules/editors.h"
#include "modules/gfx.h"
#include "modules/gui.h"
#include "modules/tools.h"
#include "raster/image.h"
#include "raster/sprite.h"
#include "util/render.h"
@ -89,10 +88,10 @@ void PreviewCommand::preview_sprite(Context* context, int flags)
int redraw;
JRect vp;
int bg_color, index_bg_color = -1;
tiled_t tiled;
TiledMode tiled;
if (flags & PREVIEW_TILED) {
tiled = get_tiled_mode();
tiled = context->getSettings()->getTiledMode();
if (tiled == TILED_NONE)
tiled = TILED_BOTH;
}

View File

@ -41,9 +41,9 @@
#include "effect/convmatr.h"
#include "effect/effect.h"
#include "modules/gui.h"
#include "modules/tools.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/colbut.h"
#include "widgets/curvedit.h"
@ -124,7 +124,7 @@ void ConvolutionMatrixCommand::execute(Context* context)
if (get_config_bool("ConvolutionMatrix", "Preview", true))
jwidget_select(check_preview);
if (get_tiled_mode() != TILED_NONE)
if (context->getSettings()->getTiledMode() != TILED_NONE)
jwidget_select(check_tiled);
jview_attach(view_convmatr, list_convmatr);
@ -295,7 +295,9 @@ static bool list_change_hook(JWidget widget, void *data)
set_config_string("ConvolutionMatrix", "Selected", convmatr->name);
set_convmatr(convmatr);
// TODO avoid UIContext::instance, hold the context in some place
TiledMode tiled = UIContext::instance()->getSettings()->getTiledMode();
set_convmatr(convmatr, tiled);
target_button_set_target(target_button, new_target);
effect_set_target(preview_get_effect(preview), new_target);
@ -322,7 +324,12 @@ static bool preview_change_hook(JWidget widget, void *data)
static bool tiled_change_hook(JWidget widget, void *data)
{
set_tiled_mode(jwidget_is_selected(widget) ? TILED_BOTH: TILED_NONE);
TiledMode tiled = jwidget_is_selected(widget) ? TILED_BOTH:
TILED_NONE;
// TODO avoid UIContext::instance, hold the context in some place
UIContext::instance()->getSettings()->setTiledMode(tiled);
make_preview();
return false;
}

View File

@ -35,9 +35,10 @@
#include "effect/effect.h"
#include "effect/median.h"
#include "modules/gui.h"
#include "modules/tools.h"
#include "raster/mask.h"
#include "raster/sprite.h"
#include "settings/settings.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/preview.h"
#include "widgets/target.h"
@ -111,7 +112,7 @@ void DespeckleCommand::execute(Context* context)
if (get_config_bool("Median", "Preview", true))
jwidget_select(check_preview);
if (get_tiled_mode() != TILED_NONE)
if (context->getSettings()->getTiledMode() != TILED_NONE)
jwidget_select(check_tiled);
jwidget_add_child(box_target, target_button);
@ -177,7 +178,11 @@ static bool preview_change_hook(JWidget widget, void *data)
static bool tiled_change_hook(JWidget widget, void *data)
{
set_tiled_mode(jwidget_is_selected(widget) ? TILED_BOTH: TILED_NONE);
TiledMode tiled = jwidget_is_selected(widget) ? TILED_BOTH:
TILED_NONE;
// TODO save context in some place, don't use UIContext directly
UIContext::instance()->getSettings()->setTiledMode(tiled);
make_preview();
return false;
}
@ -189,7 +194,9 @@ static void make_preview()
w = get_config_int("Median", "Width", 3);
h = get_config_int("Median", "Height", 3);
set_median_size(MID(1, w, 32), MID(1, h, 32));
// TODO do not use UIContext::instance
set_median_size(UIContext::instance()->getSettings()->getTiledMode(),
MID(1, w, 32), MID(1, h, 32));
if (jwidget_is_selected (check_preview))
preview_restart(preview);

View File

@ -26,9 +26,10 @@
#include "commands/command.h"
#include "raster/sprite.h"
Context::Context()
Context::Context(ISettings* settings)
{
m_currentSprite = NULL;
m_settings = settings;
}
Context::~Context()
@ -39,16 +40,8 @@ Context::~Context()
delete sprite;
}
m_sprites.clear();
}
int Context::get_fg_color()
{
return 0; // TODO
}
int Context::get_bg_color()
{
return 0; // TODO
delete m_settings;
}
const SpriteList& Context::get_sprite_list() const

View File

@ -21,6 +21,7 @@
#include <list>
#include "ase_exception.h"
#include "settings/settings.h"
class Sprite;
class SpriteReader;
@ -44,9 +45,18 @@ class Context
// Current selected sprite to operate.
Sprite* m_currentSprite;
public:
// Settings in this context.
ISettings* m_settings;
private:
Context();
Context(const Context&);
protected:
// The "settings" are deleted automatically in the ~Context destructor
Context(ISettings* settings);
public:
virtual ~Context();
virtual bool is_ui_available() const { return false; }
@ -54,8 +64,9 @@ public:
virtual bool is_executing_macro() const { return false; }
virtual bool is_executing_script() const { return false; }
virtual int get_fg_color();
virtual int get_bg_color();
ISettings* getSettings() { return m_settings; }
int getFgColor() { return m_settings->getFgColor(); }
int getBgColor() { return m_settings->getBgColor(); }
const SpriteList& get_sprite_list() const;
Sprite* get_first_sprite() const;

View File

@ -72,25 +72,29 @@ void set_config_bool(const char *section, const char *name, bool value)
set_config_string(section, name, value ? "yes": "no");
}
void get_config_rect(const char *section, const char *name, JRect rect)
Rect get_config_rect(const char *section, const char *name, const Rect& rect)
{
Rect rect2(rect);
char **argv;
int argc;
argv = get_config_argv(section, name, &argc);
if (argv && argc == 4) {
rect->x1 = ustrtol(argv[0], NULL, 10);
rect->y1 = ustrtol(argv[1], NULL, 10);
rect->x2 = ustrtol(argv[2], NULL, 10);
rect->y2 = ustrtol(argv[3], NULL, 10);
rect2.x = ustrtol(argv[0], NULL, 10);
rect2.y = ustrtol(argv[1], NULL, 10);
rect2.w = ustrtol(argv[2], NULL, 10);
rect2.h = ustrtol(argv[3], NULL, 10);
}
return rect2;
}
void set_config_rect(const char *section, const char *name, JRect rect)
void set_config_rect(const char *section, const char *name, const Rect& rect)
{
char buf[128];
uszprintf(buf, sizeof(buf), "%d %d %d %d",
rect->x1, rect->y1, rect->x2, rect->y2);
rect.x, rect.y, rect.w, rect.h);
set_config_string(section, name, buf);
}

View File

@ -21,6 +21,7 @@
#include <allegro/config.h>
#include "jinete/jbase.h"
#include "jinete/jrect.h"
#include "core/color.h"
@ -34,8 +35,8 @@ public:
bool get_config_bool(const char *section, const char *name, bool value);
void set_config_bool(const char *section, const char *name, bool value);
void get_config_rect(const char *section, const char *name, JRect rect);
void set_config_rect(const char *section, const char *name, JRect rect);
Rect get_config_rect(const char *section, const char *name, const Rect& rect);
void set_config_rect(const char *section, const char *name, const Rect& rect);
color_t get_config_color(const char *section, const char *name, color_t value);
void set_config_color(const char *section, const char *name, color_t value);

View File

@ -27,7 +27,6 @@
#include "modules/palettes.h"
#include "modules/recent.h"
#include "modules/rootmenu.h"
#include "modules/tools.h"
#define DEF_MODULE(name, reqs) \
{ #name, init_module_##name, exit_module_##name, (reqs), false }
@ -48,7 +47,6 @@ static Module module[] =
DEF_MODULE(palette, 0),
DEF_MODULE(effect, 0),
DEF_MODULE(tools, 0),
DEF_MODULE(graphics, REQUIRE_INTERFACE),
DEF_MODULE(gui, REQUIRE_INTERFACE),
DEF_MODULE(recent, REQUIRE_INTERFACE),

View File

@ -29,7 +29,6 @@
#include "effect/convmatr.h"
#include "effect/effect.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "util/filetoks.h"
@ -40,7 +39,7 @@
static struct { /* TODO warning: not thread safe */
JList matrices;
ConvMatr *convmatr;
tiled_t tiled;
TiledMode tiled;
unsigned char **lines;
} data;
@ -112,10 +111,10 @@ void convmatr_free(ConvMatr *convmatr)
jfree(convmatr);
}
void set_convmatr(ConvMatr *convmatr)
void set_convmatr(ConvMatr *convmatr, TiledMode tiled)
{
data.convmatr = convmatr;
data.tiled = get_tiled_mode();
data.tiled = tiled;
if (data.lines != NULL)
jfree(data.lines);

View File

@ -20,6 +20,7 @@
#define EFFECT_CONVMATR_H_INCLUDED
#include "jinete/jbase.h"
#include "tiled_mode.h"
struct Effect;
@ -39,7 +40,7 @@ ConvMatr *convmatr_new(int w, int h);
ConvMatr *convmatr_new_string(const char *format);
void convmatr_free(ConvMatr *convmatr);
void set_convmatr(ConvMatr *convmatr);
void set_convmatr(ConvMatr *convmatr, TiledMode tiled);
ConvMatr *get_convmatr();
ConvMatr *get_convmatr_by_name(const char *name);

View File

@ -23,6 +23,7 @@
#include <cstring>
#include "sprite_wrappers.h"
#include "jinete/jbase.h"
#include "tiled_mode.h"
class Image;
class Mask;

View File

@ -22,22 +22,22 @@
#include "effect/effect.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "tiled_mode.h"
static struct {
tiled_t tiled;
TiledMode tiled;
int w, h;
int ncolors;
unsigned char *channel[4];
} data = { TILED_NONE, 0, 0, 0, { NULL, NULL, NULL, NULL } };
void set_median_size(int w, int h)
void set_median_size(TiledMode tiled, int w, int h)
{
int c;
data.tiled = get_tiled_mode();
data.tiled = tiled;
data.w = w;
data.h = h;
data.ncolors = w*h;

View File

@ -19,10 +19,14 @@
#ifndef EFFECT_MEDIAN_H_INCLUDED
#define EFFECT_MEDIAN_H_INCLUDED
void set_median_size(int w, int h);
#include "tiled_mode.h"
void apply_median4 (struct Effect *effect);
void apply_median2 (struct Effect *effect);
void apply_median1 (struct Effect *effect);
struct Effect;
void set_median_size(TiledMode tiled, int w, int h);
void apply_median4(Effect* effect);
void apply_median2(Effect* effect);
void apply_median1(Effect* effect);
#endif

View File

@ -20,6 +20,7 @@
#define MODULES_EDITORS_H_INCLUDED
#include "jinete/jbase.h"
#include "core/color.h"
class Editor;

View File

@ -24,6 +24,7 @@
#include "jinete/jintern.h"
#include "jinete/jsystem.h"
#include "jinete/jtheme.h"
#include "jinete/jrect.h"
#include "console.h"
#include "app.h"
@ -32,7 +33,6 @@
#include "modules/gfx.h"
#include "modules/gui.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/blend.h"
#include "raster/image.h"
#include "widgets/editor.h"

View File

@ -49,13 +49,14 @@
#include "modules/palettes.h"
#include "modules/rootmenu.h"
#include "modules/skinneable_theme.h"
#include "modules/tools.h"
#include "raster/sprite.h"
#include "sprite_wrappers.h"
#include "ui_context.h"
#include "util/recscr.h"
#include "widgets/editor.h"
#include "widgets/statebar.h"
#include "widgets/toolbar.h"
#include "tools/toolbox.h"
#define REBUILD_RECENT_LIST 2
#define REFRESH_FULL_SCREEN 4
@ -506,7 +507,7 @@ void gui_feedback()
rec_screen_poll();
/* double buffering? */
if (double_buffering) {
if (double_buffering && ji_screen) {
jmouse_draw_cursor();
if (ji_dirty_region) {
@ -603,31 +604,25 @@ void reload_default_font()
void load_window_pos(JWidget window, const char *section)
{
JRect pos, orig_pos;
// Default position
Rect orig_pos = window->getBounds();
Rect pos = orig_pos;
/* default position */
orig_pos = jwidget_get_rect(window);
pos = jrect_new_copy(orig_pos);
// Load configurated position
pos = get_config_rect(section, "WindowPos", pos);
/* load configurated position */
get_config_rect(section, "WindowPos", pos);
pos.w = MID(orig_pos.w, pos.w, JI_SCREEN_W);
pos.h = MID(orig_pos.h, pos.h, JI_SCREEN_H);
pos->x2 = pos->x1 + MID(jrect_w(orig_pos), jrect_w(pos), JI_SCREEN_W);
pos->y2 = pos->y1 + MID(jrect_h(orig_pos), jrect_h(pos), JI_SCREEN_H);
pos.setOrigin(Point(MID(0, pos.x, JI_SCREEN_W-pos.w),
MID(0, pos.y, JI_SCREEN_H-pos.h)));
jrect_moveto(pos,
MID(0, pos->x1, JI_SCREEN_W-jrect_w(pos)),
MID(0, pos->y1, JI_SCREEN_H-jrect_h(pos)));
jwidget_set_rect(window, pos);
jrect_free(pos);
jrect_free(orig_pos);
window->setBounds(pos);
}
void save_window_pos(JWidget window, const char *section)
{
set_config_rect(section, "WindowPos", window->rc);
set_config_rect(section, "WindowPos", window->getBounds());
}
JWidget load_widget(const char *filename, const char *name)
@ -1055,25 +1050,45 @@ static bool manager_msg_proc(JWidget widget, JMessage msg)
switch (shortcut->type) {
case Shortcut_ChangeTool: {
Tool* current_tool = UIContext::instance()->getSettings()->getCurrentTool();
Tool* select_this_tool = shortcut->tool;
Tool* group[MAX_TOOLS];
int i, j;
ToolBox* toolbox = App::instance()->get_toolbox();
std::vector<Tool*> possibles;
for (i=j=0; i<MAX_TOOLS; i++) {
if (get_keyboard_shortcut_for_tool(tools_list[i])->is_key_pressed(msg))
group[j++] = tools_list[i];
// Iterate over all tools
for (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_key_pressed(msg))
possibles.push_back(*it);
}
if (j >= 2) {
for (i=0; i<j; i++) {
if (group[i] == current_tool && i+1 < j) {
select_this_tool = group[i+1];
if (possibles.size() >= 2) {
bool done = false;
for (size_t i=0; i<possibles.size(); ++i) {
if (possibles[i] != current_tool &&
toolbar_is_tool_visible(app_get_toolbar(), possibles[i])) {
select_this_tool = possibles[i];
done = true;
break;
}
}
if (!done) {
for (size_t i=0; i<possibles.size(); ++i) {
// If one of the possibilities is the current tool
if (possibles[i] == current_tool) {
// We select the next tool in the possibilities
select_this_tool = possibles[(i+1) % possibles.size()];
break;
}
}
}
}
select_tool(select_this_tool);
toolbar_select_tool(app_get_toolbar(), select_this_tool);
break;
}

View File

@ -25,11 +25,12 @@
#include "ase_exception.h"
#include "jinete/jbase.h"
#include "jinete/jaccel.h"
#include "jinete/jwidget.h"
class Command;
class Params;
struct Tool;
class Tool;
class Widget;
class Frame;
//////////////////////////////////////////////////////////////////////

View File

@ -34,8 +34,8 @@
#include "core/dirs.h"
#include "intl/intl.h"
#include "modules/rootmenu.h"
#include "modules/tools.h"
#include "modules/gui.h"
#include "tools/toolbox.h"
#include "util/filetoks.h"
#include "widgets/menuitem.h"
@ -203,7 +203,7 @@ static int load_root_menu()
const char* tool_key = xmlKey->Attribute("shortcut");
if (tool_id && tool_key) {
Tool *tool = get_tool_by_name(tool_id);
Tool* tool = App::instance()->get_toolbox()->getToolById(tool_id);
if (tool) {
/* add the keyboard shortcut to the tool */
PRINTF(" - Shortcut for tool `%s': <%s>\n", tool_id, tool_key);

View File

@ -30,6 +30,8 @@
#include "modules/skinneable_theme.h"
#include "modules/gui.h"
#include "tinyxml.h"
#define CHARACTER_LENGTH(f, c) ((f)->vtable->char_length((f), (c)))
#define BGCOLOR (get_bg_color(widget))
@ -362,6 +364,11 @@ SkinneableTheme::~SkinneableTheme()
for (int c=0; c<PARTS; ++c)
destroy_bitmap(m_part[c]);
for (std::map<std::string, BITMAP*>::iterator
it = m_toolicon.begin(); it != m_toolicon.end(); ++it) {
destroy_bitmap(it->second);
}
destroy_bitmap(m_sheet_bmp);
}
@ -383,6 +390,50 @@ void SkinneableTheme::regen()
m_part[c] = apply_gui_scale(m_part[c]);
}
// Load tool icons
{
DIRS* dirs = filename_in_datadir("skins/default_skin.xml");
for (DIRS* dir=dirs; dir; dir=dir->next) {
if ((dir->path) && exists(dir->path)) {
TiXmlDocument doc;
if (!doc.LoadFile(dir->path))
throw ase_exception(&doc);
TiXmlHandle handle(&doc);
TiXmlElement* xmlIcon = handle
.FirstChild("skin")
.FirstChild("tools")
.FirstChild("tool").ToElement();
while (xmlIcon) {
// Get the tool-icon rectangle
const char* tool_id = xmlIcon->Attribute("id");
int x = strtol(xmlIcon->Attribute("x"), NULL, 10);
int y = strtol(xmlIcon->Attribute("y"), NULL, 10);
int w = strtol(xmlIcon->Attribute("w"), NULL, 10);
int h = strtol(xmlIcon->Attribute("h"), NULL, 10);
// Crop the tool-icon from the sheet
BITMAP* toolicon = create_bitmap(w, h);
clear_to_color(toolicon, bitmap_mask_color(m_sheet_bmp));
set_alpha_blender();
draw_trans_sprite(toolicon, m_sheet_bmp, -x, -y);
set_trans_blender(0, 0, 0, 0);
// Add the tool-icon in the map
if (m_toolicon[tool_id]) destroy_bitmap(m_toolicon[tool_id]);
m_toolicon[tool_id] = apply_gui_scale(toolicon);
xmlIcon = xmlIcon->NextSiblingElement();
}
break;
}
}
dirs_free(dirs);
}
}
BITMAP* SkinneableTheme::set_cursor(int type, int* focus_x, int* focus_y)
@ -1514,6 +1565,15 @@ void SkinneableTheme::draw_entry_cursor(JWidget widget, int x, int y)
vline(ji_screen, x+1, y-1, y+h, COLOR_FOREGROUND);
}
BITMAP* SkinneableTheme::get_toolicon(const char* tool_id) const
{
std::map<std::string, BITMAP*>::const_iterator it = m_toolicon.find(tool_id);
if (it != m_toolicon.end())
return it->second;
else
return NULL;
}
void SkinneableTheme::draw_bounds(int x1, int y1, int x2, int y2, int nw, int bg)
{
int x, y;

View File

@ -19,8 +19,11 @@
#ifndef MODULES_SKINNEABLE_THEME_H_INCLUDED
#define MODULES_SKINNEABLE_THEME_H_INCLUDED
#include <map>
#include <string>
#include <allegro/color.h>
#include "jinete/jtheme.h"
#include "jinete/jrect.h"
enum {
@ -283,6 +286,7 @@ class SkinneableTheme : public jtheme
{
BITMAP* m_sheet_bmp;
BITMAP* m_part[PARTS];
std::map<std::string, BITMAP*> m_toolicon;
public:
SkinneableTheme();
@ -371,12 +375,18 @@ public:
int get_panel_face_color() const { return makecol(125, 146, 158); }
BITMAP* get_part(int part_i) const { return m_part[part_i]; }
BITMAP* get_toolicon(const char* tool_id) const;
// helper functions to draw parts
void draw_bounds(int x1, int y1, int x2, int y2, int nw, int bg);
void draw_bounds2(int x1, int y1, int x2, int y2, int x_mid, int nw1, int nw2, int bg1, int bg2);
void draw_hline(int x1, int y1, int x2, int y2, int part);
// Wrapper to use the new "Rect" class (x, y, w, h)
void draw_bounds(const Rect& rc, int nw, int bg) {
draw_bounds(rc.x, rc.y, rc.x+rc.w-1, rc.y+rc.h-1, nw, bg);
}
private:
int get_bg_color(JWidget widget);

View File

@ -19,6 +19,8 @@
#ifndef MODULES_TOOLS_H_INCLUDED
#define MODULES_TOOLS_H_INCLUDED
#error Deprecated
#include "jinete/jbase.h"
#include "jinete/jrect.h"

View File

@ -1,5 +1,5 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2010 David Capello
* Copyright (C) 2001-2009 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
@ -16,38 +16,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef RASTER_BRUSH_H_INCLUDED
#define RASTER_BRUSH_H_INCLUDED
#ifndef PEN_TYPE_H_INCLUDED
#define PEN_TYPE_H_INCLUDED
class Image;
enum PenType {
PEN_TYPE_CIRCLE = 0,
PEN_TYPE_SQUARE = 1,
PEN_TYPE_LINE = 2,
enum {
BRUSH_CIRCLE,
BRUSH_SQUARE,
BRUSH_LINE,
PEN_TYPE_FIRST = PEN_TYPE_CIRCLE,
PEN_TYPE_LAST = PEN_TYPE_LINE,
};
struct BrushScanline
{
int state, x1, x2;
};
struct Brush
{
int type; /* type of brush */
int size; /* size (diameter) */
int angle; /* angle in degrees 0-360 */
Image* image; /* image of the brush */
BrushScanline* scanline;
};
Brush* brush_new();
Brush* brush_new_copy(const Brush* brush);
void brush_free(Brush* brush);
void brush_set_type(Brush* brush, int type);
void brush_set_size(Brush* brush, int size);
void brush_set_angle(Brush* brush, int angle);
#endif

View File

@ -1,182 +0,0 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2010 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
*/
#include "config.h"
#include <allegro/base.h>
#include <math.h>
#include "jinete/jbase.h"
#include "raster/algo.h"
#include "raster/brush.h"
#include "raster/image.h"
static void clean_brush (Brush *brush);
static void regenerate_brush (Brush *brush);
Brush *brush_new ()
{
Brush *brush;
brush = jnew (Brush, 1);
if (!brush)
return NULL;
brush->type = BRUSH_CIRCLE;
brush->size = 1;
brush->angle = 0;
brush->image = NULL;
brush->scanline = NULL;
regenerate_brush (brush);
return brush;
}
/* Makes a copy of "brush". */
Brush *brush_new_copy (const Brush *brush)
{
Brush *brush_copy;
brush_copy = brush_new ();
if (!brush_copy)
return NULL;
brush_copy->type = brush->type;
brush_copy->size = brush->size;
brush_copy->angle = brush->angle;
regenerate_brush (brush_copy);
return brush_copy;
}
void brush_free (Brush *brush)
{
clean_brush (brush);
jfree (brush);
}
void brush_set_type (Brush *brush, int type)
{
brush->type = type;
regenerate_brush (brush);
}
void brush_set_size (Brush *brush, int size)
{
brush->size = size;
regenerate_brush (brush);
}
void brush_set_angle (Brush *brush, int angle)
{
brush->angle = angle;
regenerate_brush (brush);
}
/* Cleans the brush's data (image and region). */
static void clean_brush (Brush *brush)
{
if (brush->image) {
image_free (brush->image);
brush->image = NULL;
}
if (brush->scanline) {
jfree (brush->scanline);
brush->scanline = NULL;
}
}
static void algo_hline(int x1, int y, int x2, void *data)
{
image_hline(reinterpret_cast<Image*>(data), x1, y, x2, 1);
}
/* Regenerates the brush bitmap and its rectangle's region. */
static void regenerate_brush(Brush *brush)
{
int x, y;
clean_brush(brush);
brush->image = image_new(IMAGE_BITMAP, brush->size, brush->size);
image_clear(brush->image, 0);
switch (brush->type) {
case BRUSH_CIRCLE:
image_ellipsefill(brush->image, 0, 0, brush->size-1, brush->size-1, 1);
break;
case BRUSH_SQUARE: {
double a = PI * brush->angle / 180;
int r = brush->size/2;
int x1, y1, x2, y2, x3, y3, x4, y4;
x1 = cos(a+ PI/4) * r;
y1 = -sin(a+ PI/4) * r;
x2 = cos(a+3*PI/4) * r;
y2 = -sin(a+3*PI/4) * r;
x3 = cos(a-3*PI/4) * r;
y3 = -sin(a-3*PI/4) * r;
x4 = cos(a- PI/4) * r;
y4 = -sin(a- PI/4) * r;
image_line(brush->image, r+x1, r+y1, r+x2, r+y2, 1);
image_line(brush->image, r+x2, r+y2, r+x3, r+y3, 1);
image_line(brush->image, r+x3, r+y3, r+x4, r+y4, 1);
image_line(brush->image, r+x4, r+y4, r+x1, r+y1, 1);
algo_floodfill(brush->image, r, r, brush->image, algo_hline);
break;
}
case BRUSH_LINE: {
double a = PI * brush->angle / 180;
int r = brush->size/2;
x = cos(a) * r;
y = -sin(a) * r;
image_line(brush->image, r-x, r-y, r+x, r+y, 1);
image_line(brush->image, r-x-1, r-y, r+x-1, r+y, 1);
break;
}
}
brush->scanline = jnew(BrushScanline, brush->size);
for (y=0; y<brush->size; y++) {
brush->scanline[y].state = false;
for (x=0; x<brush->size; x++) {
if (image_getpixel(brush->image, x, y)) {
brush->scanline[y].x1 = x;
for (; x<brush->size; x++)
if (!image_getpixel(brush->image, x, y))
break;
brush->scanline[y].x2 = x-1;
brush->scanline[y].state = true;
break;
}
}
}
}

View File

@ -21,7 +21,7 @@
#include <string.h>
#include "raster/algo.h"
#include "raster/brush.h"
#include "raster/pen.h"
#include "raster/dirty.h"
#include "raster/image.h"
#include "raster/mask.h"
@ -115,7 +115,7 @@
typedef struct AlgoData
{
Dirty* dirty;
Brush* brush;
Pen* pen;
int thickness;
} AlgoData;
@ -123,7 +123,7 @@ typedef void (*HLineSwapper)(void*,void*,int,int);
static void algo_putpixel(int x, int y, AlgoData *data);
/* static void algo_putthick(int x, int y, AlgoData *data); */
static void algo_putbrush(int x, int y, AlgoData *data);
static void algo_putpen(int x, int y, AlgoData *data);
static HLineSwapper swap_hline(Image* image);
static void swap_hline32(void* image, void* data, int x1, int x2);
@ -608,35 +608,35 @@ void dirty_rectfill(Dirty* dirty, int x1, int y1, int x2, int y2)
dirty_hline(dirty, x1, y, x2);
}
void dirty_putpixel_brush(Dirty* dirty, Brush* brush, int x, int y)
void dirty_putpixel_pen(Dirty* dirty, Pen* pen, int x, int y)
{
AlgoData data = { dirty, brush, 0 };
if (brush->size == 1)
AlgoData data = { dirty, pen, 0 };
if (pen->get_size() == 1)
algo_putpixel(x, y, &data);
else
algo_putbrush(x, y, &data);
algo_putpen(x, y, &data);
}
void dirty_hline_brush(Dirty* dirty, struct Brush* brush, int x1, int y, int x2)
void dirty_hline_pen(Dirty* dirty, Pen* pen, int x1, int y, int x2)
{
AlgoData data = { dirty, brush, 0 };
AlgoData data = { dirty, pen, 0 };
int x;
if (brush->size == 1)
if (pen->get_size() == 1)
for (x=x1; x<=x2; ++x)
algo_putpixel(x, y, &data);
else
for (x=x1; x<=x2; ++x)
algo_putbrush(x, y, &data);
algo_putpen(x, y, &data);
}
void dirty_line_brush(Dirty* dirty, Brush* brush, int x1, int y1, int x2, int y2)
void dirty_line_pen(Dirty* dirty, Pen* pen, int x1, int y1, int x2, int y2)
{
AlgoData data = { dirty, brush, 0 };
AlgoData data = { dirty, pen, 0 };
algo_line(x1, y1, x2, y2, &data,
(brush->size == 1)?
(pen->get_size() == 1)?
(AlgoPixel)algo_putpixel:
(AlgoPixel)algo_putbrush);
(AlgoPixel)algo_putpen);
}
void dirty_save_image_data(Dirty* dirty)
@ -711,15 +711,15 @@ static void algo_putpixel(int x, int y, AlgoData *data)
dirty_putpixel(data->dirty, x, y);
}
static void algo_putbrush(int x, int y, AlgoData *data)
static void algo_putpen(int x, int y, AlgoData *data)
{
register BrushScanline* scanline = data->brush->scanline;
register int c = data->brush->size/2;
register PenScanline* scanline = data->pen->get_scanline();
register int c = data->pen->get_size()/2;
x -= c;
y -= c;
for (c=0; c<data->brush->size; ++c) {
for (c=0; c<data->pen->get_size(); ++c) {
if (scanline->state)
dirty_hline(data->dirty, x+scanline->x1, y+c, x+scanline->x2);
++scanline;

View File

@ -21,7 +21,7 @@
#include "raster/image.h"
struct Brush;
class Pen;
class Image;
class Mask;
@ -66,9 +66,9 @@ void dirty_line(Dirty* dirty, int x1, int y1, int x2, int y2);
void dirty_rect(Dirty* dirty, int x1, int y1, int x2, int y2);
void dirty_rectfill(Dirty* dirty, int x1, int y1, int x2, int y2);
void dirty_putpixel_brush(Dirty* dirty, Brush* brush, int x, int y);
void dirty_hline_brush(Dirty* dirty, Brush* brush, int x1, int y, int x2);
void dirty_line_brush(Dirty* dirty, Brush* brush, int x1, int y1, int x2, int y2);
void dirty_putpixel_pen(Dirty* dirty, Pen* pen, int x, int y);
void dirty_hline_pen(Dirty* dirty, Pen* pen, int x1, int y, int x2);
void dirty_line_pen(Dirty* dirty, Pen* pen, int x1, int y1, int x2, int y2);
void dirty_save_image_data(Dirty* dirty);
void dirty_restore_image_data(Dirty* dirty);

View File

@ -25,7 +25,7 @@
#include "raster/algo.h"
#include "raster/blend.h"
#include "raster/brush.h"
#include "raster/pen.h"
#include "raster/image.h"
#include "raster/image_impl.h"
#include "raster/palette.h"
@ -98,6 +98,22 @@ void image_putpixel(Image* image, int x, int y, int color)
image->putpixel(x, y, color);
}
void image_putpen(Image* image, Pen* pen, int x, int y, int color)
{
Image* pen_image = pen->get_image();
int u, v, size = pen->get_size();
x -= size/2;
y -= size/2;
for (v=0; v<pen_image->h; v++) {
for (u=0; u<pen_image->w; u++) {
if (image_getpixel(pen_image, u, v))
image_putpixel(image, x+u, y+v, color);
}
}
}
void image_clear(Image* image, int color)
{
image->clear(color);
@ -293,71 +309,6 @@ void image_ellipsefill(Image* image, int x1, int y1, int x2, int y2, int color)
algo_ellipsefill(x1, y1, x2, y2, &data, (AlgoHLine)hline_for_image);
}
/*********************************************************************
Brushes
*********************************************************************/
/* typedef struct AlgoData */
/* { */
/* Image* image; */
/* Brush *brush; */
/* int color; */
/* } AlgoData; */
/* static void algo_putpixel(int x, int y, AlgoData *data); */
/* static void algo_putbrush(int x, int y, AlgoData *data); */
/* void image_putpixel_brush(Image* image, Brush *brush, int x, int y, int color) */
/* { */
/* AlgoData data = { image, brush, color }; */
/* if (brush->size == 1) */
/* algo_putpixel(x, y, &data); */
/* else */
/* algo_putbrush(x, y, &data); */
/* } */
/* void image_hline_brush(Image* image, Brush *brush, int x1, int y, int x2, int color) */
/* { */
/* AlgoData data = { image, brush, color }; */
/* int x; */
/* if (brush->size == 1) */
/* for (x=x1; x<=x2; ++x) */
/* algo_putpixel(x, y, &data); */
/* else */
/* for (x=x1; x<=x2; ++x) */
/* algo_putbrush(x, y, &data); */
/* } */
/* void image_line_brush(Image* image, Brush *brush, int x1, int y1, int x2, int y2, int color) */
/* { */
/* AlgoData data = { image, brush, color }; */
/* algo_line(x1, y1, x2, y2, &data, */
/* (brush->size == 1)? */
/* (AlgoPixel)algo_putpixel: */
/* (AlgoPixel)algo_putbrush); */
/* } */
/* static void algo_putpixel(int x, int y, AlgoData *data) */
/* { */
/* image_putpixel(data->image, x, y, data->color); */
/* } */
/* static void algo_putbrush(int x, int y, AlgoData *data) */
/* { */
/* register struct BrushScanline *scanline = data->brush->scanline; */
/* register int c = data->brush->size/2; */
/* x -= c; */
/* y -= c; */
/* for (c=0; c<data->brush->size; ++c) { */
/* if (scanline->state) */
/* image_hline(data->image, x+scanline->x1, y+c, x+scanline->x2, data->color); */
/* ++scanline; */
/* } */
/* } */
void image_to_allegro(const Image* image, BITMAP *bmp, int x, int y)
{
image->to_allegro(bmp, x, y);

View File

@ -24,6 +24,7 @@
#include "raster/blend.h"
class Palette;
class Pen;
// Image Types
enum {
@ -69,6 +70,7 @@ int image_depth(Image* image);
int image_getpixel(const Image* image, int x, int y);
void image_putpixel(Image* image, int x, int y, int color);
void image_putpen(Image* image, Pen* pen, int x, int y, int color);
void image_clear(Image* image, int color);

173
src/raster/pen.cpp Normal file
View File

@ -0,0 +1,173 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "config.h"
#include <allegro/base.h>
#include <math.h>
#include "jinete/jbase.h"
#include "raster/algo.h"
#include "raster/pen.h"
#include "raster/image.h"
Pen::Pen()
{
m_type = PEN_TYPE_CIRCLE;
m_size = 1;
m_angle = 0;
m_image = NULL;
m_scanline = NULL;
regenerate_pen();
}
Pen::Pen(PenType type, int size, int angle)
{
m_type = type;
m_size = size;
m_angle = angle;
m_image = NULL;
m_scanline = NULL;
regenerate_pen();
}
Pen::Pen(const Pen& pen)
{
m_type = pen.m_type;
m_size = pen.m_size;
m_angle = pen.m_angle;
regenerate_pen();
}
Pen::~Pen()
{
clean_pen();
}
void Pen::set_type(PenType type)
{
m_type = type;
regenerate_pen();
}
void Pen::set_size(int size)
{
m_size = size;
regenerate_pen();
}
void Pen::set_angle(int angle)
{
m_angle = angle;
regenerate_pen();
}
// Cleans the pen's data (image and region).
void Pen::clean_pen()
{
if (m_image) {
image_free(m_image);
m_image = NULL;
}
if (m_scanline) {
jfree(m_scanline);
m_scanline = NULL;
}
}
static void algo_hline(int x1, int y, int x2, void *data)
{
image_hline(reinterpret_cast<Image*>(data), x1, y, x2, 1);
}
// Regenerates the pen bitmap and its rectangle's region.
void Pen::regenerate_pen()
{
int x, y;
clean_pen();
m_image = image_new(IMAGE_BITMAP, m_size, m_size);
image_clear(m_image, 0);
switch (m_type) {
case PEN_TYPE_CIRCLE:
image_ellipsefill(m_image, 0, 0, m_size-1, m_size-1, 1);
break;
case PEN_TYPE_SQUARE: {
double a = PI * m_angle / 180;
int r = m_size/2;
int x1, y1, x2, y2, x3, y3, x4, y4;
x1 = cos(a+ PI/4) * r;
y1 = -sin(a+ PI/4) * r;
x2 = cos(a+3*PI/4) * r;
y2 = -sin(a+3*PI/4) * r;
x3 = cos(a-3*PI/4) * r;
y3 = -sin(a-3*PI/4) * r;
x4 = cos(a- PI/4) * r;
y4 = -sin(a- PI/4) * r;
image_line(m_image, r+x1, r+y1, r+x2, r+y2, 1);
image_line(m_image, r+x2, r+y2, r+x3, r+y3, 1);
image_line(m_image, r+x3, r+y3, r+x4, r+y4, 1);
image_line(m_image, r+x4, r+y4, r+x1, r+y1, 1);
algo_floodfill(m_image, r, r, m_image, algo_hline);
break;
}
case PEN_TYPE_LINE: {
double a = PI * m_angle / 180;
int r = m_size/2;
x = cos(a) * r;
y = -sin(a) * r;
image_line(m_image, r-x, r-y, r+x, r+y, 1);
image_line(m_image, r-x-1, r-y, r+x-1, r+y, 1);
break;
}
}
m_scanline = jnew(PenScanline, m_size);
for (y=0; y<m_size; y++) {
m_scanline[y].state = false;
for (x=0; x<m_size; x++) {
if (image_getpixel(m_image, x, y)) {
m_scanline[y].x1 = x;
for (; x<m_size; x++)
if (!image_getpixel(m_image, x, y))
break;
m_scanline[y].x2 = x-1;
m_scanline[y].state = true;
break;
}
}
}
}

61
src/raster/pen.h Normal file
View File

@ -0,0 +1,61 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 RASTER_PEN_H_INCLUDED
#define RASTER_PEN_H_INCLUDED
#include "pen_type.h"
class Image;
struct PenScanline
{
int state, x1, x2;
};
class Pen
{
PenType m_type; /* type of pen */
int m_size; /* size (diameter) */
int m_angle; /* angle in degrees 0-360 */
Image* m_image; /* image of the pen */
PenScanline* m_scanline;
public:
Pen();
Pen(PenType type, int size, int angle);
Pen(const Pen& pen);
~Pen();
PenType get_type() const { return m_type; }
int get_size() const { return m_size; }
int get_angle() const { return m_angle; }
Image* get_image() { return m_image; }
PenScanline* get_scanline() { return m_scanline; }
void set_type(PenType type);
void set_size(int size);
void set_angle(int angle);
private:
void clean_pen();
void regenerate_pen();
};
#endif

View File

@ -21,7 +21,6 @@
#include "raster/algo.h"
#include "raster/blend.h"
#include "raster/brush.h"
#include "raster/cel.h"
#include "raster/dirty.h"
#include "raster/gfxobj.h"
@ -30,6 +29,7 @@
#include "raster/mask.h"
#include "raster/palette.h"
#include "raster/path.h"
#include "raster/pen.h"
#include "raster/quant.h"
#include "raster/rotate.h"
#include "raster/sprite.h"

112
src/settings/settings.h Normal file
View File

@ -0,0 +1,112 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 SETTINGS_SETTINGS_H_INCLUDED
#define SETTINGS_SETTINGS_H_INCLUDED
#include "jinete/jrect.h"
#include "core/color.h"
#include "tiled_mode.h"
#include "pen_type.h"
class IToolSettings;
class IPenSettings;
class Tool;
// Settings used in tool <-> drawing <-> editor stuff
class ISettings
{
public:
virtual ~ISettings() { }
// General settings
virtual color_t getFgColor() = 0;
virtual color_t getBgColor() = 0;
virtual Tool* getCurrentTool() = 0;
virtual TiledMode getTiledMode() = 0;
virtual void setFgColor(color_t color) = 0;
virtual void setBgColor(color_t color) = 0;
virtual void setCurrentTool(Tool* tool) = 0;
virtual void setTiledMode(TiledMode mode) = 0;
// Grid settings
virtual bool getSnapToGrid() = 0;
virtual bool getGridVisible() = 0;
virtual Rect getGridBounds() = 0;
virtual color_t getGridColor() = 0;
virtual void setSnapToGrid(bool state) = 0;
virtual void setGridVisible(bool state) = 0;
virtual void setGridBounds(Rect rect) = 0;
virtual void setGridColor(color_t color) = 0;
// Onionskin settings
virtual bool getUseOnionskin() = 0;
virtual int getOnionskinPrevFrames() = 0;
virtual int getOnionskinNextFrames() = 0;
virtual void setUseOnionskin(bool state) = 0;
virtual void setOnionskinPrevFrames(int frames) = 0;
virtual void setOnionskinNextFrames(int frames) = 0;
// Tools settings
virtual IToolSettings* getToolSettings(Tool* tool) = 0;
};
// Tool's settings
class IToolSettings
{
public:
virtual ~IToolSettings() { }
virtual IPenSettings* getPen() = 0;
virtual int getOpacity() = 0;
virtual bool getFilled() = 0;
virtual int getSprayWidth() = 0;
virtual int getSpraySpeed() = 0;
virtual void setOpacity(int opacity) = 0;
virtual void setFilled(bool state) = 0;
virtual void setSprayWidth(int width) = 0;
virtual void setSpraySpeed(int speed) = 0;
};
// Settings for a tool's pen
class IPenSettings
{
public:
virtual ~IPenSettings() { }
virtual PenType getType() = 0;
virtual int getSize() = 0;
virtual int getAngle() = 0;
virtual void setType(PenType type) = 0;
virtual void setSize(int size) = 0;
virtual void setAngle(int angle) = 0;
};
#endif

View File

@ -0,0 +1,333 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "config.h"
#include <allegro/color.h>
#include <string>
#include "app.h"
#include "core/cfg.h"
#include "settings/ui_settings_impl.h"
#include "ui_context.h"
#include "tools/tool.h"
#include "tools/toolbox.h"
#include "widgets/colbar.h"
//////////////////////////////////////////////////////////////////////
// UISettingsImpl
UISettingsImpl::UISettingsImpl()
: m_gridBounds(0, 0, 16, 16)
{
m_currentTool = NULL;
m_tiledMode = (TiledMode)get_config_int("Tools", "Tiled", (int)TILED_NONE);
m_tiledMode = (TiledMode)MID(0, (int)m_tiledMode, (int)TILED_BOTH);
m_use_onionskin = get_config_bool("Tools", "Onionskin", false);
m_snapToGrid = get_config_bool("Grid", "SnapTo", false);
m_gridVisible = get_config_bool("Grid", "Visible", false);
m_gridColor = get_config_color("Grid", "Color", color_rgb(0, 0, 255));
m_gridBounds = get_config_rect("Grid", "Bounds", m_gridBounds);
}
UISettingsImpl::~UISettingsImpl()
{
set_config_int("Tools", "Tiled", m_tiledMode);
set_config_bool("Tools", "Onionskin", m_use_onionskin);
set_config_bool("Grid", "SnapTo", m_snapToGrid);
set_config_bool("Grid", "Visible", m_gridVisible);
set_config_rect("Grid", "Bounds", m_gridBounds);
set_config_color("Grid", "Color", m_gridColor);
// delete all tool settings
std::map<std::string, IToolSettings*>::iterator it;
for (it = m_toolSettings.begin(); it != m_toolSettings.end(); ++it)
delete it->second;
}
//////////////////////////////////////////////////////////////////////
// General settings
color_t UISettingsImpl::getFgColor()
{
return colorbar_get_fg_color(app_get_colorbar());
}
color_t UISettingsImpl::getBgColor()
{
return colorbar_get_bg_color(app_get_colorbar());
}
Tool* UISettingsImpl::getCurrentTool()
{
if (!m_currentTool)
m_currentTool = App::instance()->get_toolbox()->getToolById("pencil");
return m_currentTool;
}
TiledMode UISettingsImpl::getTiledMode()
{
return m_tiledMode;
}
void UISettingsImpl::setFgColor(color_t color)
{
colorbar_set_fg_color(app_get_colorbar(), color);
}
void UISettingsImpl::setBgColor(color_t color)
{
colorbar_set_fg_color(app_get_colorbar(), color);
}
void UISettingsImpl::setCurrentTool(Tool* tool)
{
if (m_currentTool != tool) {
// Fire PenSizeBeforeChange signal (maybe the new selected tool has a different pen size)
App::instance()->PenSizeBeforeChange();
// Change the tool
m_currentTool = tool;
App::instance()->CurrentToolChange(); // Fire CurrentToolChange signal
App::instance()->PenSizeAfterChange(); // Fire PenSizeAfterChange signal
}
}
void UISettingsImpl::setTiledMode(TiledMode mode)
{
m_tiledMode = mode;
}
//////////////////////////////////////////////////////////////////////
// Grid settings
bool UISettingsImpl::getSnapToGrid()
{
return m_snapToGrid;
}
bool UISettingsImpl::getGridVisible()
{
return m_gridVisible;
}
Rect UISettingsImpl::getGridBounds()
{
return m_gridBounds;
}
color_t UISettingsImpl::getGridColor()
{
return m_gridColor;
}
void UISettingsImpl::setSnapToGrid(bool state)
{
m_snapToGrid = state;
}
void UISettingsImpl::setGridVisible(bool state)
{
m_gridVisible = state;
}
void UISettingsImpl::setGridBounds(Rect rect)
{
m_gridBounds = rect;
}
void UISettingsImpl::setGridColor(color_t color)
{
m_gridColor = color;
}
//////////////////////////////////////////////////////////////////////
// Onionskin settings
bool UISettingsImpl::getUseOnionskin()
{
return m_use_onionskin;
}
int UISettingsImpl::getOnionskinPrevFrames()
{
return 1;
}
int UISettingsImpl::getOnionskinNextFrames()
{
return 0;
}
void UISettingsImpl::setUseOnionskin(bool state)
{
}
void UISettingsImpl::setOnionskinPrevFrames(int frames)
{
}
void UISettingsImpl::setOnionskinNextFrames(int frames)
{
}
//////////////////////////////////////////////////////////////////////
// Tools & pen settings
class UIPenSettingsImpl : public IPenSettings
{
PenType m_type;
int m_size;
int m_angle;
bool m_fireSignals;
public:
UIPenSettingsImpl()
{
m_type = PEN_TYPE_FIRST;
m_size = 1;
m_angle = 0;
m_fireSignals = true;
}
~UIPenSettingsImpl()
{
}
PenType getType() { return m_type; }
int getSize() { return m_size; }
int getAngle() { return m_angle; }
void setType(PenType type)
{
m_type = MID(PEN_TYPE_FIRST, type, PEN_TYPE_LAST);
}
void setSize(int size)
{
// Trigger PenSizeBeforeChange signal
if (m_fireSignals)
App::instance()->PenSizeBeforeChange();
// Change the size of the pencil
m_size = MID(1, size, 32);
// Trigger PenSizeAfterChange signal
if (m_fireSignals)
App::instance()->PenSizeAfterChange();
}
void setAngle(int angle)
{
m_angle = MID(0, angle, 360);
}
void enableSignals(bool state)
{
m_fireSignals = state;
}
};
class UIToolSettingsImpl : public IToolSettings
{
Tool* m_tool;
UIPenSettingsImpl m_pen;
int m_opacity;
bool m_filled;
int m_spray_width;
int m_spray_speed;
public:
UIToolSettingsImpl(Tool* tool)
: m_tool(tool)
{
std::string cfg_section(getCfgSection());
m_opacity = get_config_int(cfg_section.c_str(), "Opacity", 255);
m_opacity = MID(0, m_opacity, 255);
m_filled = false;
m_spray_width = 16;
m_spray_speed = 32;
m_pen.enableSignals(false);
m_pen.setType((PenType)get_config_int(cfg_section.c_str(), "PenType", (int)PEN_TYPE_CIRCLE));
m_pen.setSize(get_config_int(cfg_section.c_str(), "PenSize", m_tool->getDefaultPenSize()));
m_pen.setAngle(get_config_int(cfg_section.c_str(), "PenAngle", 0));
m_pen.enableSignals(true);
if (m_tool->getPointShape(0)->isSpray() ||
m_tool->getPointShape(1)->isSpray()) {
m_spray_width = get_config_int(cfg_section.c_str(), "SprayWidth", m_spray_width);
m_spray_speed = get_config_int(cfg_section.c_str(), "SpraySpeed", m_spray_speed);
}
}
~UIToolSettingsImpl()
{
std::string cfg_section(getCfgSection());
set_config_int(cfg_section.c_str(), "Opacity", m_opacity);
set_config_int(cfg_section.c_str(), "PenType", m_pen.getType());
set_config_int(cfg_section.c_str(), "PenSize", m_pen.getSize());
set_config_int(cfg_section.c_str(), "PenAngle", m_pen.getAngle());
if (m_tool->getPointShape(0)->isSpray() ||
m_tool->getPointShape(1)->isSpray()) {
set_config_int(cfg_section.c_str(), "SprayWidth", m_spray_width);
set_config_int(cfg_section.c_str(), "SpraySpeed", m_spray_speed);
}
}
IPenSettings* getPen() { return &m_pen; }
int getOpacity() { return m_opacity; }
bool getFilled() { return m_filled; }
int getSprayWidth() { return m_spray_width; }
int getSpraySpeed() { return m_spray_speed; }
void setOpacity(int opacity) { m_opacity = opacity; }
void setFilled(bool state) { m_filled = state; }
void setSprayWidth(int width) { m_spray_width = width; }
void setSpraySpeed(int speed) { m_spray_speed = speed; }
private:
std::string getCfgSection() const {
return std::string("Tool:") + m_tool->getId();
}
};
IToolSettings* UISettingsImpl::getToolSettings(Tool* tool)
{
assert(tool != NULL);
std::map<std::string, IToolSettings*>::iterator
it = m_toolSettings.find(tool->getId());
if (it != m_toolSettings.end()) {
return it->second;
}
else {
IToolSettings* tool_settings = new UIToolSettingsImpl(tool);
m_toolSettings[tool->getId()] = tool_settings;
return tool_settings;
}
}

View File

@ -0,0 +1,81 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 SETTINGS_UI_SETTINGS_H_INCLUDED
#define SETTINGS_UI_SETTINGS_H_INCLUDED
#include <map>
#include <string>
#include "settings/settings.h"
class UISettingsImpl : public ISettings
{
TiledMode m_tiledMode;
Tool* m_currentTool;
bool m_use_onionskin;
bool m_snapToGrid;
bool m_gridVisible;
Rect m_gridBounds;
color_t m_gridColor;
std::map<std::string, IToolSettings*> m_toolSettings;
public:
UISettingsImpl();
~UISettingsImpl();
// General settings
color_t getFgColor();
color_t getBgColor();
Tool* getCurrentTool();
TiledMode getTiledMode();
void setFgColor(color_t color);
void setBgColor(color_t color);
void setCurrentTool(Tool* tool);
void setTiledMode(TiledMode mode);
// Grid settings
bool getSnapToGrid();
bool getGridVisible();
Rect getGridBounds();
color_t getGridColor();
void setSnapToGrid(bool state);
void setGridVisible(bool state);
void setGridBounds(Rect rect);
void setGridColor(color_t color);
// Onionskin settings
bool getUseOnionskin();
int getOnionskinPrevFrames();
int getOnionskinNextFrames();
void setUseOnionskin(bool state);
void setOnionskinPrevFrames(int frames);
void setOnionskinNextFrames(int frames);
// Tools settings
IToolSettings* getToolSettings(Tool* tool);
};
#endif

View File

@ -29,8 +29,8 @@ static void draw_dirty(int x1, int y, int y2, void *data)
int main (int argc, char *argv[])
{
Brush* brush1;
Brush* brush2;
Pen* pen1;
Pen* pen2;
Dirty* dirty;
Image* image;
BITMAP* bmp;
@ -52,11 +52,11 @@ int main (int argc, char *argv[])
image = image_new(IMAGE_INDEXED, bmp->w, bmp->h);
dirty = dirty_new(image, 0, 0, image->w-1, image->h-1, false);
brush1 = brush_new();
brush2 = brush_new();
pen1 = pen_new();
pen2 = pen_new();
brush_set_size(brush1, 1);
brush_set_size(brush2, 8);
pen_set_size(pen1, 1);
pen_set_size(pen2, 8);
image_clear(image, 0);
for (c=128; c>0; c-=8)
@ -81,8 +81,8 @@ int main (int argc, char *argv[])
mb = mouse_b;
if (mb) {
dirty_line_brush(dirty, (mb & 2) ? brush2: brush1,
ox, oy, mx, my);
dirty_line_pen(dirty, (mb & 2) ? pen2: pen1,
ox, oy, mx, my);
redraw = true;
}

30
src/tiled_mode.h Normal file
View File

@ -0,0 +1,30 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 TILED_MODE_H_INCLUDED
#define TILED_MODE_H_INCLUDED
enum TiledMode {
TILED_NONE = 0,
TILED_X_AXIS = 1,
TILED_Y_AXIS = 2,
TILED_BOTH = 3,
};
#endif

275
src/tools/controllers.h Normal file
View File

@ -0,0 +1,275 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include <cmath>
#include <allegro.h> // TODO avoid to include this for key_shifts
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// Controls clicks for tools like pencil
class FreehandController : public ToolController
{
public:
void pressButton(std::vector<Point>& points, const Point& point)
{
points.push_back(point);
}
bool releaseButton(std::vector<Point>& points, const Point& point)
{
return false;
}
void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point)
{
points.push_back(point);
}
void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output)
{
if (input.size() == 1) {
output.push_back(input[0]);
}
else if (input.size() >= 2) {
output.push_back(input[input.size()-2]);
output.push_back(input[input.size()-1]);
}
}
void getStatusBarText(const std::vector<Point>& points, std::string& text)
{
char buf[1024];
sprintf(buf, "Start %3d %3d End %3d %3d",
points[0].x, points[0].y,
points[points.size()-1].x,
points[points.size()-1].y);
text = buf;
}
};
// Controls clicks for tools like line
class TwoPointsController : public ToolController
{
Point m_center;
public:
void pressButton(std::vector<Point>& points, const Point& point)
{
m_center = point;
points.push_back(point);
points.push_back(point);
}
bool releaseButton(std::vector<Point>& points, const Point& point)
{
return false;
}
void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point)
{
points[1] = point;
// Square aspect
if (key_shifts & KB_SHIFT_FLAG) { // TODO avoid direct access to key_shifts
int dx = points[1].x - m_center.x;
int dy = points[1].y - m_center.y;
int minsize = MIN(ABS(dx), ABS(dy));
int maxsize = MAX(ABS(dx), ABS(dy));
// Lines
if (loop->getIntertwine()->snapByAngle()) {
double angle = 180.0 * std::atan(static_cast<double>(-dy) /
static_cast<double>(dx)) / M_PI;
angle = ABS(angle);
// Snap horizontally
if (angle < 18.0) {
points[1].y = m_center.y;
}
// Snap at 26.565
else if (angle < 36.0) {
points[1].x = m_center.x + SGN(dx)*maxsize;
points[1].y = m_center.y + SGN(dy)*maxsize/2;
}
// Snap at 45
else if (angle < 54.0) {
points[1].x = m_center.x + SGN(dx)*minsize;
points[1].y = m_center.y + SGN(dy)*minsize;
}
// Snap at 63.435
else if (angle < 72.0) {
points[1].x = m_center.x + SGN(dx)*maxsize/2;
points[1].y = m_center.y + SGN(dy)*maxsize;
}
// Snap vertically
else {
points[1].x = m_center.x;
}
}
// Rectangles and ellipses
else {
points[1].x = m_center.x + SGN(dx)*minsize;
points[1].y = m_center.y + SGN(dy)*minsize;
}
}
// Center
if (key_shifts & KB_CTRL_FLAG) { // TODO avoid direct access to key_shifts
int rx = points[1].x - m_center.x;
int ry = points[1].y - m_center.y;
points[0].x = m_center.x - rx;
points[0].y = m_center.y - ry;
points[1].x = m_center.x + rx;
points[1].y = m_center.y + ry;
}
else
points[0] = m_center;
}
void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output)
{
output.push_back(input[0]);
output.push_back(input[1]);
}
void getStatusBarText(const std::vector<Point>& points, std::string& text)
{
char buf[1024];
sprintf(buf, "Start %3d %3d End %3d %3d (Size %3d %3d) Angle %.1f",
points[0].x, points[0].y,
points[1].x, points[1].y,
ABS(points[1].x-points[0].x)+1,
ABS(points[1].y-points[0].y)+1,
180.0 * std::atan2(static_cast<double>(points[0].y-points[1].y),
static_cast<double>(points[1].x-points[0].x)) / M_PI);
text = buf;
}
};
// Controls clicks for tools like polygon
class PointByPointController : public ToolController
{
public:
void pressButton(std::vector<Point>& points, const Point& point)
{
points.push_back(point);
points.push_back(point);
}
bool releaseButton(std::vector<Point>& points, const Point& point)
{
if (points[points.size()-2] == point &&
points[points.size()-1] == point)
return false; // Click in the same point (no-drag), we are done
else
return true; // Continue adding points
}
void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point)
{
points[points.size()-1] = point;
}
void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output)
{
output = input;
}
void getStatusBarText(const std::vector<Point>& points, std::string& text)
{
char buf[1024];
sprintf(buf, "Start %3d %3d End %3d %3d",
points[0].x, points[0].y,
points[points.size()-1].x,
points[points.size()-1].y);
text = buf;
}
};
class OnePointController : public ToolController
{
public:
// Do not apply grid to "one point tools" (e.g. magic wand, flood fill, etc.)
bool canSnapToGrid() { return false; }
void pressButton(std::vector<Point>& points, const Point& point)
{
if (points.size() == 0)
points.push_back(point);
}
bool releaseButton(std::vector<Point>& points, const Point& point)
{
return false;
}
void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point)
{
// Do nothing
}
void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output)
{
output = input;
}
void getStatusBarText(const std::vector<Point>& points, std::string& text)
{
char buf[1024];
sprintf(buf, "Pos %3d %3d", points[0].x, points[0].y);
text = buf;
}
};
class FourPointsController : public ToolController
{
int m_clickCounter;
public:
void pressButton(std::vector<Point>& points, const Point& point)
{
if (points.size() == 0) {
points.resize(4, point);
m_clickCounter = 0;
}
else
m_clickCounter++;
}
bool releaseButton(std::vector<Point>& points, const Point& point)
{
m_clickCounter++;
return m_clickCounter < 4;
}
void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point)
{
switch (m_clickCounter) {
case 0:
for (size_t i=1; i<points.size(); ++i)
points[i] = point;
break;
case 1:
case 2:
points[1] = point;
points[2] = point;
break;
case 3:
points[2] = point;
break;
}
}
void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output)
{
output = input;
}
void getStatusBarText(const std::vector<Point>& points, std::string& text)
{
char buf[1024];
sprintf(buf, "Start %3d %3d End %3d %3d (%3d %3d - %3d %3d)",
points[0].x, points[0].y,
points[3].x, points[3].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
text = buf;
}
};

465
src/tools/ink_processing.h Normal file
View File

@ -0,0 +1,465 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "effect/effect.h"
#include "modules/palettes.h"
#include "raster/palette.h"
//////////////////////////////////////////////////////////////////////
// Ink Processing
//////////////////////////////////////////////////////////////////////
#define DEFINE_INK_PROCESSING(addresses_define, \
addresses_initialize, \
addresses_increment, \
processing) \
addresses_define \
register int x; \
\
/* with mask */ \
if (!loop->getMask()->is_empty()) { \
Point maskOrigin(loop->getMaskOrigin()); \
\
if ((y < maskOrigin.y) || (y >= maskOrigin.y+loop->getMask()->h)) \
return; \
\
if (x1 < maskOrigin.x) \
x1 = maskOrigin.x; \
\
if (x2 > maskOrigin.x+loop->getMask()->w-1) \
x2 = maskOrigin.x+loop->getMask()->w-1; \
\
if (Image* bitmap = loop->getMask()->bitmap) { \
addresses_initialize; \
for (x=x1; x<=x2; ++x) { \
if (bitmap->getpixel(x-maskOrigin.x, y-maskOrigin.y)) \
processing; \
\
addresses_increment; \
} \
return; \
} \
} \
\
addresses_initialize; \
for (x=x1; x<=x2; ++x) { \
processing; \
addresses_increment; \
}
#define DEFINE_INK_PROCESSING_DST(Traits, processing) \
DEFINE_INK_PROCESSING(register Traits::address_t dst_address; , \
dst_address = ((Traits::address_t*)loop->getDstImage()->line)[y]+x1; , \
++dst_address , \
processing)
#define DEFINE_INK_PROCESSING_SRCDST(Traits, processing) \
DEFINE_INK_PROCESSING(register Traits::address_t src_address; \
register Traits::address_t dst_address; , \
src_address = ((Traits::address_t*)loop->getSrcImage()->line)[y]+x1; \
dst_address = ((Traits::address_t*)loop->getDstImage()->line)[y]+x1; , \
++src_address; \
++dst_address; , \
processing)
//////////////////////////////////////////////////////////////////////
// Opaque Ink
//////////////////////////////////////////////////////////////////////
static void ink_hline32_opaque(int x1, int y, int x2, IToolLoop* loop)
{
int c = loop->getPrimaryColor();
DEFINE_INK_PROCESSING_DST
(RgbTraits,
*dst_address = c );
}
static void ink_hline16_opaque(int x1, int y, int x2, IToolLoop* loop)
{
int c = loop->getPrimaryColor();
DEFINE_INK_PROCESSING_DST
(GrayscaleTraits,
*dst_address = c );
}
static void ink_hline8_opaque(int x1, int y, int x2, IToolLoop* loop)
{
int c = loop->getPrimaryColor();
DEFINE_INK_PROCESSING_DST
(IndexedTraits,
*dst_address = c );
/* memset(((ase_uint8 **)data->dst_image->line)[y]+x1, data->color, x2-x1+1); */
}
//////////////////////////////////////////////////////////////////////
// Transparent Ink
//////////////////////////////////////////////////////////////////////
static void ink_hline32_transparent(int x1, int y, int x2, IToolLoop* loop)
{
int color = loop->getPrimaryColor();
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(RgbTraits,
*dst_address = _rgba_blend_normal(*src_address, color, opacity));
}
static void ink_hline16_transparent(int x1, int y, int x2, IToolLoop* loop)
{
int color = loop->getPrimaryColor();
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(GrayscaleTraits,
*dst_address = _graya_blend_normal(*src_address, color, opacity));
}
static void ink_hline8_transparent(int x1, int y, int x2, IToolLoop* loop)
{
Palette* pal = get_current_palette();
ase_uint32 c;
ase_uint32 tc = pal->color[loop->getPrimaryColor()];
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(IndexedTraits,
{
c = _rgba_blend_normal(pal->color[*src_address], tc, opacity);
*dst_address = orig_rgb_map->data
[_rgba_getr(c)>>3]
[_rgba_getg(c)>>3]
[_rgba_getb(c)>>3];
});
}
//////////////////////////////////////////////////////////////////////
// Blur Ink
//////////////////////////////////////////////////////////////////////
static void ink_hline32_blur(int x1, int y, int x2, IToolLoop* loop)
{
int c, r, g, b, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint32 *src_address2;
DEFINE_INK_PROCESSING_SRCDST
(RgbTraits,
{
c = 0;
r = g = b = a = 0;
GET_MATRIX_DATA
(ase_uint32, src, src_address2,
3, 3, 1, 1, tiled,
color = *src_address2;
if (_rgba_geta(color) != 0) {
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
a += _rgba_geta(color);
++c;
}
);
if (c > 0) {
r /= c;
g /= c;
b /= c;
a /= 9;
c = *src_address;
r = _rgba_getr(c) + (r-_rgba_getr(c)) * opacity / 255;
g = _rgba_getg(c) + (g-_rgba_getg(c)) * opacity / 255;
b = _rgba_getb(c) + (b-_rgba_getb(c)) * opacity / 255;
a = _rgba_geta(c) + (a-_rgba_geta(c)) * opacity / 255;
*dst_address = _rgba(r, g, b, a);
}
else {
*dst_address = *src_address;
}
});
}
static void ink_hline16_blur(int x1, int y, int x2, IToolLoop* loop)
{
int c, v, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint16 *src_address2;
DEFINE_INK_PROCESSING_SRCDST
(GrayscaleTraits,
{
c = 0;
v = a = 0;
GET_MATRIX_DATA
(ase_uint16, src, src_address2,
3, 3, 1, 1, tiled,
color = *src_address2;
if (_graya_geta(color) > 0) {
v += _graya_getv(color);
a += _graya_geta(color);
}
c++;
);
if (c > 0) {
v /= c;
a /= 9;
c = *src_address;
v = _graya_getv(c) + (v-_graya_getv(c)) * opacity / 255;
a = _graya_geta(c) + (a-_graya_geta(c)) * opacity / 255;
*dst_address = _graya(v, a);
}
else {
*dst_address = *src_address;
}
});
}
static void ink_hline8_blur(int x1, int y, int x2, IToolLoop* loop)
{
Palette *pal = get_current_palette();
int c, r, g, b, a;
int opacity = loop->getOpacity();
TiledMode tiled = loop->getTiledMode();
Image* src = loop->getSrcImage();
int getx, gety;
int addx, addy;
int dx, dy, color;
ase_uint8 *src_address2;
DEFINE_INK_PROCESSING_SRCDST
(IndexedTraits,
{
c = 0;
r = g = b = a = 0;
GET_MATRIX_DATA
(ase_uint8, src, src_address2,
3, 3, 1, 1, tiled,
color = *src_address2;
a += (color == 0 ? 0: 255);
color = pal->color[color];
r += _rgba_getr(color);
g += _rgba_getg(color);
b += _rgba_getb(color);
c++;
);
if (c > 0 && a/9 >= 128) {
r /= c;
g /= c;
b /= c;
c = pal->color[*src_address];
r = _rgba_getr(c) + (r-_rgba_getr(c)) * opacity / 255;
g = _rgba_getg(c) + (g-_rgba_getg(c)) * opacity / 255;
b = _rgba_getb(c) + (b-_rgba_getb(c)) * opacity / 255;
*dst_address = orig_rgb_map->data[r>>3][g>>3][b>>3];
}
else {
*dst_address = *src_address;
}
});
}
//////////////////////////////////////////////////////////////////////
// Replace Ink
//////////////////////////////////////////////////////////////////////
static void ink_hline32_replace(int x1, int y, int x2, IToolLoop* loop)
{
int color1 = loop->getPrimaryColor();
int color2 = loop->getSecondaryColor();
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(RgbTraits,
if (*src_address == color1) {
*dst_address = _rgba_blend_normal(*src_address, color2, opacity);
});
}
static void ink_hline16_replace(int x1, int y, int x2, IToolLoop* loop)
{
int color1 = loop->getPrimaryColor();
int color2 = loop->getSecondaryColor();
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(GrayscaleTraits,
if (*src_address == color1) {
*dst_address = _graya_blend_normal(*src_address, color2, opacity);
});
}
static void ink_hline8_replace(int x1, int y, int x2, IToolLoop* loop)
{
int color1 = loop->getPrimaryColor();
Palette *pal = get_current_palette();
ase_uint32 c;
ase_uint32 tc = pal->color[loop->getSecondaryColor()];
int opacity = loop->getOpacity();
DEFINE_INK_PROCESSING_SRCDST
(IndexedTraits,
if (*src_address == color1) {
c = _rgba_blend_normal(pal->color[*src_address], tc, opacity);
*dst_address = orig_rgb_map->data
[_rgba_getr(c)>>3]
[_rgba_getg(c)>>3]
[_rgba_getb(c)>>3];
});
}
//////////////////////////////////////////////////////////////////////
// Jumble Ink
//////////////////////////////////////////////////////////////////////
#define JUMBLE_XY_IN_UV() \
u = x + (rand() % 3)-1 - speed.x; \
v = y + (rand() % 3)-1 - speed.y; \
\
if (tiled & TILED_X_AXIS) { \
if (u < 0) \
u = loop->getSrcImage()->w - (-(u+1) % loop->getSrcImage()->w) - 1; \
else if (u >= loop->getSrcImage()->w) \
u %= loop->getSrcImage()->w; \
} \
else { \
u = MID(0, u, loop->getSrcImage()->w-1); \
} \
\
if (tiled & TILED_Y_AXIS) { \
if (v < 0) \
v = loop->getSrcImage()->h - (-(v+1) % loop->getSrcImage()->h) - 1; \
else if (v >= loop->getSrcImage()->h) \
v %= loop->getSrcImage()->h; \
} \
else { \
v = MID(0, v, loop->getSrcImage()->h-1); \
} \
color = image_getpixel(loop->getSrcImage(), u, v);
static void ink_hline32_jumble(int x1, int y, int x2, IToolLoop* loop)
{
int opacity = loop->getOpacity();
Point speed(loop->getSpeed() / 4);
TiledMode tiled = loop->getTiledMode();
int u, v, color;
DEFINE_INK_PROCESSING_SRCDST
(RgbTraits,
{
JUMBLE_XY_IN_UV();
*dst_address = _rgba_blend_MERGE(*src_address, color, opacity);
}
);
}
static void ink_hline16_jumble(int x1, int y, int x2, IToolLoop* loop)
{
int opacity = loop->getOpacity();
Point speed(loop->getSpeed() / 4);
TiledMode tiled = loop->getTiledMode();
int u, v, color;
DEFINE_INK_PROCESSING_SRCDST
(GrayscaleTraits,
{
JUMBLE_XY_IN_UV();
*dst_address = _graya_blend_MERGE(*src_address, color, opacity);
}
);
}
static void ink_hline8_jumble(int x1, int y, int x2, IToolLoop* loop)
{
Palette *pal = get_current_palette();
ase_uint32 c, tc;
int opacity = loop->getOpacity();
Point speed(loop->getSpeed() / 4);
TiledMode tiled = loop->getTiledMode();
int u, v, color;
DEFINE_INK_PROCESSING_SRCDST
(IndexedTraits,
{
JUMBLE_XY_IN_UV();
tc = color != 0 ? pal->color[color]: 0;
c = _rgba_blend_MERGE(*src_address != 0 ? pal->color[*src_address]: 0,
tc, opacity);
if (_rgba_geta(c) >= 128)
*dst_address = orig_rgb_map->data
[_rgba_getr(c)>>3]
[_rgba_getg(c)>>3]
[_rgba_getb(c)>>3];
else
*dst_address = 0;
}
);
}
//////////////////////////////////////////////////////////////////////
enum {
INK_OPAQUE,
INK_TRANSPARENT,
INK_BLUR,
INK_REPLACE,
INK_JUMBLE,
MAX_INKS
};
static AlgoHLine ink_processing[][3] =
{
#define DEF_INK(name) \
{ (AlgoHLine)ink_hline32_##name, \
(AlgoHLine)ink_hline16_##name, \
(AlgoHLine)ink_hline8_##name }
DEF_INK(opaque),
DEF_INK(transparent),
DEF_INK(blur),
DEF_INK(replace),
DEF_INK(jumble)
};

267
src/tools/inks.h Normal file
View File

@ -0,0 +1,267 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "app.h" // TODO avoid to include this file
#include "raster/undo.h"
#include "commands/commands.h"
#include "commands/params.h"
#include "tools/ink_processing.h"
// Ink used for tools which paint with primary/secondary
// (or foreground/background colors)
class PaintInk : public ToolInk
{
public:
enum Type { Normal, WithFg, WithBg };
private:
AlgoHLine m_proc;
Type m_type;
public:
PaintInk(Type type) : m_type(type) { }
bool isPaint() const { return true; }
void prepareInk(IToolLoop* loop)
{
switch (m_type) {
case Normal:
// Do nothing, use the default colors
break;
case WithFg:
case WithBg:
{
int color = get_color_for_layer(loop->getLayer(),
m_type == WithFg ?
loop->getContext()->getSettings()->getFgColor():
loop->getContext()->getSettings()->getBgColor());
loop->setPrimaryColor(color);
loop->setSecondaryColor(color);
}
break;
}
m_proc = loop->getOpacity() == 255 ?
ink_processing[INK_OPAQUE][MID(0, loop->getSprite()->imgtype, 2)]:
ink_processing[INK_TRANSPARENT][MID(0, loop->getSprite()->imgtype, 2)];
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
(*m_proc)(x1, y, x2, loop);
}
};
class PickInk : public ToolInk
{
public:
enum Target { Fg, Bg };
private:
Target m_target;
public:
PickInk(Target target) : m_target(target) { }
bool isEyedropper() const { return true; }
void prepareInk(IToolLoop* loop)
{
// Do nothing
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
Command* eyedropper_cmd =
CommandsModule::instance()->get_command_by_name(CommandId::eyedropper);
Params params;
params.set("target", m_target == Bg ? "background": "foreground");
loop->getContext()->execute_command(eyedropper_cmd, &params);
}
};
class ScrollInk : public ToolInk
{
public:
void prepareInk(IToolLoop* loop)
{
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
}
};
class MoveInk : public ToolInk
{
public:
void prepareInk(IToolLoop* loop)
{
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
}
};
class EraserInk : public ToolInk
{
public:
enum Type { Eraser, ReplaceFgWithBg, ReplaceBgWithFg };
private:
AlgoHLine m_proc;
Type m_type;
public:
EraserInk(Type type) : m_type(type) { }
bool isPaint() const { return true; }
bool isEffect() const { return true; }
void prepareInk(IToolLoop* loop)
{
switch (m_type) {
case Eraser:
m_proc = ink_processing[INK_OPAQUE][MID(0, loop->getSprite()->imgtype, 2)];
// TODO app_get_color_to_clear_layer should receive the context as parameter
loop->setPrimaryColor(app_get_color_to_clear_layer(loop->getLayer()));
loop->setSecondaryColor(app_get_color_to_clear_layer(loop->getLayer()));
break;
case ReplaceFgWithBg:
m_proc = ink_processing[INK_REPLACE][MID(0, loop->getSprite()->imgtype, 2)];
loop->setPrimaryColor(get_color_for_layer(loop->getLayer(),
loop->getContext()->getSettings()->getFgColor()));
loop->setSecondaryColor(get_color_for_layer(loop->getLayer(),
loop->getContext()->getSettings()->getBgColor()));
break;
case ReplaceBgWithFg:
m_proc = ink_processing[INK_REPLACE][MID(0, loop->getSprite()->imgtype, 2)];
loop->setPrimaryColor(get_color_for_layer(loop->getLayer(),
loop->getContext()->getSettings()->getBgColor()));
loop->setSecondaryColor(get_color_for_layer(loop->getLayer(),
loop->getContext()->getSettings()->getFgColor()));
break;
}
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
(*m_proc)(x1, y, x2, loop);
}
};
class BlurInk : public ToolInk
{
AlgoHLine m_proc;
public:
bool isPaint() const { return true; }
bool isEffect() const { return true; }
void prepareInk(IToolLoop* loop)
{
m_proc = ink_processing[INK_BLUR][MID(0, loop->getSprite()->imgtype, 2)];
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
(*m_proc)(x1, y, x2, loop);
}
};
class JumbleInk : public ToolInk
{
AlgoHLine m_proc;
public:
bool isPaint() const { return true; }
bool isEffect() const { return true; }
void prepareInk(IToolLoop* loop)
{
m_proc = ink_processing[INK_JUMBLE][MID(0, loop->getSprite()->imgtype, 2)];
}
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
(*m_proc)(x1, y, x2, loop);
}
};
// Ink used for selection tools (like Rectangle Marquee, Lasso, Magic Wand, etc.)
class SelectionInk : public ToolInk
{
bool m_modify_selection;
public:
SelectionInk() { m_modify_selection = false; }
bool isSelection() const { return true; }
void inkHline(int x1, int y, int x2, IToolLoop* loop)
{
if (m_modify_selection) {
if (loop->getMouseButton() == 0)
loop->getMask()->add(x1, y, x2-x1+1, 1);
else if (loop->getMouseButton() == 1)
mask_subtract(loop->getMask(), x1, y, x2-x1+1, 1);
}
else
image_hline(loop->getDstImage(), x1, y, x2, loop->getPrimaryColor());
}
void setFinalStep(IToolLoop* loop, bool state)
{
m_modify_selection = state;
if (state) {
if (undo_is_enabled(loop->getSprite()->undo))
undo_set_mask(loop->getSprite()->undo, loop->getSprite());
loop->getMask()->freeze();
loop->getMask()->reserve(0, 0, loop->getSprite()->w, loop->getSprite()->h);
}
else {
loop->getMask()->unfreeze();
}
}
};

214
src/tools/intertwiners.h Normal file
View File

@ -0,0 +1,214 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
class IntertwineNone : public ToolIntertwine
{
public:
void joinPoints(IToolLoop* loop, const std::vector<Point>& points)
{
for (size_t c=0; c<points.size(); ++c)
doPointshapePoint(points[c].x, points[c].y, loop);
}
void fillPoints(IToolLoop* loop, const std::vector<Point>& points)
{
joinPoints(loop, points);
}
};
class IntertwineAsLines : public ToolIntertwine
{
public:
bool snapByAngle() { return true; }
void joinPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() == 0)
return;
if (points.size() == 1) {
doPointshapePoint(points[0].x, points[0].y, loop);
}
else if (points.size() >= 2) {
for (size_t c=0; c+1<points.size(); c+=2) {
int x1 = points[c].x;
int y1 = points[c].y;
int x2 = points[c+1].x;
int y2 = points[c+1].y;
algo_line(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
}
}
}
void fillPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() < 3) {
joinPoints(loop, points);
return;
}
algo_polygon(loop->getDstImage(),
points.size(),
(const int*)&points[0], loop, (AlgoHLine)doPointshapeHline);
}
};
class IntertwineAsRectangles : public ToolIntertwine
{
public:
void joinPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() == 0)
return;
if (points.size() == 1) {
doPointshapePoint(points[0].x, points[0].y, loop);
}
else if (points.size() >= 2) {
for (size_t c=0; c+1<points.size(); c+=2) {
int x1 = points[c].x;
int y1 = points[c].y;
int x2 = points[c+1].x;
int y2 = points[c+1].y;
int y;
if (x1 > x2) std::swap(x1, x2);
if (y1 > y2) std::swap(y1, y2);
doPointshapeLine(x1, y1, x2, y1, loop);
doPointshapeLine(x1, y2, x2, y2, loop);
for (y=y1; y<=y2; y++) {
doPointshapePoint(x1, y, loop);
doPointshapePoint(x2, y, loop);
}
}
}
}
void fillPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() < 2) {
joinPoints(loop, points);
return;
}
for (size_t c=0; c+1<points.size(); c+=2) {
int x1 = points[c].x;
int y1 = points[c].y;
int x2 = points[c+1].x;
int y2 = points[c+1].y;
int y;
if (x1 > x2) std::swap(x1, x2);
if (y1 > y2) std::swap(y1, y2);
for (y=y1; y<=y2; y++)
doPointshapeLine(x1, y, x2, y, loop);
}
}
};
class IntertwineAsEllipses : public ToolIntertwine
{
public:
void joinPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() == 0)
return;
if (points.size() == 1) {
doPointshapePoint(points[0].x, points[0].y, loop);
}
else if (points.size() >= 2) {
for (size_t c=0; c+1<points.size(); c+=2) {
int x1 = points[c].x;
int y1 = points[c].y;
int x2 = points[c+1].x;
int y2 = points[c+1].y;
if (x1 > x2) std::swap(x1, x2);
if (y1 > y2) std::swap(y1, y2);
algo_ellipse(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
}
}
}
void fillPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() < 2) {
joinPoints(loop, points);
return;
}
for (size_t c=0; c+1<points.size(); c+=2) {
int x1 = points[c].x;
int y1 = points[c].y;
int x2 = points[c+1].x;
int y2 = points[c+1].y;
if (x1 > x2) std::swap(x1, x2);
if (y1 > y2) std::swap(y1, y2);
algo_ellipsefill(x1, y1, x2, y2, loop, (AlgoHLine)doPointshapeHline);
}
}
};
class IntertwineAsBezier : public ToolIntertwine
{
public:
void joinPoints(IToolLoop* loop, const std::vector<Point>& points)
{
if (points.size() == 0)
return;
for (size_t c=0; c<points.size(); c += 4) {
if (points.size()-c == 1) {
doPointshapePoint(points[c].x, points[c].y, loop);
}
else if (points.size()-c == 2) {
algo_line(points[c].x, points[c].y,
points[c+1].x, points[c+1].y, loop, (AlgoPixel)doPointshapePoint);
}
else if (points.size()-c == 3) {
algo_spline(points[c ].x, points[c ].y,
points[c+1].x, points[c+1].y,
points[c+1].x, points[c+1].y,
points[c+2].x, points[c+2].y, loop, (AlgoLine)doPointshapeLine);
}
else {
algo_spline(points[c ].x, points[c ].y,
points[c+1].x, points[c+1].y,
points[c+2].x, points[c+2].y,
points[c+3].x, points[c+3].y, loop, (AlgoLine)doPointshapeLine);
}
}
}
void fillPoints(IToolLoop* loop, const std::vector<Point>& points)
{
joinPoints(loop, points);
}
};

137
src/tools/point_shapes.h Normal file
View File

@ -0,0 +1,137 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
class NonePointShape : public ToolPointShape
{
public:
void transformPoint(IToolLoop* loop, int x, int y)
{
// Do nothing
}
void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area)
{
// Do nothing
}
};
class PixelPointShape : public ToolPointShape
{
public:
void transformPoint(IToolLoop* loop, int x, int y)
{
doInkHline(x, y, x, loop);
}
void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area)
{
area = Rect(x, y, 1, 1);
}
};
class PenPointShape : public ToolPointShape
{
public:
void transformPoint(IToolLoop* loop, int x, int y)
{
Pen* pen = loop->getPen();
register PenScanline *scanline = pen->get_scanline();
register int h = pen->get_size();
register int c = h/2;
x -= c;
y -= c;
for (c=0; c<h; c++) {
if (scanline->state)
doInkHline(x+scanline->x1, y+c, x+scanline->x2, loop);
++scanline;
}
}
void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area)
{
Pen* pen = loop->getPen();
int size = pen->get_size();
area = Rect(x-size/2, y-size/2, size, size);
}
};
class FloodFillPointShape : public ToolPointShape
{
public:
void transformPoint(IToolLoop* loop, int x, int y)
{
algo_floodfill(loop->getSrcImage(), x, y, loop, (AlgoHLine)doInkHline);
}
void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area)
{
area = Rect(0, 0, 9999, 9999);
}
};
class SprayPointShape : public ToolPointShape
{
PenPointShape m_subPointShape;
public:
bool isSpray() { return true; }
void transformPoint(IToolLoop* loop, int x, int y)
{
int spray_width = loop->getSprayWidth();
int spray_speed = loop->getSpraySpeed();
int c, u, v, times = (spray_width*spray_width/4) * spray_speed / 100;
// In Windows, rand() has a RAND_MAX too small
#if RAND_MAX <= 0xffff
fixed angle, radius;
for (c=0; c<times; c++) {
angle = itofix(rand() * 256 / RAND_MAX);
radius = itofix(rand() * (spray_width*10) / RAND_MAX) / 10;
u = fixtoi(fixmul(radius, fixcos(angle)));
v = fixtoi(fixmul(radius, fixsin(angle)));
m_subPointShape.transformPoint(loop, x+u, y+v);
}
#else
fixed angle, radius;
for (c=0; c<times; c++) {
angle = rand();
radius = rand() % itofix(spray_width);
u = fixtoi(fixmul(radius, fixcos(angle)));
v = fixtoi(fixmul(radius, fixsin(angle)));
m_subPointShape.transformPoint(loop, x+u, y+v);
}
#endif
}
void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area)
{
int spray_width = loop->getSprayWidth();
Point p1(x-spray_width, y-spray_width);
Point p2(x+spray_width, y+spray_width);
Rect area1;
Rect area2;
m_subPointShape.getModifiedArea(loop, p1.x, p1.y, area1);
m_subPointShape.getModifiedArea(loop, p2.x, p2.y, area2);
area = area1.createUnion(area2);
}
};

303
src/tools/tool.cpp Normal file
View File

@ -0,0 +1,303 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "config.h"
#include "raster/algo.h"
#include "raster/image.h"
#include "tools/tool.h"
#include "util/render.h"
#include "context.h"
//////////////////////////////////////////////////////////////////////
// ToolPointShape class
void ToolPointShape::doInkHline(int x1, int y, int x2, IToolLoop* loop)
{
register int w, size; // width or height
register int x;
// Tiled in Y axis
if (loop->getTiledMode() & TILED_Y_AXIS) {
size = loop->getDstImage()->h; // size = image height
if (y < 0)
y = size - (-(y+1) % size) - 1;
else
y = y % size;
}
else if (y < 0 || y >= loop->getDstImage()->h)
return;
// Tiled in X axis
if (loop->getTiledMode() & TILED_X_AXIS) {
if (x1 > x2)
return;
size = loop->getDstImage()->w; // size = image width
w = x2-x1+1;
if (w >= size)
loop->getInk()->inkHline(0, y, size-1, loop);
else {
x = x1;
if (x < 0)
x = size - (-(x+1) % size) - 1;
else
x = x % size;
if (x+w-1 <= size-1)
loop->getInk()->inkHline(x, y, x+w-1, loop);
else {
loop->getInk()->inkHline(x, y, size-1, loop);
loop->getInk()->inkHline(0, y, w-(size-x)-1, loop);
}
}
}
// Clipped in X axis
else {
if (x1 < 0)
x1 = 0;
if (x2 >= loop->getDstImage()->w)
x2 = loop->getDstImage()->w-1;
if (x2-x1+1 < 1)
return;
loop->getInk()->inkHline(x1, y, x2, loop);
}
}
//////////////////////////////////////////////////////////////////////
// ToolIntertwine class
void ToolIntertwine::doPointshapePoint(int x, int y, IToolLoop* loop)
{
loop->getPointShape()->transformPoint(loop, x, y);
}
void ToolIntertwine::doPointshapeHline(int x1, int y, int x2, IToolLoop* loop)
{
algo_line(x1, y, x2, y, loop, (AlgoPixel)doPointshapePoint);
}
void ToolIntertwine::doPointshapeLine(int x1, int y1, int x2, int y2, IToolLoop* loop)
{
algo_line(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
}
//////////////////////////////////////////////////////////////////////
// ToolLoopManager class
ToolLoopManager::ToolLoopManager(IToolLoop* toolLoop)
: m_toolLoop(toolLoop)
{
}
ToolLoopManager::~ToolLoopManager()
{
delete m_toolLoop;
}
void ToolLoopManager::prepareLoop(JMessage msg)
{
// Start with no points at all
m_points.clear();
// Prepare the image where we will draw on
image_copy(m_toolLoop->getDstImage(),
m_toolLoop->getSrcImage(), 0, 0);
// Prepare the ink
m_toolLoop->getInk()->prepareInk(m_toolLoop);
// Prepare preview image (the destination image will be our preview
// in the tool-loop time, so we can see what we are drawing)
RenderEngine::setPreviewImage(m_toolLoop->getLayer(),
m_toolLoop->getDstImage());
}
void ToolLoopManager::releaseLoop(JMessage msg)
{
// No more preview image
RenderEngine::setPreviewImage(NULL, NULL);
}
void ToolLoopManager::pressButton(JMessage msg)
{
// If the user pressed the other mouse button...
if ((m_toolLoop->getMouseButton() == 0 && msg->mouse.right) ||
(m_toolLoop->getMouseButton() == 1 && msg->mouse.left)) {
// Cancel the tool-loop (the destination image should be completelly discarded)
m_toolLoop->cancel();
return;
}
// Convert the screen point to a sprite point
Point spritePoint = m_toolLoop->screenToSprite(Point(msg->mouse.x, msg->mouse.y));
m_toolLoop->setSpeed(Point(0, 0));
m_oldPoint = spritePoint;
snapToGrid(true, spritePoint);
m_toolLoop->getController()->pressButton(m_points, spritePoint);
std::string statusText;
m_toolLoop->getController()->getStatusBarText(m_points, statusText);
m_toolLoop->updateStatusBar(statusText.c_str());
doLoopStep(false);
}
bool ToolLoopManager::releaseButton(JMessage msg)
{
Point spritePoint = m_toolLoop->screenToSprite(Point(msg->mouse.x, msg->mouse.y));
snapToGrid(true, spritePoint);
bool res = m_toolLoop->getController()->releaseButton(m_points, spritePoint);
if (!res && (m_toolLoop->getInk()->isSelection() || m_toolLoop->getFilled())) {
m_toolLoop->getInk()->setFinalStep(m_toolLoop, true);
doLoopStep(true);
m_toolLoop->getInk()->setFinalStep(m_toolLoop, false);
}
return res;
}
void ToolLoopManager::movement(JMessage msg)
{
// Convert the screen point to a sprite point
Point spritePoint = m_toolLoop->screenToSprite(Point(msg->mouse.x, msg->mouse.y));
// Calculate the speed (new sprite point - old sprite point)
m_toolLoop->setSpeed(spritePoint - m_oldPoint);
m_oldPoint = spritePoint;
snapToGrid(true, spritePoint);
m_toolLoop->getController()->movement(m_toolLoop, m_points, spritePoint);
std::string statusText;
m_toolLoop->getController()->getStatusBarText(m_points, statusText);
m_toolLoop->updateStatusBar(statusText.c_str());
doLoopStep(false);
}
void ToolLoopManager::doLoopStep(bool last_step)
{
static Rect old_dirty_area; // TODO Not thread safe
std::vector<Point> points_to_interwine;
if (!last_step)
m_toolLoop->getController()->getPointsToInterwine(m_points, points_to_interwine);
else
points_to_interwine = m_points;
Point offset(m_toolLoop->getOffset());
for (size_t i=0; i<points_to_interwine.size(); ++i)
points_to_interwine[i] += offset;
switch (m_toolLoop->getTracePolicy()) {
case TOOL_TRACE_POLICY_ACCUMULATE:
// do nothing
break;
case TOOL_TRACE_POLICY_LAST:
image_clear(m_toolLoop->getDstImage(), 0);
image_copy(m_toolLoop->getDstImage(), m_toolLoop->getSrcImage(), 0, 0);
break;
}
// Get the modified area in the sprite with this intertwined set of points
if (!last_step || !m_toolLoop->getFilled())
m_toolLoop->getIntertwine()->joinPoints(m_toolLoop, points_to_interwine);
else
m_toolLoop->getIntertwine()->fillPoints(m_toolLoop, points_to_interwine);
// Calculat the area to be updated in the screen/editor/sprite
Rect dirty_area;
calculateDirtyArea(m_toolLoop, points_to_interwine, dirty_area);
Rect new_dirty_area;
if (m_toolLoop->getTracePolicy() == TOOL_TRACE_POLICY_LAST) {
new_dirty_area = old_dirty_area.createUnion(dirty_area);
old_dirty_area = dirty_area;
}
else {
new_dirty_area = dirty_area;
}
if (!new_dirty_area.isEmpty())
m_toolLoop->updateArea(new_dirty_area);
}
// Applies the grid settings to the specified sprite point, if
// "flexible" is true this function will try to snap the point
// to one of the four corners of each grid-tile, if "flexible"
// is false, only the origin of each grid-tile will be used
// to snap the point
void ToolLoopManager::snapToGrid(bool flexible, Point& point)
{
if (!m_toolLoop->getController()->canSnapToGrid() ||
!m_toolLoop->getContext()->getSettings()->getSnapToGrid())
return;
Rect grid(m_toolLoop->getContext()->getSettings()->getGridBounds());
register int w = grid.w;
register int h = grid.h;
div_t d, dx, dy;
flexible = flexible ? 1: 0;
dx = div(grid.x, w);
dy = div(grid.y, h);
d = div(point.x-dx.rem, w);
point.x = dx.rem + d.quot*w + ((d.rem > w/2)? w-flexible: 0);
d = div(point.y-dy.rem, h);
point.y = dy.rem + d.quot*h + ((d.rem > h/2)? h-flexible: 0);
}
void ToolLoopManager::calculateDirtyArea(IToolLoop* loop, const std::vector<Point>& points, Rect& dirty_area)
{
Point minpt, maxpt;
calculateMinMax(points, minpt, maxpt);
// Expand the dirty-area with the pen width
Rect r1, r2;
loop->getPointShape()->getModifiedArea(loop, minpt.x, minpt.y, r1);
loop->getPointShape()->getModifiedArea(loop, maxpt.x, maxpt.y, r2);
dirty_area = r1.createUnion(r2);
}
void ToolLoopManager::calculateMinMax(const std::vector<Point>& points, Point& minpt, Point& maxpt)
{
assert(points.size() > 0);
minpt.x = points[0].x;
minpt.y = points[0].y;
maxpt.x = points[0].x;
maxpt.y = points[0].y;
for (size_t c=1; c<points.size(); ++c) {
minpt.x = MIN(minpt.x, points[c].x);
minpt.y = MIN(minpt.y, points[c].y);
maxpt.x = MAX(maxpt.x, points[c].x);
maxpt.y = MAX(maxpt.y, points[c].y);
}
}

378
src/tools/tool.h Normal file
View File

@ -0,0 +1,378 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 TOOLS_TOOL_H_INCLUDED
#define TOOLS_TOOL_H_INCLUDED
#include <string>
#include <list>
#include <vector>
#include "jinete/jmessage.h"
#include "jinete/jrect.h"
#include "jinete/jpoint.h"
#include "tiled_mode.h"
class Context;
class Sprite;
class Image;
class Layer;
class Mask;
class Tool;
class Pen;
class IToolLoop;
enum ToolFill
{
TOOL_FILL_NONE,
TOOL_FILL_ALWAYS,
TOOL_FILL_OPTIONAL,
};
enum ToolTracePolicy
{
TOOL_TRACE_POLICY_ACCUMULATE,
TOOL_TRACE_POLICY_LAST,
};
// Class used to paint directly in the destination image (loop->getDstImage())
//
// The main task of this class is to draw scanlines through its
// inkHline function member.
class ToolInk
{
// selection, paint, paint_fg, paint_bg, eraser,
// replace_fg_with_bg, replace_bg_with_fg, pick_fg, pick_bg, scroll,
// move, shade, blur, jumble
public:
virtual ~ToolInk() { }
// Returns true if this ink modifies the selection/mask
virtual bool isSelection() const { return false; }
// Returns true if this ink modifies the destination image
virtual bool isPaint() const { return false; }
// Returns true if this ink is an effect (is useful to know if a ink
// is a effect so the Editor can display the cursor bounds)
virtual bool isEffect() const { return false; }
// Returns true if this ink picks colors from the image
virtual bool isEyedropper() const { return false; }
// It is called when the tool-loop start (generally when the user
// presses a mouse button over a sprite editor)
virtual void prepareInk(IToolLoop* loop) { }
// It is used in the final stage of the tool-loop, it is called twice
// (first with state=true and then state=false)
virtual void setFinalStep(IToolLoop* loop, bool state) { }
// It is used to paint scanlines in the destination image.
// ToolPointShapes call this method when they convert a mouse-point
// to a shape (e.g. pen shape) with various scanlines.
virtual void inkHline(int x1, int y, int x2, IToolLoop* loop) = 0;
};
// This class controls user input.
class ToolController
{
// freehand, point_by_point, one_point, two_points, four_points
public:
virtual ~ToolController() { }
virtual bool canSnapToGrid() { return true; }
virtual void pressButton(std::vector<Point>& points, const Point& point) = 0;
virtual bool releaseButton(std::vector<Point>& points, const Point& point) = 0;
virtual void movement(IToolLoop* loop, std::vector<Point>& points, const Point& point) = 0;
virtual void getPointsToInterwine(const std::vector<Point>& input, std::vector<Point>& output) = 0;
virtual void getStatusBarText(const std::vector<Point>& points, std::string& text) = 0;
};
// Converts a point to a shape to be drawn
class ToolPointShape
{
// none, pixel, pen, floodfill, spray
public:
virtual ~ToolPointShape() { }
virtual bool isSpray() { return false; }
virtual void transformPoint(IToolLoop* loop, int x, int y) = 0;
virtual void getModifiedArea(IToolLoop* loop, int x, int y, Rect& area) = 0;
protected:
// Calls loop->getInk()->inkHline() function for each horizontal-scanline
// that should be drawn (applying the "tiled" mode loop->getTiledMode())
static void doInkHline(int x1, int y, int x2, IToolLoop* loop);
};
class ToolIntertwine
{
// none, as_lines, as_bezier, as_rectangles, as_ellipses
public:
virtual ~ToolIntertwine() { }
virtual bool snapByAngle() { return false; }
virtual void joinPoints(IToolLoop* loop, const std::vector<Point>& points) = 0;
virtual void fillPoints(IToolLoop* loop, const std::vector<Point>& points) = 0;
protected:
static void doPointshapePoint(int x, int y, IToolLoop* loop);
static void doPointshapeHline(int x1, int y, int x2, IToolLoop* loop);
static void doPointshapeLine(int x1, int y1, int x2, int y2, IToolLoop* loop);
};
// A group of tools.
class ToolGroup
{
std::string m_name;
std::string m_label;
public:
ToolGroup(const char* name,
const char* label) : m_name(name)
, m_label(label) { }
const std::string& getName() const { return m_name; }
const std::string& getLabel() const { return m_label; }
};
// A drawing tool
class Tool
{
ToolGroup* m_group;
std::string m_id;
std::string m_text;
std::string m_tips;
int m_default_pen_size;
struct {
ToolFill m_fill;
ToolInk* m_ink;
ToolController* m_controller;
ToolPointShape* m_point_shape;
ToolIntertwine* m_intertwine;
ToolTracePolicy m_trace_policy;
} m_button[2]; // Two buttons: [0] left and [1] right
public:
Tool(ToolGroup* group,
const std::string& id,
const std::string& text,
const std::string& tips,
int default_pen_size)
: m_group(group)
, m_id(id)
, m_text(text)
, m_tips(tips)
, m_default_pen_size(default_pen_size)
{ }
virtual ~Tool()
{ }
const ToolGroup* getGroup() const { return m_group; }
const std::string& getId() const { return m_id; }
const std::string& getText() const { return m_text; }
const std::string& getTips() const { return m_tips; }
int getDefaultPenSize() const { return m_default_pen_size; }
ToolFill getFill(int button) { return m_button[button].m_fill; }
ToolInk* getInk(int button) { return m_button[button].m_ink; }
ToolController* getController(int button) { return m_button[button].m_controller; }
ToolPointShape* getPointShape(int button) { return m_button[button].m_point_shape; }
ToolIntertwine* getIntertwine(int button) { return m_button[button].m_intertwine; }
ToolTracePolicy getTracePolicy(int button) { return m_button[button].m_trace_policy; }
void setFill(int button, ToolFill fill) { m_button[button].m_fill = fill; }
void setInk(int button, ToolInk* ink) { m_button[button].m_ink = ink; }
void setController(int button, ToolController* controller) { m_button[button].m_controller = controller; }
void setPointShape(int button, ToolPointShape* point_shape) { m_button[button].m_point_shape = point_shape; }
void setIntertwine(int button, ToolIntertwine* intertwine) { m_button[button].m_intertwine = intertwine; }
void setTracePolicy(int button, ToolTracePolicy trace_policy) { m_button[button].m_trace_policy = trace_policy; }
};
// Interface to communicate the sprite editor with the tool when the user
// start using a tool to paint, select, pick color, etc.
//
// All this information should be provided by the editor and consumed
// by the tool (+controller+intertwiner+pointshape+ink).
class IToolLoop
{
public:
virtual ~IToolLoop() { }
// Returns the context where we want to draw on (generally UIContext::instance() singleton)
virtual Context* getContext() = 0;
// Returns the tool to use to draw or use
virtual Tool* getTool() = 0;
// Returns the pen which will be used with the tool
virtual Pen* getPen() = 0;
// Returns the sprite where we will draw on
virtual Sprite* getSprite() = 0;
// Returns the layer that will be modified if the tool paints
virtual Layer* getLayer() = 0;
// Should return an image where we can read pixels (readonly image)
virtual Image* getSrcImage() = 0;
// Should return an image where we can write pixels
virtual Image* getDstImage() = 0;
// Current mask to limit paint area
virtual Mask* getMask() = 0;
// Gets mask X,Y origin coordinates
virtual Point getMaskOrigin() = 0;
// Return the mouse button which start the tool-loop (0 = left
// button, 1 = right button). It can be used by some tools that
// instead of using the primary/secondary color uses the pressed
// button for different behavior (like selection tools)
virtual int getMouseButton() = 0;
// Primary color to draw (e.g. foreground if the user start drawing
// with the left button, or background color if he used the right
// button)
virtual int getPrimaryColor() = 0;
virtual void setPrimaryColor(int color) = 0;
// Secondary color to draw (e.g. background if the user start drawing
// with the left button, or foreground color if he used the right
// button)
virtual int getSecondaryColor() = 0;
virtual void setSecondaryColor(int color) = 0;
// Returns the opacity to be used by the ink (ToolInk).
virtual int getOpacity() = 0;
// Returns true if each scanline generated by a ToolPointShape must
// be "tiled". See the method ToolPointShape::doInkHline to check
// how this member is used. When tiled mode is activated, each
// scanline can be divided in various sub-lines if they pass the
// image bounds. For each of these scanlines a ToolInk::inkHline
// is called
virtual TiledMode getTiledMode() = 0;
// Returns true if the figure must be filled when we release the
// mouse (e.g. a filled rectangle, etc.)
//
// To fill a shape, the ToolIntertwine::fillPoints function is used.
virtual bool getFilled() = 0;
// Spray configuration
virtual int getSprayWidth() = 0;
virtual int getSpraySpeed() = 0;
// Offset for each point
virtual Point getOffset() = 0;
// Velocity vector of the mouse
virtual void setSpeed(const Point& speed) = 0;
virtual Point getSpeed() = 0;
// Returns the ink to use with the tool. Each tool has an associated
// ink, but it could be modified for this specific loop, so
// generally you should return the same ink as the tool, but it can
// be different. The same for the other properties.
virtual ToolInk* getInk() = 0;
virtual ToolController* getController() = 0;
virtual ToolPointShape* getPointShape() = 0;
virtual ToolIntertwine* getIntertwine() = 0;
virtual ToolTracePolicy getTracePolicy() = 0;
// Used by the tool when the user cancels the operation pressing the
// other mouse button.
virtual void cancel() = 0;
// Returns true if the loop was canceled by the user
virtual bool isCanceled() = 0;
// Converts a coordinate in the screen to the sprite.
virtual Point screenToSprite(const Point& screenPoint) = 0;
// Redraws in the screen the specified are of sprite.
virtual void updateArea(const Rect& dirty_area) = 0;
virtual void updateStatusBar(const char* text) = 0;
};
// Class to manage the drawing tool (editor <-> tool interface).
//
// The flow is this:
// 1. The user press a mouse button in a Editor widget
// 2. The Editor creates an implementation of IToolLoop and use it
// with the ToolLoopManager constructor
// 3. The ToolLoopManager is used to call
// the following methods:
// - ToolLoopManager::prepareLoop
// - ToolLoopManager::pressButton
// 4. If the user moves the mouse, the method
// - ToolLoopManager::movement
// is called.
// 5. When the user release the mouse:
// - ToolLoopManager::releaseButton
// - ToolLoopManager::releaseLoop
class ToolLoopManager
{
IToolLoop* m_toolLoop;
std::vector<Point> m_points;
Point m_oldPoint;
public:
ToolLoopManager(IToolLoop* toolLoop);
virtual ~ToolLoopManager();
bool isCanceled() const { return m_toolLoop->isCanceled(); }
// Should be called when the user start a tool-trace (pressing the
// left or right button for first time in the editor).
void prepareLoop(JMessage msg);
// Called when the loop is over.
void releaseLoop(JMessage msg);
// Should be called each time the user presses a mouse button.
void pressButton(JMessage msg);
// Should be called each time the user releases a mouse button.
//
// Returns true if the tool-loop should continue, or false
// if the editor should release the mouse capture.
bool releaseButton(JMessage msg);
// Should be called each time the user moves the mouse inside the editor.
void movement(JMessage msg);
private:
void doLoopStep(bool last_step);
void snapToGrid(bool flexible, Point& point);
static void calculateDirtyArea(IToolLoop* loop, const std::vector<Point>& points, Rect& dirty_area);
static void calculateMinMax(const std::vector<Point>& points, Point& minpt, Point& maxpt);
};
#endif

253
src/tools/toolbox.cpp Normal file
View File

@ -0,0 +1,253 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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
*/
#include "config.h"
#include <allegro/file.h>
#include <allegro/fixed.h>
#include <allegro/fmaths.h>
#include "core/dirs.h"
#include "raster/algo.h"
#include "raster/image.h"
#include "raster/mask.h"
#include "raster/pen.h"
#include "raster/sprite.h"
#include "tools/toolbox.h"
#include "ase_exception.h"
#include "tinyxml.h"
#include "tools/inks.h"
#include "tools/controllers.h"
#include "tools/point_shapes.h"
#include "tools/intertwiners.h"
//////////////////////////////////////////////////////////////////////
ToolBox::ToolBox()
{
PRINTF("Toolbox module: installing\n");
m_inks["selection"] = new SelectionInk();
m_inks["paint"] = new PaintInk(PaintInk::Normal);
m_inks["paint_fg"] = new PaintInk(PaintInk::WithFg);
m_inks["paint_bg"] = new PaintInk(PaintInk::WithBg);
m_inks["eraser"] = new EraserInk(EraserInk::Eraser);
m_inks["replace_fg_with_bg"] = new EraserInk(EraserInk::ReplaceFgWithBg);
m_inks["replace_bg_with_fg"] = new EraserInk(EraserInk::ReplaceBgWithFg);
m_inks["pick_fg"] = new PickInk(PickInk::Fg);
m_inks["pick_bg"] = new PickInk(PickInk::Bg);
m_inks["scroll"] = new ScrollInk();
m_inks["move"] = new MoveInk();
m_inks["blur"] = new BlurInk();
m_inks["jumble"] = new JumbleInk();
m_controllers["freehand"] = new FreehandController();
m_controllers["point_by_point"] = new PointByPointController();
m_controllers["one_point"] = new OnePointController();
m_controllers["two_points"] = new TwoPointsController();
m_controllers["four_points"] = new FourPointsController();
m_pointshapers["none"] = new NonePointShape();
m_pointshapers["pixel"] = new PixelPointShape();
m_pointshapers["pen"] = new PenPointShape();
m_pointshapers["floodfill"] = new FloodFillPointShape();
m_pointshapers["spray"] = new SprayPointShape();
m_intertwiners["none"] = new IntertwineNone();
m_intertwiners["as_lines"] = new IntertwineAsLines();
m_intertwiners["as_rectangles"] = new IntertwineAsRectangles();
m_intertwiners["as_ellipses"] = new IntertwineAsEllipses();
m_intertwiners["as_bezier"] = new IntertwineAsBezier();
loadTools();
PRINTF("Toolbox module: installed\n");
}
struct deleter {
template<typename T>
void operator()(T* p) { delete p; }
template<typename A, typename B>
void operator()(std::pair<A,B>& p) { delete p.second; }
};
ToolBox::~ToolBox()
{
PRINTF("Toolbox module: uninstalling\n");
for_each(m_tools.begin(), m_tools.end(), deleter());
for_each(m_groups.begin(), m_groups.end(), deleter());
for_each(m_intertwiners.begin(), m_intertwiners.end(), deleter());
for_each(m_pointshapers.begin(), m_pointshapers.end(), deleter());
for_each(m_controllers.begin(), m_controllers.end(), deleter());
for_each(m_inks.begin(), m_inks.end(), deleter());
PRINTF("Toolbox module: uninstalled\n");
}
Tool* ToolBox::getToolById(const std::string& id)
{
for (ToolIterator it = begin(); it != end(); ++it) {
Tool* tool = *it;
if (tool->getId() == id)
return tool;
}
// PRINTF("Error get_tool_by_name() with '%s'\n", name.c_str());
// assert(false);
return NULL;
}
void ToolBox::loadTools()
{
PRINTF("Loading ASE tools\n");
DIRS* dirs = filename_in_datadir("gui.xml");
for (DIRS* dir=dirs; dir; dir=dir->next) {
PRINTF("Trying to load tools from \"%s\"...\n", dir->path);
if (!exists(dir->path))
continue;
PRINTF(" - \"%s\" found\n", dir->path);
TiXmlDocument doc;
if (!doc.LoadFile(dir->path))
throw ase_exception(&doc);
// For each group
TiXmlHandle handle(&doc);
TiXmlElement* xmlGroup = handle.FirstChild("gui").FirstChild("tools").FirstChild("group").ToElement();
while (xmlGroup) {
const char* group_id = xmlGroup->Attribute("id");
const char* group_text = xmlGroup->Attribute("text");
PRINTF(" - New group '%s'\n", group_id);
if (!group_id || !group_text)
throw ase_exception("The configuration file has a <group> without 'id' or 'text' attributes.");
ToolGroup* tool_group = new ToolGroup(group_id, group_text);
// For each tool
TiXmlNode* xmlToolNode = xmlGroup->FirstChild("tool");
TiXmlElement* xmlTool = xmlToolNode ? xmlToolNode->ToElement(): NULL;
while (xmlTool) {
const char* tool_id = xmlTool->Attribute("id");
const char* tool_text = xmlTool->Attribute("text");
const char* tool_tips = xmlTool->Attribute("tips");
const char* default_pen_size = xmlTool->Attribute("default_pen_size");
Tool* tool = new Tool(tool_group, tool_id, tool_text,
tool_tips ? tool_tips: "",
default_pen_size ? strtol(default_pen_size, NULL, 10): 1);
PRINTF(" - New tool '%s' in group '%s' found\n", tool_id, group_id);
loadToolProperties(xmlTool, tool, 0, "left");
loadToolProperties(xmlTool, tool, 1, "right");
m_tools.push_back(tool);
xmlTool = xmlTool->NextSiblingElement();
}
m_groups.push_back(tool_group);
xmlGroup = xmlGroup->NextSiblingElement();
}
}
dirs_free(dirs);
}
void ToolBox::loadToolProperties(TiXmlElement* xmlTool, Tool* tool, int button, const std::string& suffix)
{
const char* tool_id = tool->getId().c_str();
const char* fill = xmlTool->Attribute(("fill_"+suffix).c_str());
const char* ink = xmlTool->Attribute(("ink_"+suffix).c_str());
const char* controller = xmlTool->Attribute(("controller_"+suffix).c_str());
const char* pointshape = xmlTool->Attribute(("pointshape_"+suffix).c_str());
const char* intertwine = xmlTool->Attribute(("intertwine_"+suffix).c_str());
const char* tracepolicy = xmlTool->Attribute(("tracepolicy_"+suffix).c_str());
if (!fill) fill = xmlTool->Attribute("fill");
if (!ink) ink = xmlTool->Attribute("ink");
if (!controller) controller = xmlTool->Attribute("controller");
if (!pointshape) pointshape = xmlTool->Attribute("pointshape");
if (!intertwine) intertwine = xmlTool->Attribute("intertwine");
if (!tracepolicy) tracepolicy = xmlTool->Attribute("tracepolicy");
// Fill
ToolFill fill_value = TOOL_FILL_NONE;
if (fill) {
if (strcmp(fill, "none") == 0)
fill_value = TOOL_FILL_NONE;
else if (strcmp(fill, "always") == 0)
fill_value = TOOL_FILL_ALWAYS;
else if (strcmp(fill, "optional") == 0)
fill_value = TOOL_FILL_OPTIONAL;
else
throw ase_exception("Invalid fill '%s' specified in '%s' tool.\n", fill, tool_id);
}
// Find the ink
std::map<std::string, ToolInk*>::iterator it_ink
= m_inks.find(ink ? ink: "");
if (it_ink == m_inks.end())
throw ase_exception("Invalid ink '%s' specified in '%s' tool.\n", ink, tool_id);
// Find the controller
std::map<std::string, ToolController*>::iterator it_controller
= m_controllers.find(controller ? controller: "none");
if (it_controller == m_controllers.end())
throw ase_exception("Invalid controller '%s' specified in '%s' tool.\n", controller, tool_id);
// Find the point_shape
std::map<std::string, ToolPointShape*>::iterator it_pointshaper
= m_pointshapers.find(pointshape ? pointshape: "none");
if (it_pointshaper == m_pointshapers.end())
throw ase_exception("Invalid point-shape '%s' specified in '%s' tool.\n", pointshape, tool_id);
// Find the intertwiner
std::map<std::string, ToolIntertwine*>::iterator it_intertwiner
= m_intertwiners.find(intertwine ? intertwine: "none");
if (it_intertwiner == m_intertwiners.end())
throw ase_exception("Invalid intertwiner '%s' specified in '%s' tool.\n", intertwine, tool_id);
// Trace policy
ToolTracePolicy tracepolicy_value = TOOL_TRACE_POLICY_LAST;
if (tracepolicy) {
if (strcmp(tracepolicy, "accumulative") == 0)
tracepolicy_value = TOOL_TRACE_POLICY_ACCUMULATE;
else if (strcmp(tracepolicy, "last") == 0)
tracepolicy_value = TOOL_TRACE_POLICY_LAST;
else
throw ase_exception("Invalid trace-policy '%s' specified in '%s' tool.\n", tracepolicy, tool_id);
}
// Setup the tool properties
tool->setFill(button, fill_value);
tool->setInk(button, it_ink->second);
tool->setController(button, it_controller->second);
tool->setPointShape(button, it_pointshaper->second);
tool->setIntertwine(button, it_intertwiner->second);
tool->setTracePolicy(button, tracepolicy_value);
}

68
src/tools/toolbox.h Normal file
View File

@ -0,0 +1,68 @@
/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2009 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 TOOLS_TOOLBOX_H_INCLUDED
#define TOOLS_TOOLBOX_H_INCLUDED
#include <string>
#include <list>
#include <map>
#include "tools/tool.h"
class TiXmlElement;
typedef std::list<Tool*> ToolList;
typedef ToolList::iterator ToolIterator;
typedef ToolList::const_iterator ToolConstIterator;
typedef std::list<ToolGroup*> ToolGroupList;
// Loads and maintains the group of tools specified in the gui.xml file
class ToolBox
{
std::map<std::string, ToolInk*> m_inks;
std::map<std::string, ToolController*> m_controllers;
std::map<std::string, ToolPointShape*> m_pointshapers;
std::map<std::string, ToolIntertwine*> m_intertwiners;
ToolGroupList m_groups;
ToolList m_tools;
public:
ToolBox();
~ToolBox();
ToolGroupList::iterator begin_group() { return m_groups.begin(); }
ToolGroupList::iterator end_group() { return m_groups.end(); }
ToolIterator begin() { return m_tools.begin(); }
ToolIterator end() { return m_tools.end(); }
ToolConstIterator begin() const { return m_tools.begin(); }
ToolConstIterator end() const { return m_tools.end(); }
Tool* getToolById(const std::string& id);
int getGroupsCount() const { return m_groups.size(); }
private:
void loadTools();
void loadToolProperties(TiXmlElement* xmlTool, Tool* tool, int button, const std::string& suffix);
};
#endif

View File

@ -18,18 +18,20 @@
#include "config.h"
#include <cassert>
#include <allegro/file.h>
#include <cassert>
#include "ui_context.h"
#include "app.h"
#include "modules/editors.h"
#include "raster/sprite.h"
#include "settings/ui_settings_impl.h"
#include "ui_context.h"
#include "widgets/tabs.h"
UIContext* UIContext::m_instance = NULL;
UIContext::UIContext()
: Context(new UISettingsImpl)
{
assert(m_instance == NULL);
m_instance = this;
@ -41,16 +43,6 @@ UIContext::~UIContext()
m_instance = NULL;
}
int UIContext::get_fg_color()
{
return app_get_fg_color(get_current_sprite());
}
int UIContext::get_bg_color()
{
return app_get_bg_color(get_current_sprite());
}
void UIContext::on_add_sprite(Sprite* sprite)
{
// base method

View File

@ -33,9 +33,6 @@ public:
virtual bool is_ui_available() const { return true; }
virtual int get_fg_color();
virtual int get_bg_color();
protected:
virtual void on_add_sprite(Sprite* sprite);

View File

@ -18,13 +18,12 @@
#include "config.h"
#include <cassert>
#include <allegro.h>
#include <allegro/internal/aintern.h>
#include <cassert>
#include "jinete/jinete.h"
#include "sprite_wrappers.h"
#include "console.h"
#include "app.h"
#include "core/core.h"
@ -32,7 +31,6 @@
#include "modules/gfx.h"
#include "modules/gui.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/cel.h"
#include "raster/image.h"
#include "raster/layer.h"
@ -42,6 +40,9 @@
#include "raster/sprite.h"
#include "raster/stock.h"
#include "raster/undo.h"
#include "settings/settings.h"
#include "sprite_wrappers.h"
#include "ui_context.h"
#include "undoable.h"
#include "util/clipboard.h"
#include "util/misc.h"
@ -635,13 +636,13 @@ static bool interactive_transform(Editor* editor,
editor->screen_to_editor(x1, y1, &x1, &y1);
editor->screen_to_editor(x2, y2, &x2, &y2);
if (get_use_grid() && angle == 0) {
int ox = x1;
int oy = y1;
apply_grid(&x1, &y1, false);
x2 += x1 - ox;
y2 += y1 - oy;
}
// if (UIContext::instance()->getSettings()->get_snap_to_grid() && angle == 0) {
// int ox = x1;
// int oy = y1;
// apply_grid(&x1, &y1, false);
// x2 += x1 - ox;
// y2 += y1 - oy;
// }
editor->editor_to_screen(x1, y1, &x1, &y1);
editor->editor_to_screen(x2, y2, &x2, &y2);

View File

@ -26,10 +26,11 @@
#include "jinete/jlist.h"
#include "modules/palettes.h"
#include "modules/tools.h"
#include "raster/image.h"
#include "raster/raster.h"
#include "util/render.h"
#include "settings/settings.h"
#include "ui_context.h"
//////////////////////////////////////////////////////////////////////
// zoomed merge
@ -362,9 +363,9 @@ Image* RenderEngine::renderSprite(Sprite* sprite,
color_map = NULL;
/* onion-skin feature: draw the previous frame */
if (get_onionskin() && (frame > 0)) {
/* draw background layer of the current frame with opacity=255 */
// Onion-skin feature: draw the previous frame
if (UIContext::instance()->getSettings()->getUseOnionskin() && (frame > 0)) {
// Draw background layer of the current frame with opacity=255
color_map = NULL;
global_opacity = 255;

View File

@ -23,18 +23,53 @@
#include "jinete/jwidget.h"
#include "core/color.h"
#include "Vaca/Signal.h"
#define MIN_ZOOM 0
#define MAX_ZOOM 5
class Context;
class Sprite;
class IToolLoop;
class ToolLoopManager;
class Tool;
class Editor : public Widget
{
// Editor's decorators. These are useful to add some extra-graphics
// visualizators in the editor to show feedback and get user events (click)
class Decorator
{
public:
enum Type {
SELECTION_NW,
SELECTION_N,
SELECTION_NE,
SELECTION_E,
SELECTION_SE,
SELECTION_S,
SELECTION_SW,
SELECTION_W,
};
private:
Type m_type;
Rect m_bounds;
public:
Decorator(Type type, const Rect& bounds);
~Decorator();
void drawDecorator(Editor*editor, BITMAP* bmp);
bool isInsideDecorator(int x, int y);
Vaca::Signal0<void> Click;
};
// editor states
enum {
EDIT_STANDBY,
EDIT_MOVING_SCROLL,
EDIT_DRAWING,
EDITOR_STATE_STANDBY,
EDITOR_STATE_MOVING_SCROLL,
EDITOR_STATE_DRAWING,
};
/* main stuff */
@ -51,6 +86,9 @@ class Editor : public Widget
int m_old_cursor_thick;
bool m_cursor_candraw : 1;
// True if the cursor is inside the mask/selection
bool m_insideSelection : 1;
bool m_alt_pressed : 1;
bool m_ctrl_pressed : 1;
bool m_space_pressed : 1;
@ -66,6 +104,12 @@ class Editor : public Widget
/* region that must be updated */
JRegion m_refresh_region;
// Tool-loop manager
ToolLoopManager* m_toolLoopManager;
// Decorators
std::vector<Decorator*> m_decorators;
public:
// in editor.c
@ -104,8 +148,16 @@ public:
// in cursor.c
static int get_raw_cursor_color();
static bool is_cursor_mask();
static color_t get_cursor_color();
static void set_cursor_color(color_t color);
static void editor_cursor_init();
static void editor_cursor_exit();
private:
void editor_draw_cursor(int x, int y);
void editor_clean_cursor();
bool editor_cursor_is_subpixel();
@ -113,7 +165,9 @@ public:
// keys.c
bool editor_keys_toset_zoom(int scancode);
bool editor_keys_toset_brushsize(int scancode);
bool editor_keys_toset_pensize(int scancode);
public:
// click.c
@ -134,12 +188,15 @@ protected:
private:
void drawGrid();
void turnOnSelectionModifiers();
void editor_request_size(int *w, int *h);
void editor_setcursor(int x, int y);
void editor_update_candraw();
IToolLoop* createToolLoopImpl(Context* context, JMessage msg);
void for_each_pixel_of_brush(int x, int y, int color,
void (*pixel)(BITMAP *bmp, int x, int y, int color));
void for_each_pixel_of_pen(int x, int y, int color,
void (*pixel)(BITMAP *bmp, int x, int y, int color));
};
JWidget editor_view_new();

View File

@ -28,9 +28,15 @@
#include "jinete/jsystem.h"
#include "jinete/jwidget.h"
#include "app.h"
#include "core/cfg.h"
#include "core/color.h"
#include "modules/tools.h"
#include "raster/brush.h"
#include "modules/editors.h"
#include "raster/image.h"
#include "raster/pen.h"
#include "raster/sprite.h"
#include "tools/tool.h"
#include "ui_context.h"
#include "util/boundary.h"
#include "widgets/editor.h"
@ -49,17 +55,20 @@
#define MAX_SAVED 4096
static struct {
int brush_type;
int brush_size;
int brush_angle;
int pen_type;
int pen_size;
int pen_angle;
int nseg;
BoundSeg *seg;
} cursor_bound = { 0, 0, 0, 0, NULL };
enum { CURSOR_CROSS_ONE = 1,
CURSOR_BRUSH = 2 };
enum {
CURSOR_PENCIL = 1, // New cursor style (with preview)
CURSOR_CROSS_ONE = 2, // Old cursor style (deprecated)
CURSOR_BOUNDS = 4 // Old cursor boundaries (deprecated)
};
static int cursor_type;
static int cursor_type = CURSOR_PENCIL;
static int cursor_negative;
static int saved_pixel[MAX_SAVED];
@ -72,8 +81,9 @@ static JRegion old_clipping_region;
static void generate_cursor_boundaries();
static void editor_cursor_pencil(Editor *editor, int x, int y, int color, int thickness, void (*pixel)(BITMAP *bmp, int x, int y, int color));
static void editor_cursor_cross(Editor *editor, int x, int y, int color, int thickness, void (*pixel)(BITMAP *bmp, int x, int y, int color));
static void editor_cursor_brush(Editor *editor, int x, int y, int color, void (*pixel)(BITMAP *bmp, int x, int y, int color));
static void editor_cursor_bounds(Editor *editor, int x, int y, int color, void (*pixel)(BITMAP *bmp, int x, int y, int color));
static void savepixel(BITMAP *bmp, int x, int y, int color);
static void drawpixel(BITMAP *bmp, int x, int y, int color);
@ -81,18 +91,98 @@ static void cleanpixel(BITMAP *bmp, int x, int y, int color);
static int point_inside_region(int x, int y, JRegion region);
/***********************************************************/
/* CURSOR */
/***********************************************************/
//////////////////////////////////////////////////////////////////////
// CURSOR COLOR
//////////////////////////////////////////////////////////////////////
static color_t cursor_color;
static int _cursor_color;
static bool _cursor_mask;
static void update_cursor_color()
{
if (ji_screen)
_cursor_color = get_color_for_allegro(bitmap_color_depth(ji_screen),
cursor_color);
else
_cursor_color = 0;
_cursor_mask = (color_type(cursor_color) == COLOR_TYPE_MASK);
}
int Editor::get_raw_cursor_color()
{
return _cursor_color;
}
bool Editor::is_cursor_mask()
{
return _cursor_mask;
}
color_t Editor::get_cursor_color()
{
return cursor_color;
}
void Editor::set_cursor_color(color_t color)
{
cursor_color = color;
update_cursor_color();
}
//////////////////////////////////////////////////////////////////////
// Slots for App signals
//////////////////////////////////////////////////////////////////////
static void on_palette_change_update_cursor_color()
{
update_cursor_color();
}
static int pen_size_thick = 0;
static void on_pen_size_before_change()
{
assert(current_editor != NULL);
pen_size_thick = current_editor->editor_get_cursor_thick();
if (pen_size_thick)
current_editor->hide_drawing_cursor();
}
static void on_pen_size_after_change()
{
assert(current_editor != NULL);
if (current_editor->getSprite() && pen_size_thick > 0)
current_editor->show_drawing_cursor();
}
//////////////////////////////////////////////////////////////////////
// CURSOR
//////////////////////////////////////////////////////////////////////
void Editor::editor_cursor_init()
{
/* cursor color */
set_cursor_color(get_config_color("Tools", "CursorColor", color_mask()));
App::instance()->PaletteChange.connect(&on_palette_change_update_cursor_color);
App::instance()->PenSizeBeforeChange.connect(&on_pen_size_before_change);
App::instance()->PenSizeAfterChange.connect(&on_pen_size_after_change);
}
void Editor::editor_cursor_exit()
{
set_config_color("Tools", "CursorColor", cursor_color);
if (cursor_bound.seg != NULL)
jfree(cursor_bound.seg);
}
/**
* Draws the brush cursor inside the specified editor.
* Draws the pen cursor inside the specified editor.
*
* @warning You should clean the cursor before to use
* this routine with other editor.
@ -119,41 +209,70 @@ void Editor::editor_draw_cursor(int x, int y)
/* cursor in the screen (view) */
m_cursor_screen_x = x;
m_cursor_screen_y = y;
/* get cursor position in the editor */
screen_to_editor(x, y, &x, &y);
/* get cursor type */
if (get_thickness_for_cursor() == 1) {
// Get the current tool
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
// Setup the cursor type depending the current tool
if (current_tool->getInk(0)->isSelection()) {
cursor_type = CURSOR_CROSS_ONE;
}
else {
switch (get_brush_type()) {
case BRUSH_CIRCLE:
case BRUSH_SQUARE:
cursor_type = CURSOR_BRUSH;
if ((get_brush_size()<<m_zoom)/2 > 3+(1<<m_zoom))
cursor_type |= CURSOR_CROSS_ONE;
break;
case BRUSH_LINE:
cursor_type = CURSOR_BRUSH;
break;
}
else if (current_tool->getInk(0)->isEffect()) {
cursor_type = CURSOR_BOUNDS;
}
else
cursor_type = CURSOR_PENCIL;
if (cursor_type & CURSOR_BRUSH)
// For cursor type 'bounds' we have to generate cursor boundaries
if (cursor_type & CURSOR_BOUNDS)
generate_cursor_boundaries();
// draw pixel/pen preview
if (cursor_type & CURSOR_PENCIL &&
m_state != EDITOR_STATE_DRAWING) {
int color = app_get_fg_color(m_sprite);
IToolSettings* tool_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool);
IPenSettings* pen_settings =
tool_settings->getPen();
assert(pen_settings != NULL);
Pen* pen = new Pen(pen_settings->getType(),
pen_settings->getSize(),
pen_settings->getAngle());
m_sprite->set_extras_opacity(tool_settings->getOpacity());
m_sprite->prepare_extra();
image_putpen(m_sprite->get_extras(), pen, x, y, color);
editors_draw_sprite(m_sprite,
x-pen->get_size()/2,
y-pen->get_size()/2,
x+pen->get_size()/2,
y+pen->get_size()/2);
delete pen;
}
/* save area and draw the cursor */
acquire_bitmap(ji_screen);
ji_screen->clip = false;
for_each_pixel_of_brush(x, y, color, savepixel);
for_each_pixel_of_brush(x, y, color, drawpixel);
for_each_pixel_of_pen(x, y, color, savepixel);
for_each_pixel_of_pen(x, y, color, drawpixel);
ji_screen->clip = true;
release_bitmap(ji_screen);
/* cursor thickness */
m_cursor_thick = get_thickness_for_cursor();
// cursor thickness
m_cursor_thick = 1; // get_thickness_for_cursor();
/* cursor in the editor (model) */
m_cursor_editor_x = x;
@ -166,7 +285,7 @@ void Editor::editor_draw_cursor(int x, int y)
}
/**
* Cleans the brush cursor from the specified editor.
* Cleans the pen cursor from the specified editor.
*
* The mouse position is got from the last
* call to @c editor_draw_cursor. So you must
@ -191,11 +310,40 @@ void Editor::editor_clean_cursor()
/* restore points */
acquire_bitmap(ji_screen);
ji_screen->clip = false;
for_each_pixel_of_brush(x, y, 0, cleanpixel);
ji_screen->clip = true;
ji_screen->clip = FALSE;
for_each_pixel_of_pen(x, y, 0, cleanpixel);
ji_screen->clip = TRUE;
release_bitmap(ji_screen);
// clean pixel/pen preview
if (cursor_type & CURSOR_PENCIL &&
m_state != EDITOR_STATE_DRAWING) {
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
IPenSettings* pen_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen();
assert(pen_settings != NULL);
Pen* pen = new Pen(pen_settings->getType(),
pen_settings->getSize(),
pen_settings->getAngle());
m_sprite->prepare_extra();
image_putpen(m_sprite->get_extras(), pen, x, y, 0);
editors_draw_sprite(m_sprite,
x-pen->get_size()/2,
y-pen->get_size()/2,
x+pen->get_size()/2,
y+pen->get_size()/2);
delete pen;
}
m_cursor_thick = 0;
jregion_free(clipping_region);
@ -220,34 +368,63 @@ bool Editor::editor_cursor_is_subpixel()
static void generate_cursor_boundaries()
{
Tool* current_tool = UIContext::instance()
->getSettings()
->getCurrentTool();
IPenSettings* pen_settings = UIContext::instance()
->getSettings()
->getToolSettings(current_tool)
->getPen();
if (cursor_bound.seg == NULL ||
cursor_bound.brush_type != get_brush_type() ||
cursor_bound.brush_size != get_brush_size() ||
cursor_bound.brush_angle != get_brush_angle()) {
cursor_bound.brush_type = get_brush_type();
cursor_bound.brush_size = get_brush_size();
cursor_bound.brush_angle = get_brush_angle();
cursor_bound.pen_type != pen_settings->getType() ||
cursor_bound.pen_size != pen_settings->getSize() ||
cursor_bound.pen_angle != pen_settings->getAngle()) {
cursor_bound.pen_type = pen_settings->getType();
cursor_bound.pen_size = pen_settings->getSize();
cursor_bound.pen_angle = pen_settings->getAngle();
if (cursor_bound.seg != NULL)
jfree(cursor_bound.seg);
cursor_bound.seg = find_mask_boundary(get_brush()->image,
&cursor_bound.nseg,
IgnoreBounds, 0, 0, 0, 0);
Pen* pen;
UIContext* context = UIContext::instance();
Tool* current_tool = context->getSettings()->getCurrentTool();
if (current_tool) {
IPenSettings* pen_settings = context->getSettings()
->getToolSettings(current_tool)->getPen();
assert(pen_settings != NULL);
pen = new Pen(pen_settings->getType(),
pen_settings->getSize(),
pen_settings->getAngle());
}
else
pen = new Pen();
cursor_bound.seg = find_mask_boundary(pen->get_image(),
&cursor_bound.nseg,
IgnoreBounds, 0, 0, 0, 0);
delete pen;
}
}
void Editor::for_each_pixel_of_brush(int x, int y, int color,
void (*pixel)(BITMAP *bmp, int x, int y, int color))
void Editor::for_each_pixel_of_pen(int x, int y, int color,
void (*pixel)(BITMAP *bmp, int x, int y, int color))
{
saved_pixel_n = 0;
if (cursor_type & CURSOR_PENCIL) {
editor_cursor_pencil(this, m_cursor_screen_x, m_cursor_screen_y, color, 1, pixel);
}
if (cursor_type & CURSOR_CROSS_ONE) {
editor_cursor_cross(this, x, y, color, 1, pixel);
}
if (cursor_type & CURSOR_BRUSH) {
editor_cursor_brush(this, x, y, color, pixel);
if (cursor_type & CURSOR_BOUNDS) {
editor_cursor_bounds(this, x, y, color, pixel);
}
if (IS_SUBPIXEL(this)) {
@ -257,10 +434,38 @@ void Editor::for_each_pixel_of_brush(int x, int y, int color,
}
}
/**********************************************************************/
/* cross */
//////////////////////////////////////////////////////////////////////
// New cross
static void editor_cursor_cross(Editor *editor, int x, int y, int color, int thickness, void (*pixel) (BITMAP *bmp, int x, int y, int color))
static void editor_cursor_pencil(Editor *editor, int x, int y, int color, int thickness, void (*pixel)(BITMAP *bmp, int x, int y, int color))
{
static int cursor_cross[7*7] = {
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0,
};
int u, v, xout, yout;
for (v=0; v<7; v++) {
for (u=0; u<7; u++) {
if (cursor_cross[v*7+u]) {
xout = x-3+u;
yout = y-3+v;
(*pixel)(ji_screen, xout, yout, color);
}
}
}
}
//////////////////////////////////////////////////////////////////////
// Old cross
static void editor_cursor_cross(Editor* editor, int x, int y, int color, int thickness,
void (*pixel)(BITMAP *bmp, int x, int y, int color))
{
static int cursor_cross[6*6] = {
0, 0, 1, 1, 0, 0,
@ -292,10 +497,10 @@ static void editor_cursor_cross(Editor *editor, int x, int y, int color, int thi
}
}
/**********************************************************************/
/* brush */
//////////////////////////////////////////////////////////////////////
// Cursor Bounds
static void editor_cursor_brush(Editor *editor, int x, int y, int color, void (*pixel) (BITMAP *bmp, int x, int y, int color))
static void editor_cursor_bounds(Editor *editor, int x, int y, int color, void (*pixel) (BITMAP *bmp, int x, int y, int color))
{
int c, x1, y1, x2, y2;
BoundSeg *seg;
@ -303,10 +508,10 @@ static void editor_cursor_brush(Editor *editor, int x, int y, int color, void (*
for (c=0; c<cursor_bound.nseg; c++) {
seg = cursor_bound.seg+c;
x1 = seg->x1 - cursor_bound.brush_size/2;
y1 = seg->y1 - cursor_bound.brush_size/2;
x2 = seg->x2 - cursor_bound.brush_size/2;
y2 = seg->y2 - cursor_bound.brush_size/2;
x1 = seg->x1 - cursor_bound.pen_size/2;
y1 = seg->y1 - cursor_bound.pen_size/2;
x2 = seg->x2 - cursor_bound.pen_size/2;
y2 = seg->y2 - cursor_bound.pen_size/2;
editor->editor_to_screen(x+x1, y+y1, &x1, &y1);
editor->editor_to_screen(x+x2, y+y2, &x2, &y2);

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include <allegro/keyboard.h>
#include "jinete/jrect.h"
#include "jinete/jsystem.h"
#include "jinete/jview.h"
#include "jinete/jwidget.h"
@ -28,9 +29,10 @@
#include "core/color.h"
#include "modules/editors.h"
#include "modules/gui.h"
#include "modules/tools.h"
#include "raster/image.h"
#include "raster/sprite.h"
#include "settings/settings.h"
#include "ui_context.h"
#include "widgets/colbar.h"
#include "widgets/editor.h"
@ -88,21 +90,25 @@ bool Editor::editor_keys_toset_zoom(int scancode)
return false;
}
bool Editor::editor_keys_toset_brushsize(int scancode)
bool Editor::editor_keys_toset_pensize(int scancode)
{
Tool* current_tool = UIContext::instance()->getSettings()->getCurrentTool();
IToolSettings* tool_settings = UIContext::instance()->getSettings()->getToolSettings(current_tool);
IPenSettings* pen = tool_settings->getPen();
if ((m_sprite) &&
(jwidget_has_mouse(this)) &&
!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG))) {
/* TODO configurable keys */
/* set the thickness */
if (scancode == KEY_MINUS_PAD) {
if (get_brush_size () > 1)
set_brush_size (get_brush_size ()-1);
if (scancode == KEY_MINUS_PAD) { // TODO configurable keys
if (pen->getSize() > 1) {
pen->setSize(pen->getSize()-1);
}
return true;
}
else if (scancode == KEY_PLUS_PAD) {
if (get_brush_size () < 32)
set_brush_size (get_brush_size ()+1);
if (pen->getSize() < 32) {
pen->setSize(pen->getSize()+1);
}
return true;
}
}

View File

@ -23,8 +23,10 @@
#include <stdio.h>
#include <string.h>
#include "Vaca/Bind.h"
#include "jinete/jinete.h"
#include "app.h"
#include "commands/commands.h"
#include "core/core.h"
#include "modules/editors.h"
@ -35,11 +37,12 @@
#include "raster/layer.h"
#include "raster/sprite.h"
#include "raster/undo.h"
#include "sprite_wrappers.h"
#include "tools/tool.h"
#include "ui_context.h"
#include "util/misc.h"
#include "widgets/editor.h"
#include "widgets/statebar.h"
#include "sprite_wrappers.h"
#include "ui_context.h"
enum {
ACTION_LAYER,
@ -58,6 +61,16 @@ static void button_command(JWidget widget, void *data);
static void update_from_layer(StatusBar *statusbar);
static void on_current_tool_change(JWidget widget)
{
if (jwidget_is_visible(widget)) {
Tool* currentTool = UIContext::instance()->getSettings()->getCurrentTool();
if (currentTool)
statusbar_set_text(widget, 500, "%s selected",
currentTool->getText().c_str());
}
}
JWidget statusbar_new()
{
#define BUTTON_NEW(name, text, data) \
@ -112,6 +125,8 @@ JWidget statusbar_new()
jwidget_add_child(box1, box2);
statusbar->commands_box = box1;
App::instance()->CurrentToolChange.connect(Vaca::Bind<void>(&on_current_tool_change, widget));
}
return widget;

View File

@ -18,117 +18,481 @@
#include "config.h"
#include <allegro/unicode.h>
#include <map>
#include <string>
#include <allegro.h>
#include "jinete/jaccel.h"
#include "jinete/jbox.h"
#include "jinete/jbutton.h"
#include "jinete/jhook.h"
#include "jinete/jtooltips.h"
#include "jinete/jwidget.h"
#include "jinete/jinete.h"
#include "Vaca/Bind.h"
#include "Vaca/Signal.h"
#include "app.h"
#include "ui_context.h"
#include "commands/commands.h"
#include "commands/command.h"
#include "modules/gfx.h"
#include "modules/gui.h"
#include "modules/skinneable_theme.h"
#include "modules/tools.h"
#include "tools/toolbox.h"
#include "widgets/groupbut.h"
#include "widgets/toolbar.h"
static bool tools_change_hook(JWidget widget, void *data);
static void conf_command(JWidget widget);
// Class to show selected tools for each tool (vertically)
class ToolBar : public Widget
{
// What tool is selected for each tool-group
std::map<const ToolGroup*, Tool*> m_selected_in_group;
// What tool has the mouse above
Tool* m_hot_tool;
// Does the configuration button have the mouse above?
bool m_hot_conf;
// True if the popup-window must be opened when a tool-button is hot
bool m_open_on_hot;
// Window displayed to show a tool-group
PopupWindow* m_popup_window;
public:
ToolBar();
~ToolBar();
bool isToolVisible(Tool* tool);
void selectTool(Tool* tool);
protected:
bool msg_proc(JMessage msg);
private:
void onToolSelected(Tool* tool);
void onClosePopup();
void openPopupWindow(int group_index, ToolGroup* group);
Rect getToolGroupBounds(int group_index);
};
// Class to show a group of tools (horizontally)
// This widget is inside the ToolBar::m_popup_window
class ToolStrip : public Widget
{
ToolGroup* m_group;
Tool* m_hot_tool;
public:
ToolStrip(ToolGroup* group);
~ToolStrip();
Vaca::Signal1<void, Tool*> ToolSelected;
protected:
bool msg_proc(JMessage msg);
private:
Rect getToolBounds(int index);
};
static Size getToolIconSize(Widget* widget)
{
SkinneableTheme* theme = static_cast<SkinneableTheme*>(widget->theme);
BITMAP* icon = theme->get_toolicon("configuration");
if (icon)
return Size(icon->w, icon->h);
else
return Size(16, 16) * guiscale();
}
//////////////////////////////////////////////////////////////////////
// ToolBar
JWidget toolbar_new()
{
JWidget box, confbutton, tools;
char buf[1024]; /* TODO warning buffer overflow */
int c;
return new ToolBar();
}
for (c=0; c<MAX_TOOLS; c++)
if (current_tool == tools_list[c])
break;
bool toolbar_is_tool_visible(JWidget toolbar, Tool* tool)
{
return ((ToolBar*)toolbar)->isToolVisible(tool);
}
box = jbox_new(JI_VERTICAL);
confbutton = jbutton_new(NULL);
void toolbar_select_tool(JWidget toolbar, Tool* tool)
{
((ToolBar*)toolbar)->selectTool(tool);
}
add_gfxicon_to_button(confbutton, GFX_TOOL_CONFIGURATION,
JI_CENTER | JI_MIDDLE);
ToolBar::ToolBar()
: Widget(JI_WIDGET)
{
this->border_width.l = 1*guiscale();
this->border_width.t = 0;
this->border_width.r = 1*guiscale();
this->border_width.b = 0;
tools = group_button_new(1, MAX_TOOLS, c,
GFX_TOOL_MARKER,
GFX_TOOL_PENCIL,
GFX_TOOL_BRUSH,
GFX_TOOL_ERASER,
GFX_TOOL_FLOODFILL,
GFX_TOOL_SPRAY,
GFX_TOOL_LINE,
GFX_TOOL_CURVE,
GFX_TOOL_RECTANGLE,
GFX_TOOL_ELLIPSE,
GFX_TOOL_BLUR,
GFX_TOOL_JUMBLE);
m_hot_tool = NULL;
m_hot_conf = false;
m_open_on_hot = false;
m_popup_window = NULL;
for (c=0; c<MAX_TOOLS; c++) {
JWidget child;
usprintf(buf, "radio%d", c);
child = jwidget_find_name(tools, buf);
ToolBox* toolbox = App::instance()->get_toolbox();
for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Tool* tool = *it;
if (m_selected_in_group.find(tool->getGroup()) == m_selected_in_group.end())
m_selected_in_group[tool->getGroup()] = tool;
}
}
usprintf(buf, "%s", _(tools_list[c]->tips));
ToolBar::~ToolBar()
{
delete m_popup_window;
}
JAccel accel = get_accel_to_change_tool(tools_list[c]);
if (accel) {
ustrcat(buf, "\n(");
jaccel_to_string(accel, buf+ustrsize(buf));
ustrcat(buf, ")");
bool ToolBar::isToolVisible(Tool* tool)
{
return (m_selected_in_group[tool->getGroup()] == tool);
}
void ToolBar::selectTool(Tool* tool)
{
onToolSelected(tool);
}
bool ToolBar::msg_proc(JMessage msg)
{
switch (msg->type) {
case JM_REQSIZE: {
Size iconsize = getToolIconSize(this);
msg->reqsize.w = iconsize.w + this->border_width.l + this->border_width.r;
msg->reqsize.h = iconsize.h + this->border_width.t + this->border_width.b;
return true;
}
jwidget_add_tooltip_text(child, buf);
}
jwidget_expansive(box, true);
case JM_DRAW: {
SkinneableTheme* theme = static_cast<SkinneableTheme*>(this->theme);
ToolBox* toolbox = App::instance()->get_toolbox();
ToolGroupList::iterator it = toolbox->begin_group();
int groups = toolbox->getGroupsCount();
Rect toolrc;
jwidget_add_child(box, tools);
jwidget_add_child(box, confbutton);
jdraw_rectfill(this->rc, theme->get_tab_selected_face_color());
HOOK(tools, SIGNAL_GROUP_BUTTON_CHANGE, tools_change_hook, 0);
jbutton_add_command(confbutton, conf_command);
for (int c=0; c<groups; ++c, ++it) {
ToolGroup* tool_group = *it;
Tool* tool = m_selected_in_group[tool_group];
int face, nw;
box->user_data[0] = tools;
if (UIContext::instance()->getSettings()->getCurrentTool() == tool ||
m_hot_tool == tool) {
nw = PART_TOOLBUTTON_HOT_NW;
face = theme->get_button_hot_face_color();
}
else {
nw = c >= 0 && c < groups-1 ? PART_TOOLBUTTON_NORMAL_NW:
PART_TOOLBUTTON_LAST_NW;
face = theme->get_button_normal_face_color();
}
SkinneableTheme* theme = static_cast<SkinneableTheme*>(box->theme);
box->setBgColor(theme->get_panel_face_color());
toolrc = getToolGroupBounds(c);
theme->draw_bounds(toolrc, nw, face);
return box;
}
// Draw the tool icon
BITMAP* icon = theme->get_toolicon(tool->getId().c_str());
if (icon)
draw_sprite(ji_screen, icon,
toolrc.x+toolrc.w/2-icon->w/2,
toolrc.y+toolrc.h/2-icon->h/2);
}
void toolbar_update(JWidget widget)
{
JWidget group = reinterpret_cast<JWidget>(widget->user_data[0]);
int c;
toolrc = getToolGroupBounds(-1);
theme->draw_bounds(toolrc,
m_hot_conf ? PART_TOOLBUTTON_HOT_NW:
PART_TOOLBUTTON_LAST_NW,
m_hot_conf ? theme->get_button_hot_face_color():
theme->get_button_normal_face_color());
for (c=0; c<MAX_TOOLS; c++)
if (current_tool == tools_list[c])
// Draw the tool icon
BITMAP* icon = theme->get_toolicon("configuration");
if (icon)
draw_sprite(ji_screen, icon,
toolrc.x+toolrc.w/2-icon->w/2,
toolrc.y+toolrc.h/2-icon->h/2);
return true;
}
case JM_BUTTONPRESSED: {
ToolBox* toolbox = App::instance()->get_toolbox();
int groups = toolbox->getGroupsCount();
int y = rc->y1;
Rect toolrc;
ToolGroupList::iterator it = toolbox->begin_group();
for (int c=0; c<groups; ++c, ++it) {
ToolGroup* tool_group = *it;
Tool* tool = m_selected_in_group[tool_group];
toolrc = getToolGroupBounds(c);
if (msg->mouse.y >= toolrc.y && msg->mouse.y < toolrc.y+toolrc.h) {
UIContext::instance()->getSettings()->setCurrentTool(tool);
dirty();
openPopupWindow(c, tool_group);
}
}
toolrc = getToolGroupBounds(-1);
if (msg->mouse.y >= toolrc.y && msg->mouse.y < toolrc.y+toolrc.h) {
Command* conf_tools_cmd =
CommandsModule::instance()->get_command_by_name(CommandId::configure_tools);
UIContext::instance()->execute_command(conf_tools_cmd);
}
break;
}
case JM_MOTION: {
ToolBox* toolbox = App::instance()->get_toolbox();
int groups = toolbox->getGroupsCount();
Tool* hot_tool = NULL;
bool hot_conf = false;
Rect toolrc;
ToolGroupList::iterator it = toolbox->begin_group();
for (int c=0; c<groups; ++c, ++it) {
ToolGroup* tool_group = *it;
Tool* tool = m_selected_in_group[tool_group];
toolrc = getToolGroupBounds(c);
if (msg->mouse.y >= toolrc.y && msg->mouse.y < toolrc.y+toolrc.h) {
hot_tool = tool;
if (m_open_on_hot)
openPopupWindow(c, tool_group);
break;
}
}
toolrc = getToolGroupBounds(-1);
if (msg->mouse.y >= toolrc.y && msg->mouse.y < toolrc.y+toolrc.h) {
hot_conf = true;
}
// hot button changed
if (m_hot_tool != hot_tool ||
m_hot_conf != hot_conf) {
m_hot_tool = hot_tool;
m_hot_conf = hot_conf;
dirty();
}
break;
}
case JM_MOUSELEAVE:
m_hot_tool = NULL;
m_hot_conf = false;
dirty();
break;
group_button_select(group, c);
}
return Widget::msg_proc(msg);
}
static bool tools_change_hook(JWidget widget, void *data)
void ToolBar::openPopupWindow(int group_index, ToolGroup* tool_group)
{
int c = group_button_get_selected(widget);
if (m_popup_window) {
m_popup_window->closeWindow(NULL);
delete m_popup_window;
}
if (current_tool != tools_list[c])
select_tool(tools_list[c]);
m_open_on_hot = true;
m_popup_window = new PopupWindow(NULL, false);
m_popup_window->Close.connect(Vaca::Bind<void>(&ToolBar::onClosePopup, this));
return false;
ToolStrip* groupbox = new ToolStrip(tool_group);
groupbox->ToolSelected.connect(&ToolBar::onToolSelected, this);
jwidget_add_child(m_popup_window, groupbox);
Rect rc = getToolGroupBounds(group_index);
int w = 0;
ToolBox* toolbox = App::instance()->get_toolbox();
for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Tool* tool = *it;
if (tool->getGroup() == tool_group)
w += jrect_w(this->rc)-this->border_width.l-this->border_width.r-1;
}
rc.x -= w;
rc.w = w;
// Set hotregion of popup window
{
jrect rc2 = { rc.x, rc.y, this->rc->x2, rc.y+rc.h };
JRegion hotregion = jregion_new(&rc2, 1);
m_popup_window->setHotRegion(hotregion);
}
m_popup_window->set_autoremap(false);
m_popup_window->setBounds(rc);
groupbox->setBounds(rc);
m_popup_window->open_window();
groupbox->setBounds(rc);
}
static void conf_command(JWidget widget)
Rect ToolBar::getToolGroupBounds(int group_index)
{
Command* conf_tools_cmd =
CommandsModule::instance()->get_command_by_name(CommandId::configure_tools);
ToolBox* toolbox = App::instance()->get_toolbox();
int groups = toolbox->getGroupsCount();
Size iconsize = getToolIconSize(this);
UIContext::instance()->execute_command(conf_tools_cmd);
if (group_index >= 0)
return Rect(rc->x1+border_width.l,
rc->y1+border_width.t+group_index*(iconsize.h-1),
jrect_w(rc)-border_width.l-border_width.r,
group_index < groups-1 ? iconsize.h+1: iconsize.h+2);
else
return Rect(rc->x1+border_width.l,
rc->y1+border_width.t+groups*(iconsize.h-1)+ 8*guiscale(),
jrect_w(rc)-border_width.l-border_width.r,
iconsize.h+2);
}
void ToolBar::onToolSelected(Tool* tool)
{
assert(tool != NULL);
m_selected_in_group[tool->getGroup()] = tool;
UIContext::instance()->getSettings()->setCurrentTool(tool);
dirty();
}
void ToolBar::onClosePopup()
{
m_open_on_hot = false;
m_hot_tool = NULL;
dirty();
}
//////////////////////////////////////////////////////////////////////
// ToolStrip
ToolStrip::ToolStrip(ToolGroup* group)
: Widget(JI_WIDGET)
{
m_group = group;
m_hot_tool = NULL;
}
ToolStrip::~ToolStrip()
{
}
bool ToolStrip::msg_proc(JMessage msg)
{
switch (msg->type) {
case JM_REQSIZE: {
ToolBox* toolbox = App::instance()->get_toolbox();
int c = 0;
for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Tool* tool = *it;
if (tool->getGroup() == m_group) {
++c;
}
}
Size iconsize = getToolIconSize(this);
msg->reqsize.w = iconsize.w * c;
msg->reqsize.h = iconsize.h;
return true;
}
case JM_DRAW: {
SkinneableTheme* theme = static_cast<SkinneableTheme*>(this->theme);
ToolBox* toolbox = App::instance()->get_toolbox();
Rect toolrc;
int index = 0;
jdraw_rectfill(this->rc, theme->get_tab_selected_face_color());
for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Tool* tool = *it;
if (tool->getGroup() == m_group) {
int face, nw;
if (UIContext::instance()->getSettings()->getCurrentTool() == tool ||
m_hot_tool == tool) {
nw = PART_TOOLBUTTON_HOT_NW;
face = theme->get_button_hot_face_color();
}
else {
nw = PART_TOOLBUTTON_LAST_NW;
face = theme->get_button_normal_face_color();
}
toolrc = getToolBounds(index++);
theme->draw_bounds(toolrc, nw, face);
// Draw the tool icon
BITMAP* icon = theme->get_toolicon(tool->getId().c_str());
if (icon)
draw_sprite(ji_screen, icon,
toolrc.x+toolrc.w/2-icon->w/2,
toolrc.y+toolrc.h/2-icon->h/2);
}
}
return true;
}
case JM_MOTION: {
ToolBox* toolbox = App::instance()->get_toolbox();
Tool* hot_tool = NULL;
Rect toolrc;
int index = 0;
for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
Tool* tool = *it;
if (tool->getGroup() == m_group) {
toolrc = getToolBounds(index++);
if (toolrc.contains(Point(msg->mouse.x, msg->mouse.y))) {
hot_tool = tool;
break;
}
}
}
// hot button changed
if (m_hot_tool != hot_tool) {
m_hot_tool = hot_tool;
dirty();
}
break;
}
case JM_BUTTONPRESSED:
if (m_hot_tool) {
ToolSelected(m_hot_tool);
closeWindow();
}
break;
}
return Widget::msg_proc(msg);
}
Rect ToolStrip::getToolBounds(int index)
{
ToolBox* toolbox = App::instance()->get_toolbox();
Size iconsize = getToolIconSize(this);
return Rect(rc->x1+index*(iconsize.w-1), rc->y1,
iconsize.w, jrect_h(rc));
}

View File

@ -23,6 +23,7 @@
JWidget toolbar_new();
void toolbar_update(JWidget toolbar);
bool toolbar_is_tool_visible(JWidget toolbar, Tool* tool);
void toolbar_select_tool(JWidget toolbar, Tool* tool);
#endif