mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 03:39:51 +00:00
New (default) options to customize timeline range selection (fix #4024)
Now a single click will not enable the range, using Shift+click or dragging the mouse will enable the range of multiple layers/frames/cels by default (but there are new options to go back to the previous behavior or customize this behavior in an extensive way).
This commit is contained in:
parent
3f8a8662fe
commit
dd7e27a098
@ -201,6 +201,9 @@
|
||||
</section>
|
||||
<section id="timeline">
|
||||
<option id="keep_selection" type="bool" default="false" />
|
||||
<option id="select_on_click" type="bool" default="false" />
|
||||
<option id="select_on_click_with_key" type="bool" default="true" />
|
||||
<option id="select_on_drag" type="bool" default="true" />
|
||||
</section>
|
||||
<section id="cursor">
|
||||
<option id="use_native_cursor" type="bool" default="false" />
|
||||
|
@ -1659,6 +1659,9 @@ keep_timeline_selection_tooltip = <<<END
|
||||
Keep the selected range of layers/frames/cels
|
||||
when we edit the canvas.
|
||||
END
|
||||
select_on_click = Select on Click
|
||||
select_on_click_with_key = Select on Click + Shift
|
||||
select_on_drag = Select on Drag
|
||||
default_first_frame = Default First Frame:
|
||||
ui_mouse_cursor = UI Mouse Cursor
|
||||
native_cursor = Use native mouse cursors
|
||||
|
@ -276,6 +276,9 @@
|
||||
pref="general.rewind_on_stop" />
|
||||
<check text="@.keep_timeline_selection" id="keep_selection" tooltip="@.keep_timeline_selection_tooltip"
|
||||
pref="timeline.keep_selection" />
|
||||
<check text="@.select_on_click" pref="timeline.select_on_click" />
|
||||
<check text="@.select_on_click_with_key" pref="timeline.select_on_click_with_key" />
|
||||
<check text="@.select_on_drag" pref="timeline.select_on_drag" />
|
||||
<hbox>
|
||||
<label text="@.default_first_frame" />
|
||||
<expr id="first_frame" />
|
||||
|
@ -338,7 +338,7 @@ void Timeline::updateUsingEditor(Editor* editor)
|
||||
|
||||
detachDocument();
|
||||
|
||||
if (Preferences::instance().timeline.keepSelection())
|
||||
if (timelinePref().keepSelection())
|
||||
m_range = oldRange;
|
||||
else {
|
||||
// The range is reset in detachDocument()
|
||||
@ -679,14 +679,6 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
// Clicked-part = hot-part.
|
||||
m_clk = m_hot;
|
||||
|
||||
// With Ctrl+click (Win/Linux) or Shift+click (OS X) we can
|
||||
// select non-adjacents layer/frame ranges
|
||||
bool clearRange =
|
||||
#if !defined(__APPLE__)
|
||||
!msg->ctrlPressed() &&
|
||||
#endif
|
||||
!msg->shiftPressed();
|
||||
|
||||
captureMouse();
|
||||
|
||||
switch (m_hot.part) {
|
||||
@ -767,15 +759,14 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
break;
|
||||
}
|
||||
case PART_HEADER_FRAME: {
|
||||
bool selectFrame = (mouseMsg->left() || !isFrameActive(m_clk.frame));
|
||||
bool selectFrame = (mouseMsg->left() ||
|
||||
!isFrameActive(m_clk.frame));
|
||||
|
||||
if (selectFrame) {
|
||||
m_state = STATE_SELECTING_FRAMES;
|
||||
if (clearRange)
|
||||
clearAndInvalidateRange();
|
||||
m_range.startRange(m_layer, m_clk.frame, Range::kFrames);
|
||||
m_startRange = m_range;
|
||||
invalidateRange();
|
||||
|
||||
handleRangeMouseDown(msg, Range::kFrames,
|
||||
m_layer, m_clk.frame);
|
||||
|
||||
setFrame(m_clk.frame, true);
|
||||
}
|
||||
@ -796,12 +787,9 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
}
|
||||
else if (selectLayer) {
|
||||
m_state = STATE_SELECTING_LAYERS;
|
||||
if (clearRange)
|
||||
clearAndInvalidateRange();
|
||||
m_range.startRange(m_rows[m_clk.layer].layer(),
|
||||
m_frame, Range::kLayers);
|
||||
m_startRange = m_range;
|
||||
invalidateRange();
|
||||
|
||||
handleRangeMouseDown(msg, Range::kLayers,
|
||||
m_rows[m_clk.layer].layer(), m_frame);
|
||||
|
||||
// Did the user select another layer?
|
||||
if (old_layer != m_clk.layer) {
|
||||
@ -936,17 +924,14 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
else {
|
||||
if (selectCel) {
|
||||
m_state = STATE_SELECTING_CELS;
|
||||
if (clearRange)
|
||||
clearAndInvalidateRange();
|
||||
m_range.startRange(m_rows[m_clk.layer].layer(),
|
||||
m_clk.frame, Range::kCels);
|
||||
m_startRange = m_range;
|
||||
invalidateRange();
|
||||
|
||||
handleRangeMouseDown(msg, Range::kCels,
|
||||
m_rows[m_clk.layer].layer(), m_clk.frame);
|
||||
}
|
||||
|
||||
// Select the new clicked-part.
|
||||
if (old_layer != m_clk.layer
|
||||
|| old_frame != m_clk.frame) {
|
||||
if (old_layer != m_clk.layer ||
|
||||
old_frame != m_clk.frame) {
|
||||
setLayer(m_rows[m_clk.layer].layer());
|
||||
setFrame(m_clk.frame, true);
|
||||
invalidate();
|
||||
@ -1157,42 +1142,58 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
|
||||
case STATE_SELECTING_LAYERS: {
|
||||
Layer* hitLayer = m_rows[hit.layer].layer();
|
||||
if (m_layer != hitLayer) {
|
||||
m_clk.layer = hit.layer;
|
||||
if (m_layer != hitLayer ||
|
||||
// Hit other part? useful to enable the range when
|
||||
// selectOnDrag is enabled.
|
||||
m_clk.part != hit.part) {
|
||||
if (m_layer != hitLayer) {
|
||||
m_clk.layer = hit.layer;
|
||||
}
|
||||
else {
|
||||
hitLayer = m_rows[m_clk.layer].layer();
|
||||
}
|
||||
|
||||
// We have to change the range before we generate an
|
||||
// onActiveSiteChange() event so observers (like cel
|
||||
// properties dialog) know the new selected range.
|
||||
m_range = m_startRange;
|
||||
m_range.endRange(hitLayer, m_frame);
|
||||
|
||||
handleRangeMouseMove(hitLayer, m_frame);
|
||||
setLayer(hitLayer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_SELECTING_FRAMES: {
|
||||
invalidateRange();
|
||||
if (m_clk.frame != hit.frame ||
|
||||
m_clk.part != hit.part) {
|
||||
if (m_clk.frame != hit.frame)
|
||||
m_clk.frame = hit.frame;
|
||||
|
||||
m_range = m_startRange;
|
||||
m_range.endRange(m_layer, hit.frame);
|
||||
invalidateRange();
|
||||
|
||||
setFrame(m_clk.frame = hit.frame, true);
|
||||
handleRangeMouseMove(m_layer, m_clk.frame);
|
||||
setFrame(m_clk.frame, true);
|
||||
|
||||
invalidateRange();
|
||||
invalidateRange();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_SELECTING_CELS: {
|
||||
Layer* hitLayer = m_rows[hit.layer].layer();
|
||||
if ((m_layer != hitLayer) || (m_frame != hit.frame)) {
|
||||
m_clk.layer = hit.layer;
|
||||
if ((m_layer != hitLayer) ||
|
||||
(m_frame != hit.frame) ||
|
||||
(m_clk.part != hit.part)) {
|
||||
if (m_layer != hitLayer)
|
||||
m_clk.layer = hit.layer;
|
||||
else
|
||||
hitLayer = m_rows[m_clk.layer].layer();
|
||||
|
||||
m_range = m_startRange;
|
||||
m_range.endRange(hitLayer, hit.frame);
|
||||
if (m_clk.frame != hit.frame)
|
||||
m_clk.frame = hit.frame;
|
||||
|
||||
handleRangeMouseMove(hitLayer, m_clk.frame);
|
||||
setLayer(hitLayer);
|
||||
setFrame(m_clk.frame = hit.frame, true);
|
||||
setFrame(m_clk.frame, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1578,6 +1579,78 @@ bool Timeline::onProcessMessage(Message* msg)
|
||||
return Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
void Timeline::handleRangeMouseDown(const ui::Message* msg,
|
||||
const Range::Type rangeType,
|
||||
doc::Layer* fromLayer,
|
||||
const doc::frame_t fromFrame)
|
||||
{
|
||||
// With Ctrl+click (Win/Linux) or Shift+click (OS X) we can
|
||||
// select non-adjacents layer/frame ranges
|
||||
const bool hasKeyModifier =
|
||||
#if !defined(__APPLE__)
|
||||
msg->ctrlPressed() ||
|
||||
#endif
|
||||
msg->shiftPressed();
|
||||
|
||||
// Clear the range (i.e. "start range from scratch") if the shift
|
||||
// key isn't pressed, or if it shouldn't act as a "keep selection"
|
||||
// modifier (selectOnClickWithKey = false)
|
||||
if (!hasKeyModifier ||
|
||||
!timelinePref().selectOnClickWithKey()) {
|
||||
clearAndInvalidateRange();
|
||||
|
||||
// If the Shift key is pressed here, it means that
|
||||
// selectOnClickWithKey=false, so Shift+click works as if it
|
||||
// doesn't select a range at all.
|
||||
if (hasKeyModifier) {
|
||||
// Here we clear the start range too and return (so Shift+click
|
||||
// acts like a single click without selecting the range).
|
||||
m_startRange.clearRange();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Start the range on mouse down/click.
|
||||
if ((timelinePref().selectOnClick()) ||
|
||||
(timelinePref().selectOnClickWithKey() && hasKeyModifier)) {
|
||||
// If Shift key is pressed, and we are just starting the range,
|
||||
// add the current location in the range too just in case that
|
||||
// we've clicked a layer/frame different from the active one.
|
||||
if (hasKeyModifier && !m_range.enabled()) {
|
||||
m_range.startRange(m_layer, m_frame, rangeType);
|
||||
m_range.endRange(m_layer, m_frame);
|
||||
}
|
||||
// Start the range with the clicked fromLayer/Frame position.
|
||||
m_range.startRange(fromLayer, fromFrame, rangeType);
|
||||
m_startRange = m_range;
|
||||
}
|
||||
// If selectOnClick/WithKey are disabled, we start the range on
|
||||
// drag, but we've to indicate from where we're starting
|
||||
// (m_startRange).
|
||||
else if (timelinePref().selectOnDrag()) {
|
||||
m_startRange.clearRange();
|
||||
m_startRange.startRange(fromLayer, fromFrame, rangeType);
|
||||
}
|
||||
else {
|
||||
m_startRange = m_range;
|
||||
}
|
||||
|
||||
invalidateRange();
|
||||
}
|
||||
|
||||
void Timeline::handleRangeMouseMove(doc::Layer* fromLayer,
|
||||
const doc::frame_t fromFrame)
|
||||
{
|
||||
// Indicate the range end if it's already enabled by the mouse down
|
||||
// event, or in other case, check the if selectOnDrag=true to enable
|
||||
// the range when we move the mouse.
|
||||
if (m_range.enabled() ||
|
||||
timelinePref().selectOnDrag()) {
|
||||
m_range = m_startRange;
|
||||
m_range.endRange(fromLayer, fromFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::onInitTheme(ui::InitThemeEvent& ev)
|
||||
{
|
||||
Widget::onInitTheme(ev);
|
||||
@ -4166,6 +4239,11 @@ void Timeline::clearAndInvalidateRange()
|
||||
}
|
||||
}
|
||||
|
||||
app::gen::GlobalPref::Timeline& Timeline::timelinePref() const
|
||||
{
|
||||
return Preferences::instance().timeline;
|
||||
}
|
||||
|
||||
DocumentPreferences& Timeline::docPref() const
|
||||
{
|
||||
return Preferences::instance().document(m_document);
|
||||
|
@ -256,6 +256,14 @@ namespace app {
|
||||
LayerFlags m_inheritedFlags;
|
||||
};
|
||||
|
||||
void handleRangeMouseDown(const ui::Message* msg,
|
||||
const Range::Type rangeType,
|
||||
doc::Layer* fromLayer,
|
||||
const doc::frame_t fromFrame);
|
||||
|
||||
void handleRangeMouseMove(doc::Layer* fromLayer,
|
||||
const doc::frame_t fromFrame);
|
||||
|
||||
bool selectedLayersBounds(const SelectedLayers& layers,
|
||||
layer_t* first, layer_t* last) const;
|
||||
|
||||
@ -349,6 +357,7 @@ namespace app {
|
||||
|
||||
int topHeight() const;
|
||||
|
||||
app::gen::GlobalPref::Timeline& timelinePref() const;
|
||||
DocumentPreferences& docPref() const;
|
||||
|
||||
// Theme/dimensions
|
||||
|
Loading…
x
Reference in New Issue
Block a user