From a20bb2d4d73f8eef05acf471d6c338dc9c3e077b Mon Sep 17 00:00:00 2001 From: David Capello Date: Thu, 24 Jul 2014 23:50:45 -0300 Subject: [PATCH] Change Timeline logic to work with LayerIndex instead of inverted UI indexes This is a work-in-progress, dropRange() must be reimplemented. Now that the Timeline uses LayerIndex, we could change Timeline::Range to DocumentRange and create unit tests for the logic side. --- src/app/commands/cmd_remove_cel.cpp | 5 +- src/app/commands/cmd_remove_layer.cpp | 5 +- src/app/ui/timeline.cpp | 321 +++++++++++++------------- src/app/ui/timeline.h | 60 +++-- src/raster/CMakeLists.txt | 1 + src/raster/layer_index.cpp | 29 +++ src/raster/layer_index.h | 4 + 7 files changed, 230 insertions(+), 195 deletions(-) create mode 100644 src/raster/layer_index.cpp diff --git a/src/app/commands/cmd_remove_cel.cpp b/src/app/commands/cmd_remove_cel.cpp index 9a2edd464..c3c1ac0e6 100644 --- a/src/app/commands/cmd_remove_cel.cpp +++ b/src/app/commands/cmd_remove_cel.cpp @@ -72,10 +72,7 @@ void RemoveCelCommand::onExecute(Context* context) if (range.enabled()) { Sprite* sprite = writer.sprite(); - // TODO indexes in timeline are inverted!! fix that for a future release - for (LayerIndex layerIdx = sprite->countLayers() - LayerIndex(range.layerBegin()+1), - end = sprite->countLayers() - LayerIndex(range.layerEnd()+2); - layerIdx != end; --layerIdx) { + for (LayerIndex layerIdx = range.layerBegin(); layerIdx <= range.layerEnd(); ++layerIdx) { Layer* layer = sprite->indexToLayer(layerIdx); if (!layer->isImage()) continue; diff --git a/src/app/commands/cmd_remove_layer.cpp b/src/app/commands/cmd_remove_layer.cpp index d4c613352..784c84cf3 100644 --- a/src/app/commands/cmd_remove_layer.cpp +++ b/src/app/commands/cmd_remove_layer.cpp @@ -75,10 +75,7 @@ void RemoveLayerCommand::onExecute(Context* context) if (range.enabled()) { Sprite* sprite = writer.sprite(); - // TODO indexes in timeline are inverted!! fix that for a future release - for (LayerIndex layer = sprite->countLayers() - LayerIndex(range.layerBegin()+1), - end = sprite->countLayers() - LayerIndex(range.layerEnd()+2); - layer != end; --layer) { + for (LayerIndex layer = range.layerEnd(); layer >= range.layerBegin(); --layer) { document->getApi().removeLayer(sprite->indexToLayer(layer)); } } diff --git a/src/app/ui/timeline.cpp b/src/app/ui/timeline.cpp index 527d3472a..80703f8b6 100644 --- a/src/app/ui/timeline.cpp +++ b/src/app/ui/timeline.cpp @@ -265,7 +265,7 @@ void Timeline::setFrame(FrameNumber frame) // ASSERT(frame >= 0 && frame < m_sprite->getTotalFrames()); if (frame < 0) - frame = FrameNumber(0); + frame = firstFrame(); else if (frame >= m_sprite->getTotalFrames()) frame = FrameNumber(m_sprite->getTotalFrames()-1); @@ -335,7 +335,7 @@ bool Timeline::onProcessMessage(Message* msg) case A_PART_LAYER_TEXT: { const DocumentReader document(const_cast(m_document)); const Sprite* sprite = m_sprite; - int old_layer = getLayerIndex(m_layer); + LayerIndex old_layer = getLayerIndex(m_layer); bool selectLayer = (mouseMsg->left() || !isLayerActive(m_clk_layer)); FrameNumber frame = m_frame; @@ -363,7 +363,7 @@ bool Timeline::onProcessMessage(Message* msg) case A_PART_CEL: { const DocumentReader document(const_cast(m_document)); const Sprite* sprite = document->getSprite(); - int old_layer = getLayerIndex(m_layer); + LayerIndex old_layer = getLayerIndex(m_layer); bool selectCel = (mouseMsg->left() || !isLayerActive(m_clk_layer) || !isFrameActive(m_clk_frame)); @@ -402,7 +402,7 @@ bool Timeline::onProcessMessage(Message* msg) break; int hot_part = A_PART_NOTHING; - int hot_layer = -1; + LayerIndex hot_layer = LayerIndex::NoLayer; gfx::Point mousePos = static_cast(msg)->position() - getBounds().getOrigin(); @@ -454,6 +454,25 @@ bool Timeline::onProcessMessage(Message* msg) } } + hot_layer = lastLayer() - LayerIndex( + (mousePos.y + - HDRSIZE + + m_scroll_y) / LAYSIZE); + + hot_frame = FrameNumber((mousePos.x + - m_separator_x + - m_separator_w + + m_scroll_x) / FRMSIZE); + + if (hasCapture()) { + hot_layer = MID(firstLayer(), hot_layer, lastLayer()); + hot_frame = MID(firstFrame(), hot_frame, lastFrame()); + } + else { + if (hot_layer > lastLayer()) hot_layer = LayerIndex::NoLayer; + if (hot_frame > lastFrame()) hot_frame = FrameNumber(-1); + } + // Is the mouse over onionskin handles? gfx::Rect bounds = getOnionskinFramesBounds(); if (!bounds.isEmpty() && gfx::Rect(bounds.x, bounds.y, 3, bounds.h).contains(mousePos)) { @@ -464,7 +483,7 @@ bool Timeline::onProcessMessage(Message* msg) } // Is the mouse on the separator. else if (mousePos.x > m_separator_x-4 - && mousePos.x < m_separator_x+4) { + && mousePos.x < m_separator_x+4) { hot_part = A_PART_SEPARATOR; } // Is the mouse on the headers? @@ -483,26 +502,9 @@ bool Timeline::onProcessMessage(Message* msg) } else { hot_part = A_PART_HEADER_FRAME; - hot_frame = FrameNumber((mousePos.x - - m_separator_x - - m_separator_w - + m_scroll_x) / FRMSIZE); } } else { - hot_layer = (mousePos.y - - HDRSIZE - + m_scroll_y) / LAYSIZE; - - if (hot_layer >= (int)m_layers.size()) { - if (hasCapture()) - hot_layer = m_layers.size()-1; - else - hot_layer = -1; - } - else if (hasCapture() && hot_layer < 0) - hot_layer = 0; - // Is the mouse on a layer's label? if (mousePos.x < m_separator_x) { if (getPartBounds(A_PART_LAYER_EYE_ICON, hot_layer).contains(mousePos)) @@ -514,25 +516,17 @@ bool Timeline::onProcessMessage(Message* msg) else hot_part = A_PART_LAYER; } - else if (hot_layer >= 0 && hot_layer < (int)m_layers.size() && - hot_frame >= FrameNumber(0) && hot_frame <= m_sprite->getLastFrame()) { + else if (validLayer(hot_layer) && validFrame(hot_frame)) { hot_part = A_PART_CEL; } else hot_part = A_PART_NOTHING; } - if (hasCapture()) { - hot_layer = MID(0, hot_layer, (int)m_layers.size()-1); - hot_frame = MID(FrameNumber(0), hot_frame, m_sprite->getLastFrame()); - } - else { - if (hot_layer >= (int)m_layers.size()) hot_layer = -1; - if (hot_frame > m_sprite->getLastFrame()) hot_frame = FrameNumber(-1); - + if (!hasCapture()) { gfx::Rect outline = getPartBounds(A_PART_RANGE_OUTLINE); if (outline.contains(mousePos) && - !gfx::Rect(outline).shrink(4*jguiscale()).contains(mousePos)) { + !gfx::Rect(outline).shrink(2*OUTLINE_WIDTH).contains(mousePos)) { hot_part = A_PART_RANGE_OUTLINE; } } @@ -672,9 +666,7 @@ bool Timeline::onProcessMessage(Message* msg) case A_PART_LAYER_EYE_ICON: // Hide/show layer. - if (m_hot_layer == m_clk_layer && - m_hot_layer >= 0 && - m_hot_layer < (int)m_layers.size()) { + if (m_hot_layer == m_clk_layer && validLayer(m_hot_layer)) { Layer* layer = m_layers[m_clk_layer]; ASSERT(layer != NULL); layer->setReadable(!layer->isReadable()); @@ -686,9 +678,7 @@ bool Timeline::onProcessMessage(Message* msg) case A_PART_LAYER_PADLOCK_ICON: // Lock/unlock layer. - if (m_hot_layer == m_clk_layer && - m_hot_layer >= 0 && - m_hot_layer < (int)m_layers.size()) { + if (m_hot_layer == m_clk_layer && validLayer(m_hot_layer)) { Layer* layer = m_layers[m_clk_layer]; ASSERT(layer != NULL); layer->setWritable(!layer->isWritable()); @@ -714,7 +704,9 @@ bool Timeline::onProcessMessage(Message* msg) } - if (mouseMsg->left() && m_state == STATE_MOVING_RANGE) { + if (mouseMsg->left() && + m_state == STATE_MOVING_RANGE && + m_dropRange.type() != Range::kNone) { dropRange(isCopyKeyPressed(mouseMsg) ? Timeline::kCopy: Timeline::kMove); @@ -856,7 +848,7 @@ void Timeline::onPaint(ui::PaintEvent& ev) // Lock the sprite to read/render it. const DocumentReader documentReader(m_document); - int layer, first_layer, last_layer; + LayerIndex layer, first_layer, last_layer; FrameNumber frame, first_frame, last_frame; getDrawableLayers(g, &first_layer, &last_layer); @@ -883,7 +875,7 @@ void Timeline::onPaint(ui::PaintEvent& ev) } // Draw each visible layer. - for (layer=first_layer; layer<=last_layer; layer++) { + for (layer=last_layer; layer>=first_layer; --layer) { { IntersectClip clip(g, getLayerHeadersBounds()); if (clip) @@ -1070,15 +1062,20 @@ void Timeline::setCursor(int x, int y) } } -void Timeline::getDrawableLayers(ui::Graphics* g, int* first_layer, int* last_layer) +void Timeline::getDrawableLayers(ui::Graphics* g, LayerIndex* first_layer, LayerIndex* last_layer) { - *first_layer = m_scroll_y / LAYSIZE; - *first_layer = MID(0, *first_layer, (int)m_layers.size()-1); - *last_layer = *first_layer + (getClientBounds().h - HDRSIZE) / LAYSIZE; - *last_layer = MID(0, *last_layer, (int)m_layers.size()-1); + int hpx = (getClientBounds().h - HDRSIZE); + LayerIndex i = lastLayer() - LayerIndex((m_scroll_y+hpx) / LAYSIZE); + i = MID(firstLayer(), i, lastLayer()); - if (m_layers.empty()) - *last_layer = -1; + LayerIndex j = i + LayerIndex(hpx / LAYSIZE); + if (!m_layers.empty()) + j = MID(firstLayer(), j, lastLayer()); + else + j = LayerIndex::NoLayer; + + *first_layer = i; + *last_layer = j; } void Timeline::getDrawableFrames(ui::Graphics* g, FrameNumber* first_frame, FrameNumber* last_frame) @@ -1147,7 +1144,7 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, FrameNumber frame) bool is_active = isFrameActive(frame); bool is_hover = (m_hot_part == A_PART_HEADER_FRAME && m_hot_frame == frame); bool is_clicked = (m_clk_part == A_PART_HEADER_FRAME && m_clk_frame == frame); - gfx::Rect bounds = getPartBounds(A_PART_HEADER_FRAME, 0, frame); + gfx::Rect bounds = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), frame); IntersectClip clip(g, bounds); if (!clip) return; @@ -1162,19 +1159,19 @@ void Timeline::drawHeaderFrame(ui::Graphics* g, FrameNumber frame) g->setFont(oldFont); } -void Timeline::drawLayer(ui::Graphics* g, int layer_index) +void Timeline::drawLayer(ui::Graphics* g, LayerIndex layerIdx) { - Layer* layer = m_layers[layer_index]; - bool is_active = isLayerActive(layer_index); - bool hotlayer = (m_hot_layer == layer_index); - bool clklayer = (m_clk_layer == layer_index); - gfx::Rect bounds = getPartBounds(A_PART_LAYER, layer_index, FrameNumber(0)); + Layer* layer = m_layers[layerIdx]; + bool is_active = isLayerActive(layerIdx); + bool hotlayer = (m_hot_layer == layerIdx); + bool clklayer = (m_clk_layer == layerIdx); + gfx::Rect bounds = getPartBounds(A_PART_LAYER, layerIdx, firstFrame()); IntersectClip clip(g, bounds); if (!clip) return; // Draw the eye (readable flag). - bounds = getPartBounds(A_PART_LAYER_EYE_ICON, layer_index); + bounds = getPartBounds(A_PART_LAYER_EYE_ICON, layerIdx); drawPart(g, bounds, NULL, layer->isReadable() ? m_timelineOpenEyeStyle: m_timelineClosedEyeStyle, is_active, @@ -1182,7 +1179,7 @@ void Timeline::drawLayer(ui::Graphics* g, int layer_index) (clklayer && m_clk_part == A_PART_LAYER_EYE_ICON)); // Draw the padlock (writable flag). - bounds = getPartBounds(A_PART_LAYER_PADLOCK_ICON, layer_index); + bounds = getPartBounds(A_PART_LAYER_PADLOCK_ICON, layerIdx); drawPart(g, bounds, NULL, layer->isWritable() ? m_timelineOpenPadlockStyle: m_timelineClosedPadlockStyle, is_active, @@ -1190,7 +1187,7 @@ void Timeline::drawLayer(ui::Graphics* g, int layer_index) (clklayer && m_clk_part == A_PART_LAYER_PADLOCK_ICON)); // Draw the layer's name. - bounds = getPartBounds(A_PART_LAYER_TEXT, layer_index); + bounds = getPartBounds(A_PART_LAYER_TEXT, layerIdx); drawPart(g, bounds, layer->getName().c_str(), m_timelineLayerStyle, is_active, (hotlayer && m_hot_part == A_PART_LAYER_TEXT), @@ -1206,21 +1203,21 @@ void Timeline::drawLayer(ui::Graphics* g, int layer_index) } } -void Timeline::drawCel(ui::Graphics* g, int layer_index, FrameNumber frame, Cel* cel) +void Timeline::drawCel(ui::Graphics* g, LayerIndex layerIndex, FrameNumber frame, Cel* cel) { - Layer* layer = m_layers[layer_index]; + Layer* layer = m_layers[layerIndex]; Image* image = (cel ? m_sprite->getStock()->getImage(cel->getImage()): NULL); bool is_hover = (m_hot_part == A_PART_CEL && - m_hot_layer == layer_index && + m_hot_layer == layerIndex && m_hot_frame == frame); - bool is_active = (isLayerActive(layer_index) || isFrameActive(frame)); + bool is_active = (isLayerActive(layerIndex) || isFrameActive(frame)); bool is_empty = (image == NULL); - gfx::Rect bounds = getPartBounds(A_PART_CEL, layer_index, frame); + gfx::Rect bounds = getPartBounds(A_PART_CEL, layerIndex, frame); IntersectClip clip(g, bounds); if (!clip) return; - if (layer_index == getLayerIndex(m_layer) && frame == m_frame) + if (layerIndex == getLayerIndex(m_layer) && frame == m_frame) drawPart(g, bounds, NULL, m_timelineSelectedCelStyle, false, false, true); else drawPart(g, bounds, NULL, m_timelineBoxStyle, is_active, is_hover); @@ -1268,8 +1265,8 @@ void Timeline::drawLoopRange(ui::Graphics* g) if (begin > end) return; - gfx::Rect bounds1 = getPartBounds(A_PART_HEADER_FRAME, 0, begin); - gfx::Rect bounds2 = getPartBounds(A_PART_HEADER_FRAME, 0, end); + gfx::Rect bounds1 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), begin); + gfx::Rect bounds2 = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), end); gfx::Rect bounds = bounds1.createUnion(bounds2); IntersectClip clip(g, bounds); @@ -1346,33 +1343,33 @@ void Timeline::drawRangeOutline(ui::Graphics* g) void Timeline::drawPaddings(ui::Graphics* g) { gfx::Rect client = getClientBounds(); - gfx::Rect lastLayer; + gfx::Rect bottomLayer; gfx::Rect lastFrame; if (!m_layers.empty()) { - lastLayer = getPartBounds(A_PART_LAYER, m_layers.size()-1); - lastFrame = getPartBounds(A_PART_CEL, 0, m_sprite->getLastFrame()); + bottomLayer = getPartBounds(A_PART_LAYER, firstLayer()); + lastFrame = getPartBounds(A_PART_CEL, firstLayer(), this->lastFrame()); } else { - lastLayer = getPartBounds(A_PART_HEADER_LAYER); - lastFrame = getPartBounds(A_PART_HEADER_FRAME, 0, m_sprite->getLastFrame()); + bottomLayer = getPartBounds(A_PART_HEADER_LAYER); + lastFrame = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), this->lastFrame()); } drawPart(g, gfx::Rect(lastFrame.x+lastFrame.w, client.y, client.w - (lastFrame.x+lastFrame.w), - lastLayer.y+lastLayer.h), + bottomLayer.y+bottomLayer.h), NULL, m_timelinePaddingTrStyle); drawPart(g, - gfx::Rect(client.x, lastLayer.y+lastLayer.h, - lastFrame.x+lastFrame.w - client.x, client.h - (lastLayer.y+lastLayer.h)), + gfx::Rect(client.x, bottomLayer.y+bottomLayer.h, + lastFrame.x+lastFrame.w - client.x, client.h - (bottomLayer.y+bottomLayer.h)), NULL, m_timelinePaddingBlStyle); drawPart(g, - gfx::Rect(lastFrame.x+lastFrame.w, lastLayer.y+lastLayer.h, + gfx::Rect(lastFrame.x+lastFrame.w, bottomLayer.y+bottomLayer.h, client.w - (lastFrame.x+lastFrame.w), - client.h - (lastLayer.y+lastLayer.h)), + client.h - (bottomLayer.y+bottomLayer.h)), NULL, m_timelinePaddingBrStyle); } @@ -1402,11 +1399,14 @@ gfx::Rect Timeline::getOnionskinFramesBounds() const FrameNumber firstFrame = m_frame.previous(docSettings->getOnionskinPrevFrames()); FrameNumber lastFrame = m_frame.next(docSettings->getOnionskinNextFrames()); - if (firstFrame < 0) firstFrame = FrameNumber(0); - if (lastFrame > m_sprite->getLastFrame()) lastFrame = m_sprite->getLastFrame(); + if (firstFrame < this->firstFrame()) + firstFrame = this->firstFrame(); - return getPartBounds(A_PART_HEADER_FRAME, 0, firstFrame) - .createUnion(getPartBounds(A_PART_HEADER_FRAME, 0, lastFrame)); + if (lastFrame > this->lastFrame()) + lastFrame = this->lastFrame(); + + return getPartBounds(A_PART_HEADER_FRAME, firstLayer(), firstFrame) + .createUnion(getPartBounds(A_PART_HEADER_FRAME, firstLayer(), lastFrame)); } return gfx::Rect(); } @@ -1421,7 +1421,7 @@ gfx::Rect Timeline::getCelsBounds() const return rc; } -gfx::Rect Timeline::getPartBounds(int part, int layer, FrameNumber frame) const +gfx::Rect Timeline::getPartBounds(int part, LayerIndex layer, FrameNumber frame) const { const gfx::Rect bounds = getClientBounds(); @@ -1432,8 +1432,7 @@ gfx::Rect Timeline::getPartBounds(int part, int layer, FrameNumber frame) const case A_PART_SEPARATOR: return gfx::Rect(m_separator_x, 0, - m_separator_x + m_separator_w, - bounds.h); + m_separator_x + m_separator_w, bounds.h); case A_PART_HEADER_EYE: return gfx::Rect(FRMSIZE*0, 0, FRMSIZE, HDRSIZE); @@ -1449,64 +1448,56 @@ gfx::Rect Timeline::getPartBounds(int part, int layer, FrameNumber frame) const case A_PART_HEADER_LAYER: return gfx::Rect(FRMSIZE*4, 0, - m_separator_x - FRMSIZE*4, - HDRSIZE); + m_separator_x - FRMSIZE*4, HDRSIZE); case A_PART_HEADER_FRAME: - if (frame >= 0 && frame < m_sprite->getTotalFrames()) { + if (validFrame(frame)) { return gfx::Rect(m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x, - 0, - FRMSIZE, - HDRSIZE); + 0, FRMSIZE, HDRSIZE); } break; case A_PART_LAYER: - if (layer >= 0 && layer < (int)m_layers.size()) { + if (validLayer(layer)) { return gfx::Rect(0, - HDRSIZE + LAYSIZE*layer - m_scroll_y, - m_separator_x, - LAYSIZE); + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y, + m_separator_x, LAYSIZE); } break; case A_PART_LAYER_EYE_ICON: - if (layer >= 0 && layer < (int)m_layers.size()) { + if (validLayer(layer)) { return gfx::Rect(0, - HDRSIZE + LAYSIZE*layer - m_scroll_y, - FRMSIZE, - LAYSIZE); + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y, + FRMSIZE, LAYSIZE); } break; case A_PART_LAYER_PADLOCK_ICON: - if (layer >= 0 && layer < (int)m_layers.size()) { + if (validLayer(layer)) { return gfx::Rect(FRMSIZE, - HDRSIZE + LAYSIZE*layer - m_scroll_y, - FRMSIZE, - LAYSIZE); + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y, + FRMSIZE, LAYSIZE); } break; case A_PART_LAYER_TEXT: - if (layer >= 0 && layer < (int)m_layers.size()) { + if (validLayer(layer)) { int x = FRMSIZE*2; return gfx::Rect(x, - HDRSIZE + LAYSIZE*layer - m_scroll_y, - m_separator_x - x, - LAYSIZE); + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y, + m_separator_x - x, LAYSIZE); } break; case A_PART_CEL: - if (layer >= 0 && layer < (int)m_layers.size() && - frame >= 0 && frame < m_sprite->getTotalFrames()) { + if (validLayer(layer) && validFrame(frame)) { Cel* cel = (m_layers[layer]->isImage() ? static_cast(m_layers[layer])->getCel(frame): NULL); - return gfx::Rect(m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x, - HDRSIZE + LAYSIZE*layer - m_scroll_y, - FRMSIZE, - LAYSIZE); + return gfx::Rect( + m_separator_x + m_separator_w - 1 + FRMSIZE*frame - m_scroll_x, + HDRSIZE + LAYSIZE*(lastLayer()-layer) - m_scroll_y, + FRMSIZE, LAYSIZE); } break; @@ -1533,8 +1524,8 @@ gfx::Rect Timeline::getRangeBounds(const Range& range) const getPartBounds(A_PART_CEL, range.layerEnd(), range.frameEnd())); break; case Range::kFrames: - rc = getPartBounds(A_PART_HEADER_FRAME, 0, range.frameBegin()).createUnion( - getPartBounds(A_PART_HEADER_FRAME, 0, range.frameEnd())); + rc = getPartBounds(A_PART_HEADER_FRAME, firstLayer(), range.frameBegin()).createUnion( + getPartBounds(A_PART_HEADER_FRAME, firstLayer(), range.frameEnd())); break; case Range::kLayers: rc = getPartBounds(A_PART_LAYER, range.layerBegin()).createUnion( @@ -1544,7 +1535,7 @@ gfx::Rect Timeline::getRangeBounds(const Range& range) const return rc; } -void Timeline::invalidatePart(int part, int layer, FrameNumber frame) +void Timeline::invalidatePart(int part, LayerIndex layer, FrameNumber frame) { invalidateRect(getPartBounds(part, layer, frame).offset(getOrigin())); } @@ -1563,10 +1554,10 @@ void Timeline::regenerateLayers() } for (size_t c=0; cindexToLayer(LayerIndex(nlayers-c-1)); + m_layers[c] = m_sprite->indexToLayer(LayerIndex(c)); } -void Timeline::hotThis(int hot_part, int hot_layer, FrameNumber hot_frame) +void Timeline::hotThis(int hot_part, LayerIndex hot_layer, FrameNumber hot_frame) { // If the part, layer or frame change. if (hot_part != m_hot_part || @@ -1609,7 +1600,7 @@ void Timeline::updateStatusBar(ui::Message* msg) break; case Range::kFrames: - if (m_hot_frame >= FrameNumber(0) && m_hot_frame <= m_sprite->getLastFrame()) { + if (validFrame(m_hot_frame)) { if (m_dropTarget.hhit == DropTarget::Before) { sb->setStatusText(0, "%s before frame %d", verb, (int)m_dropRange.frameBegin().next()); return; @@ -1645,9 +1636,7 @@ void Timeline::updateStatusBar(ui::Message* msg) } } else { - Layer* layer = - ((m_hot_layer >= 0 && - m_hot_layer < (int)m_layers.size()) ? m_layers[m_hot_layer]: NULL); + Layer* layer = (validLayer(m_hot_layer) ? m_layers[m_hot_layer]: NULL); switch (m_hot_part) { @@ -1691,8 +1680,7 @@ void Timeline::updateStatusBar(ui::Message* msg) break; case A_PART_HEADER_FRAME: - if (m_hot_frame >= FrameNumber(0) && - m_hot_frame <= m_sprite->getLastFrame()) { + if (validFrame(m_hot_frame)) { sb->setStatusText(0, "Frame %d [%d msecs]", (int)m_hot_frame+1, @@ -1717,23 +1705,23 @@ void Timeline::updateStatusBar(ui::Message* msg) sb->clearText(); } -void Timeline::centerCel(int layer, FrameNumber frame) +void Timeline::centerCel(LayerIndex layer, FrameNumber frame) { int target_x = (getBounds().x + m_separator_x + m_separator_w + getBounds().x2())/2 - FRMSIZE/2; int target_y = (getBounds().y + HDRSIZE + getBounds().y2())/2 - LAYSIZE/2; int scroll_x = getBounds().x + m_separator_x + m_separator_w + FRMSIZE*frame - target_x; - int scroll_y = getBounds().y + HDRSIZE + LAYSIZE*layer - target_y; + int scroll_y = getBounds().y + HDRSIZE + LAYSIZE*(lastLayer() - layer) - target_y; setScroll(scroll_x, scroll_y); } -void Timeline::showCel(int layer, FrameNumber frame) +void Timeline::showCel(LayerIndex layer, FrameNumber frame) { int scroll_x, scroll_y; int x1, y1, x2, y2; x1 = getBounds().x + m_separator_x + m_separator_w + FRMSIZE*frame - m_scroll_x; - y1 = getBounds().y + HDRSIZE + LAYSIZE*layer - m_scroll_y; + y1 = getBounds().y + HDRSIZE + LAYSIZE*(lastLayer() - layer) - m_scroll_y; x2 = x1 + FRMSIZE - 1; y2 = y1 + LAYSIZE - 1; @@ -1761,8 +1749,8 @@ void Timeline::showCel(int layer, FrameNumber frame) void Timeline::showCurrentCel() { - int layer = getLayerIndex(m_layer); - if (layer >= 0) + LayerIndex layer = getLayerIndex(m_layer); + if (layer >= firstLayer()) showCel(layer, m_frame); } @@ -1823,21 +1811,23 @@ bool Timeline::allLayersUnlocked() return true; } -int Timeline::getLayerIndex(const Layer* layer) const +LayerIndex Timeline::getLayerIndex(const Layer* layer) const { - for (size_t i=0; ilayerToIndex(layer) == LayerIndex(i)); + return LayerIndex(i); + } - return -1; + return LayerIndex::NoLayer; } -bool Timeline::isLayerActive(int layer_index) const +bool Timeline::isLayerActive(LayerIndex layerIndex) const { - if (layer_index == getLayerIndex(m_layer)) + if (layerIndex == getLayerIndex(m_layer)) return true; else - return m_range.inRange(layer_index); + return m_range.inRange(layerIndex); } bool Timeline::isFrameActive(FrameNumber frame) const @@ -1848,6 +1838,7 @@ bool Timeline::isFrameActive(FrameNumber frame) const return m_range.inRange(frame); } +// TODO This must be re-implemented void Timeline::dropRange(DropOp op) { Range drop = m_dropRange; @@ -1885,14 +1876,14 @@ void Timeline::dropRange(DropOp op) case Range::kFrames: if (op == Timeline::kMove && m_range.frameBegin() < drop.frameBegin()) { - drop.displace(0, FrameNumber(-m_range.frames())); + drop.displace(firstLayer(), -m_range.frames()); } drop.setFrames(m_range.frames()); break; case Range::kLayers: if (op == Timeline::kMove && m_range.layerBegin() < drop.layerBegin()) { - drop.displace(-m_range.layers(), FrameNumber(0)); + drop.displace(-m_range.layers(), 0); } drop.setLayers(m_range.layers()); break; @@ -1907,10 +1898,10 @@ void Timeline::dropRange(DropOp op) void Timeline::dropCels(DropOp op, const Range& drop) { - ASSERT(drop.layerBegin() >= 0 && drop.layerBegin() < (int)m_layers.size()); - ASSERT(drop.layerEnd() >= 0 && drop.layerEnd() < (int)m_layers.size()); - ASSERT(drop.frameBegin() >= FrameNumber(0) && drop.frameBegin() < m_sprite->getTotalFrames()); - ASSERT(drop.frameEnd() >= FrameNumber(0) && drop.frameEnd() < m_sprite->getTotalFrames()); + ASSERT(validLayer(drop.layerBegin())); + ASSERT(validLayer(drop.layerEnd())); + ASSERT(validFrame(drop.frameBegin())); + ASSERT(validFrame(drop.frameEnd())); int srcLayerBegin, srcLayerStep, srcLayerEnd; int dstLayerBegin, dstLayerStep; @@ -2011,7 +2002,7 @@ void Timeline::dropFrames(DropOp op, const Range& drop) srcFrameStep = FrameNumber(-1); srcFrameEnd = m_range.frameBegin().previous(); dstFrameBegin = drop.frameBegin(); - dstFrameStep = FrameNumber(0); + dstFrameStep = firstFrame(); } break; } @@ -2043,6 +2034,7 @@ void Timeline::dropLayers(DropOp op, const Range& drop) Layer* firstLayer = m_layers[m_range.layerBegin()]; Layer* lastLayer = m_layers[m_range.layerEnd()]; + std::vector layers = m_layers; switch (op) { @@ -2104,18 +2096,19 @@ void Timeline::updateDropRange(const gfx::Point& pt) case Range::kCels: { FrameNumber dx = m_hot_frame - m_clk_frame; - int dy = m_hot_layer - m_clk_layer; - int layerIdx; + LayerIndex dy = m_hot_layer - m_clk_layer; + LayerIndex layerIdx; FrameNumber frame; layerIdx = dy+m_range.layerBegin(); - layerIdx = MID(0, layerIdx, (int)m_layers.size() - m_range.layers()); + layerIdx = MID(firstLayer(), layerIdx, LayerIndex(m_layers.size() - m_range.layers())); + frame = dx+m_range.frameBegin(); - frame = MID(FrameNumber(0), frame, m_sprite->getTotalFrames() - m_range.frames()); + frame = MID(firstFrame(), frame, m_sprite->getTotalFrames() - m_range.frames()); m_dropRange.startRange(layerIdx, frame, m_range.type()); m_dropRange.endRange( - layerIdx+m_range.layers()-1, + layerIdx+LayerIndex(m_range.layers()-1), (frame+m_range.frames()).previous()); break; } @@ -2129,19 +2122,19 @@ void Timeline::updateDropRange(const gfx::Point& pt) frameEnd = (frame + m_range.frames()).previous(); } - int layerIdx = getLayerIndex(m_layer); + LayerIndex layerIdx = getLayerIndex(m_layer); m_dropRange.startRange(layerIdx, frame, m_range.type()); m_dropRange.endRange(layerIdx, frameEnd); break; } case Range::kLayers: { - int layer = m_hot_layer; - int layerEnd = layer; + LayerIndex layer = m_hot_layer; + LayerIndex layerEnd = layer; if (layer >= m_range.layerBegin() && layer <= m_range.layerEnd()) { layer = m_range.layerBegin(); - layerEnd = layer + m_range.layers() - 1; + layerEnd = layer + LayerIndex(m_range.layers() - 1); } m_dropRange.startRange(layer, m_frame, m_range.type()); @@ -2173,14 +2166,14 @@ bool Timeline::isCopyKeyPressed(ui::Message* msg) return msg->ctrlPressed(); } -void Timeline::Range::startRange(int layer, FrameNumber frame, Type type) +void Timeline::Range::startRange(LayerIndex layer, FrameNumber frame, Type type) { m_type = type; m_layerBegin = m_layerEnd = layer; m_frameBegin = m_frameEnd = frame; } -void Timeline::Range::endRange(int layer, FrameNumber frame) +void Timeline::Range::endRange(LayerIndex layer, FrameNumber frame) { ASSERT(enabled()); m_layerEnd = layer; @@ -2192,7 +2185,7 @@ void Timeline::Range::disableRange() m_type = kNone; } -bool Timeline::Range::inRange(int layer) const +bool Timeline::Range::inRange(LayerIndex layer) const { if (enabled()) return (layer >= layerBegin() && layer <= layerEnd()); @@ -2208,15 +2201,15 @@ bool Timeline::Range::inRange(FrameNumber frame) const return false; } -bool Timeline::Range::inRange(int layer, FrameNumber frame) const +bool Timeline::Range::inRange(LayerIndex layer, FrameNumber frame) const { return inRange(layer) && inRange(frame); } void Timeline::Range::setLayers(int layers) { - if (m_layerBegin <= m_layerEnd) m_layerEnd = m_layerBegin + layers - 1; - else m_layerBegin = m_layerEnd + layers - 1; + if (m_layerBegin <= m_layerEnd) m_layerEnd = m_layerBegin + LayerIndex(layers - 1); + else m_layerBegin = m_layerEnd + LayerIndex(layers - 1); } void Timeline::Range::setFrames(FrameNumber frames) @@ -2225,12 +2218,12 @@ void Timeline::Range::setFrames(FrameNumber frames) else m_frameBegin = (m_frameEnd + frames).previous(); } -void Timeline::Range::displace(int layerDelta, FrameNumber frameDelta) +void Timeline::Range::displace(int layerDelta, int frameDelta) { - m_layerBegin += layerDelta; - m_layerEnd += layerDelta; - m_frameBegin += frameDelta; - m_frameEnd += frameDelta; + m_layerBegin += LayerIndex(layerDelta); + m_layerEnd += LayerIndex(layerDelta); + m_frameBegin += FrameNumber(frameDelta); + m_frameEnd += FrameNumber(frameDelta); } } // namespace app diff --git a/src/app/ui/timeline.h b/src/app/ui/timeline.h index 49b696d15..e3f4b9737 100644 --- a/src/app/ui/timeline.h +++ b/src/app/ui/timeline.h @@ -26,6 +26,8 @@ #include "app/ui/skin/style.h" #include "base/compiler_specific.h" #include "raster/frame_number.h" +#include "raster/layer_index.h" +#include "raster/sprite.h" #include "ui/widget.h" #include @@ -73,8 +75,8 @@ namespace app { Type type() const { return m_type; } bool enabled() const { return m_type != kNone; } - int layerBegin() const { return MIN(m_layerBegin, m_layerEnd); } - int layerEnd() const { return MAX(m_layerBegin, m_layerEnd); } + LayerIndex layerBegin() const { return MIN(m_layerBegin, m_layerEnd); } + LayerIndex layerEnd() const { return MAX(m_layerBegin, m_layerEnd); } FrameNumber frameBegin() const { return MIN(m_frameBegin, m_frameEnd); } FrameNumber frameEnd() const { return MAX(m_frameBegin, m_frameEnd); } @@ -82,14 +84,14 @@ namespace app { FrameNumber frames() const { return (frameEnd() - frameBegin()).next(); } void setLayers(int layers); void setFrames(FrameNumber frames); - void displace(int layerDelta, FrameNumber frameDelta); + void displace(int layerDelta, int frameDelta); - bool inRange(int layer) const; + bool inRange(LayerIndex layer) const; bool inRange(FrameNumber frame) const; - bool inRange(int layer, FrameNumber frame) const; + bool inRange(LayerIndex layer, FrameNumber frame) const; - void startRange(int layer, FrameNumber frame, Type type); - void endRange(int layer, FrameNumber frame); + void startRange(LayerIndex layer, FrameNumber frame, Type type); + void endRange(LayerIndex layer, FrameNumber frame); void disableRange(); bool operator==(const Range& o) const { @@ -100,8 +102,8 @@ namespace app { private: Type m_type; - int m_layerBegin; - int m_layerEnd; + LayerIndex m_layerBegin; + LayerIndex m_layerEnd; FrameNumber m_frameBegin; FrameNumber m_frameEnd; }; @@ -164,7 +166,7 @@ namespace app { HHit hhit; VHit vhit; Layer* layer; - int layer_index; + LayerIndex layerIdx; FrameNumber frame; int xpos, ypos; }; @@ -175,35 +177,35 @@ namespace app { bool allLayersUnlocked(); void detachDocument(); void setCursor(int x, int y); - void getDrawableLayers(ui::Graphics* g, int* first_layer, int* last_layer); + void getDrawableLayers(ui::Graphics* g, LayerIndex* first_layer, LayerIndex* last_layer); void getDrawableFrames(ui::Graphics* g, FrameNumber* first_frame, FrameNumber* last_frame); void drawPart(ui::Graphics* g, const gfx::Rect& bounds, const char* text, skin::Style* style, bool is_active = false, bool is_hover = false, bool is_clicked = false); void drawHeader(ui::Graphics* g); void drawHeaderFrame(ui::Graphics* g, FrameNumber frame); - void drawLayer(ui::Graphics* g, int layer_index); - void drawCel(ui::Graphics* g, int layer_index, FrameNumber frame, Cel* cel); + void drawLayer(ui::Graphics* g, LayerIndex layerIdx); + void drawCel(ui::Graphics* g, LayerIndex layerIdx, FrameNumber frame, Cel* cel); void drawLoopRange(ui::Graphics* g); void drawRangeOutline(ui::Graphics* g); void drawPaddings(ui::Graphics* g); - bool drawPart(ui::Graphics* g, int part, int layer, FrameNumber frame); + bool drawPart(ui::Graphics* g, int part, LayerIndex layer, FrameNumber frame); gfx::Rect getLayerHeadersBounds() const; gfx::Rect getFrameHeadersBounds() const; gfx::Rect getOnionskinFramesBounds() const; gfx::Rect getCelsBounds() const; - gfx::Rect getPartBounds(int part, int layer = 0, FrameNumber frame = FrameNumber(0)) const; + gfx::Rect getPartBounds(int part, LayerIndex layer = LayerIndex(0), FrameNumber frame = FrameNumber(0)) const; gfx::Rect getRangeBounds(const Range& range) const; - void invalidatePart(int part, int layer, FrameNumber frame); + void invalidatePart(int part, LayerIndex layer, FrameNumber frame); void regenerateLayers(); - void hotThis(int hot_part, int hot_layer, FrameNumber hotFrame); - void centerCel(int layer, FrameNumber frame); - void showCel(int layer, FrameNumber frame); + void hotThis(int hot_part, LayerIndex hot_layer, FrameNumber hotFrame); + void centerCel(LayerIndex layer, FrameNumber frame); + void showCel(LayerIndex layer, FrameNumber frame); void showCurrentCel(); void cleanClk(); void setScroll(int x, int y); - int getLayerIndex(const Layer* layer) const; - bool isLayerActive(int layer_index) const; + LayerIndex getLayerIndex(const Layer* layer) const; + bool isLayerActive(LayerIndex layerIdx) const; bool isFrameActive(FrameNumber frame) const; void updateStatusBar(ui::Message* msg); bool doesDropModifySprite(const Range& drop, DropOp op) const; @@ -215,6 +217,18 @@ namespace app { bool isCopyKeyPressed(ui::Message* msg); + // The layer of the bottom (e.g. Background layer) + LayerIndex firstLayer() const { return LayerIndex(0); } + + // The layer of the top. + LayerIndex lastLayer() const { return LayerIndex(m_layers.size()-1); } + + FrameNumber firstFrame() const { return FrameNumber(0); } + FrameNumber lastFrame() const { return m_sprite->getLastFrame(); } + + bool validLayer(LayerIndex layer) const { return layer >= firstLayer() && layer <= lastLayer(); } + bool validFrame(FrameNumber frame) const { return frame >= firstFrame() && frame <= lastFrame(); } + skin::Style* m_timelineStyle; skin::Style* m_timelineBoxStyle; skin::Style* m_timelineOpenEyeStyle; @@ -256,12 +270,12 @@ namespace app { int m_origFrames; // The 'hot' part is where the mouse is on top of int m_hot_part; - int m_hot_layer; + LayerIndex m_hot_layer; FrameNumber m_hot_frame; DropTarget m_dropTarget; // The 'clk' part is where the mouse's button was pressed (maybe for a drag & drop operation) int m_clk_part; - int m_clk_layer; + LayerIndex m_clk_layer; FrameNumber m_clk_frame; // Absolute mouse positions for scrolling. gfx::Point m_oldPos; diff --git a/src/raster/CMakeLists.txt b/src/raster/CMakeLists.txt index 21b6c1741..3da66e95a 100644 --- a/src/raster/CMakeLists.txt +++ b/src/raster/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(raster-lib image_io.cpp images_collector.cpp layer.cpp + layer_index.cpp layer_io.cpp mask.cpp mask_io.cpp diff --git a/src/raster/layer_index.cpp b/src/raster/layer_index.cpp new file mode 100644 index 000000000..4a8a9fdd7 --- /dev/null +++ b/src/raster/layer_index.cpp @@ -0,0 +1,29 @@ +/* Aseprite + * Copyright (C) 2001-2014 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "raster/layer_index.h" + +namespace raster { + +const LayerIndex LayerIndex::NoLayer(-1); + +} // namespace raster diff --git a/src/raster/layer_index.h b/src/raster/layer_index.h index e2cb03012..2a039d32a 100644 --- a/src/raster/layer_index.h +++ b/src/raster/layer_index.h @@ -24,6 +24,8 @@ namespace raster { class LayerIndex { public: + static const LayerIndex NoLayer; + LayerIndex() : m_value(0) { } explicit LayerIndex(int value) : m_value(value) { } @@ -38,6 +40,8 @@ namespace raster { LayerIndex& operator--() { --m_value; return *this; } LayerIndex operator++(int) { LayerIndex old(*this); ++m_value; return old; } LayerIndex operator--(int) { LayerIndex old(*this); --m_value; return old; } + LayerIndex& operator+=(const LayerIndex& o) { m_value += o.m_value; return *this; } + LayerIndex& operator-=(const LayerIndex& o) { m_value -= o.m_value; return *this; } bool operator<(const LayerIndex& o) const { return m_value < o.m_value; } bool operator>(const LayerIndex& o) const { return m_value > o.m_value; } bool operator<=(const LayerIndex& o) const { return m_value <= o.m_value; }