mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 04:59:24 +00:00
- All tools stuff refactored in various files/components.
- Added classes: IToolLoop, Tool, ToolGroup, ToolInk, ToolController, ToolPointShape, ToolIntertwine, ToolBox, etc. - Added ToolLoopManager. - Removed old src/modules/tools.cpp. - Added ISettings and UISettingsImpl, adding the tools settings (onion skinning, grid, tiled mode, etc.). - Added App::PenSizeBeforeChange, PenSizeAfterChange, CurrentToolChange signals. - Renamed Context::get_bg/fg_color to getBg/FgColor. - Refactored Brush class to Pen and added PenType. - Renamed tiled_t to TiledMode. - get_config_rect now uses the new Rect class imported from Vaca instead of old jrect. - Added default_skin.xml to load tool icons. - Added pen preview in Editor::cursor stuff. - Added Editor::decorators. Note: This big patch is from some time ago. I did my best to pre-commit other small changes before this big one.
This commit is contained in:
parent
ef51fd59ea
commit
cb97884026
@ -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.
|
||||
|
12
NEWS.txt
12
NEWS.txt
@ -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
|
||||
-----
|
||||
|
35
TODO.txt
35
TODO.txt
@ -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:
|
||||
|
246
data/gui.xml
246
data/gui.xml
@ -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>
|
||||
|
@ -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 &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">
|
||||
|
41
data/skins/default_skin.xml
Normal file
41
data/skins/default_skin.xml
Normal 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>
|
BIN
data/skins/default_skin_font.pcx
Normal file
BIN
data/skins/default_skin_font.pcx
Normal file
Binary file not shown.
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -112,6 +112,8 @@ VPATH = src \
|
||||
src/modules \
|
||||
src/raster \
|
||||
src/raster/x86 \
|
||||
src/settings \
|
||||
src/tools \
|
||||
src/util \
|
||||
src/widgets \
|
||||
src/widgets/editor \
|
||||
|
@ -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 \
|
||||
|
@ -154,6 +154,8 @@ VPATH = src \
|
||||
src/modules \
|
||||
src/raster \
|
||||
src/raster/x86 \
|
||||
src/settings \
|
||||
src/tools \
|
||||
src/util \
|
||||
src/widgets \
|
||||
src/widgets/editor \
|
||||
|
@ -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 \
|
||||
|
@ -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"
|
||||
}
|
||||
|
11
src/app.cpp
11
src/app.cpp
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <cstring>
|
||||
#include "sprite_wrappers.h"
|
||||
#include "jinete/jbase.h"
|
||||
#include "tiled_mode.h"
|
||||
|
||||
class Image;
|
||||
class Mask;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define MODULES_EDITORS_H_INCLUDED
|
||||
|
||||
#include "jinete/jbase.h"
|
||||
#include "core/color.h"
|
||||
|
||||
class Editor;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef MODULES_TOOLS_H_INCLUDED
|
||||
#define MODULES_TOOLS_H_INCLUDED
|
||||
|
||||
#error Deprecated
|
||||
|
||||
#include "jinete/jbase.h"
|
||||
#include "jinete/jrect.h"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
173
src/raster/pen.cpp
Normal 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
61
src/raster/pen.h
Normal 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
|
||||
|
@ -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
112
src/settings/settings.h
Normal 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
|
||||
|
333
src/settings/ui_settings_impl.cpp
Normal file
333
src/settings/ui_settings_impl.cpp
Normal 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;
|
||||
}
|
||||
}
|
81
src/settings/ui_settings_impl.h
Normal file
81
src/settings/ui_settings_impl.h
Normal 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
|
@ -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
30
src/tiled_mode.h
Normal 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
275
src/tools/controllers.h
Normal 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
465
src/tools/ink_processing.h
Normal 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
267
src/tools/inks.h
Normal 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, ¶ms);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
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
214
src/tools/intertwiners.h
Normal 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
137
src/tools/point_shapes.h
Normal 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
303
src/tools/tool.cpp
Normal 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
378
src/tools/tool.h
Normal 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
253
src/tools/toolbox.cpp
Normal 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
68
src/tools/toolbox.h
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user