mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 13:32:27 +00:00
Improve context bar for slice tool (combobox of slices + action buttons)
This commit is contained in:
parent
33dc3fd354
commit
e8716cbb6e
@ -34,8 +34,7 @@ void AddSlice::onExecute()
|
|||||||
Sprite* sprite = this->sprite();
|
Sprite* sprite = this->sprite();
|
||||||
Slice* slice = this->slice();
|
Slice* slice = this->slice();
|
||||||
|
|
||||||
sprite->slices().add(slice);
|
addSlice(sprite, slice);
|
||||||
sprite->incrementVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSlice::onUndo()
|
void AddSlice::onUndo()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2019 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -10,6 +11,7 @@
|
|||||||
|
|
||||||
#include "app/cmd/set_slice_name.h"
|
#include "app/cmd/set_slice_name.h"
|
||||||
|
|
||||||
|
#include "app/doc.h"
|
||||||
#include "app/doc_event.h"
|
#include "app/doc_event.h"
|
||||||
#include "doc/document.h"
|
#include "doc/document.h"
|
||||||
#include "doc/slice.h"
|
#include "doc/slice.h"
|
||||||
@ -27,14 +29,27 @@ SetSliceName::SetSliceName(Slice* slice, const std::string& name)
|
|||||||
|
|
||||||
void SetSliceName::onExecute()
|
void SetSliceName::onExecute()
|
||||||
{
|
{
|
||||||
slice()->setName(m_newName);
|
Slice* slice = this->slice();
|
||||||
slice()->incrementVersion();
|
slice->setName(m_newName);
|
||||||
|
slice->incrementVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSliceName::onUndo()
|
void SetSliceName::onUndo()
|
||||||
{
|
{
|
||||||
slice()->setName(m_oldName);
|
Slice* slice = this->slice();
|
||||||
slice()->incrementVersion();
|
slice->setName(m_oldName);
|
||||||
|
slice->incrementVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSliceName::onFireNotifications()
|
||||||
|
{
|
||||||
|
Slice* slice = this->slice();
|
||||||
|
Sprite* sprite = slice->owner()->sprite();
|
||||||
|
Doc* doc = static_cast<Doc*>(sprite->document());
|
||||||
|
DocEvent ev(doc);
|
||||||
|
ev.sprite(sprite);
|
||||||
|
ev.slice(slice);
|
||||||
|
doc->notify_observers<DocEvent&>(&DocObserver::onSliceNameChange, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cmd
|
} // namespace cmd
|
||||||
|
@ -25,11 +25,13 @@ namespace cmd {
|
|||||||
protected:
|
protected:
|
||||||
void onExecute() override;
|
void onExecute() override;
|
||||||
void onUndo() override;
|
void onUndo() override;
|
||||||
|
void onFireNotifications() override;
|
||||||
size_t onMemSize() const override {
|
size_t onMemSize() const override {
|
||||||
return sizeof(*this);
|
return sizeof(*this)
|
||||||
|
+ m_oldName.size()
|
||||||
|
+ m_newName.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_oldName;
|
std::string m_oldName;
|
||||||
std::string m_newName;
|
std::string m_newName;
|
||||||
};
|
};
|
||||||
|
@ -182,7 +182,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void fill(bool all) {
|
void fill(bool all) {
|
||||||
removeAllItems();
|
deleteAllItems();
|
||||||
|
|
||||||
MatchWords match(getEntryWidget()->text());
|
MatchWords match(getEntryWidget()->text());
|
||||||
|
|
||||||
|
@ -898,7 +898,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void refillLanguages() {
|
void refillLanguages() {
|
||||||
language()->removeAllItems();
|
language()->deleteAllItems();
|
||||||
loadLanguages();
|
loadLanguages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,9 @@ namespace app {
|
|||||||
virtual void onSelectionChanged(DocEvent& ev) { }
|
virtual void onSelectionChanged(DocEvent& ev) { }
|
||||||
virtual void onSelectionBoundariesChanged(DocEvent& ev) { }
|
virtual void onSelectionBoundariesChanged(DocEvent& ev) { }
|
||||||
|
|
||||||
|
// Slices
|
||||||
|
virtual void onSliceNameChange(DocEvent& ev) { }
|
||||||
|
|
||||||
// Called to destroy the observable. (Here you could call "delete this".)
|
// Called to destroy the observable. (Here you could call "delete this".)
|
||||||
virtual void dispose() { }
|
virtual void dispose() { }
|
||||||
};
|
};
|
||||||
|
@ -18,9 +18,13 @@
|
|||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/commands/quick_command.h"
|
#include "app/commands/quick_command.h"
|
||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
|
#include "app/doc_event.h"
|
||||||
#include "app/ini_file.h"
|
#include "app/ini_file.h"
|
||||||
|
#include "app/match_words.h"
|
||||||
|
#include "app/modules/editors.h"
|
||||||
#include "app/pref/preferences.h"
|
#include "app/pref/preferences.h"
|
||||||
#include "app/shade.h"
|
#include "app/shade.h"
|
||||||
|
#include "app/site.h"
|
||||||
#include "app/tools/active_tool.h"
|
#include "app/tools/active_tool.h"
|
||||||
#include "app/tools/controller.h"
|
#include "app/tools/controller.h"
|
||||||
#include "app/tools/ink.h"
|
#include "app/tools/ink.h"
|
||||||
@ -34,18 +38,22 @@
|
|||||||
#include "app/ui/color_button.h"
|
#include "app/ui/color_button.h"
|
||||||
#include "app/ui/color_shades.h"
|
#include "app/ui/color_shades.h"
|
||||||
#include "app/ui/dithering_selector.h"
|
#include "app/ui/dithering_selector.h"
|
||||||
|
#include "app/ui/editor/editor.h"
|
||||||
#include "app/ui/icon_button.h"
|
#include "app/ui/icon_button.h"
|
||||||
#include "app/ui/keyboard_shortcuts.h"
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
#include "app/ui/selection_mode_field.h"
|
#include "app/ui/selection_mode_field.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
|
#include "base/fs.h"
|
||||||
#include "base/scoped_value.h"
|
#include "base/scoped_value.h"
|
||||||
#include "doc/brush.h"
|
#include "doc/brush.h"
|
||||||
#include "doc/conversion_to_surface.h"
|
#include "doc/conversion_to_surface.h"
|
||||||
#include "doc/image.h"
|
#include "doc/image.h"
|
||||||
#include "doc/palette.h"
|
#include "doc/palette.h"
|
||||||
#include "doc/remap.h"
|
#include "doc/remap.h"
|
||||||
|
#include "doc/selected_objects.h"
|
||||||
|
#include "doc/slice.h"
|
||||||
#include "obs/connection.h"
|
#include "obs/connection.h"
|
||||||
#include "os/surface.h"
|
#include "os/surface.h"
|
||||||
#include "os/system.h"
|
#include "os/system.h"
|
||||||
@ -56,6 +64,7 @@
|
|||||||
#include "ui/combobox.h"
|
#include "ui/combobox.h"
|
||||||
#include "ui/int_entry.h"
|
#include "ui/int_entry.h"
|
||||||
#include "ui/label.h"
|
#include "ui/label.h"
|
||||||
|
#include "ui/listbox.h"
|
||||||
#include "ui/listitem.h"
|
#include "ui/listitem.h"
|
||||||
#include "ui/menu.h"
|
#include "ui/menu.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
@ -66,6 +75,8 @@
|
|||||||
#include "ui/theme.h"
|
#include "ui/theme.h"
|
||||||
#include "ui/tooltips.h"
|
#include "ui/tooltips.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
using namespace app::skin;
|
using namespace app::skin;
|
||||||
@ -1139,8 +1150,247 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ContextBar::SliceFields : public HBox {
|
||||||
|
class Item : public ListItem {
|
||||||
|
public:
|
||||||
|
Item(const doc::Slice* slice)
|
||||||
|
: ListItem(slice->name())
|
||||||
|
, m_slice(slice) { }
|
||||||
|
const doc::Slice* slice() const { return m_slice; }
|
||||||
|
private:
|
||||||
|
const doc::Slice* m_slice;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Combo : public ComboBox {
|
||||||
|
SliceFields* m_sliceFields;
|
||||||
|
public:
|
||||||
|
Combo(SliceFields* sliceFields)
|
||||||
|
: m_sliceFields(sliceFields) {
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void onChange() override {
|
||||||
|
ComboBox::onChange();
|
||||||
|
m_sliceFields->onSelectSliceFromComboBox();
|
||||||
|
}
|
||||||
|
void onEntryChange() override {
|
||||||
|
ComboBox::onEntryChange();
|
||||||
|
m_sliceFields->onComboBoxEntryChange();
|
||||||
|
}
|
||||||
|
void onBeforeOpenListBox() override {
|
||||||
|
ComboBox::onBeforeOpenListBox();
|
||||||
|
m_sliceFields->fillSlices();
|
||||||
|
}
|
||||||
|
void onEnterOnEditableEntry() override {
|
||||||
|
ComboBox::onEnterOnEditableEntry();
|
||||||
|
|
||||||
|
const Slice* slice = nullptr;
|
||||||
|
if (auto item = dynamic_cast<Item*>(getSelectedItem())) {
|
||||||
|
if (item->slice()->name() == getValue()) {
|
||||||
|
slice = item->slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!slice && current_editor)
|
||||||
|
slice = current_editor->sprite()->slices().getByName(getValue());
|
||||||
|
if (slice)
|
||||||
|
m_sliceFields->scrollToSlice(slice);
|
||||||
|
|
||||||
|
closeListBox();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SliceFields()
|
||||||
|
: m_doc(nullptr)
|
||||||
|
, m_sel(2)
|
||||||
|
, m_combobox(this)
|
||||||
|
, m_action(2)
|
||||||
|
{
|
||||||
|
SkinTheme* theme = SkinTheme::instance();
|
||||||
|
|
||||||
|
m_sel.addItem("All");
|
||||||
|
m_sel.addItem("None");
|
||||||
|
m_sel.ItemChange.connect(
|
||||||
|
[this](ButtonSet::Item* item){
|
||||||
|
onSelAction(m_sel.selectedItem());
|
||||||
|
});
|
||||||
|
|
||||||
|
m_combobox.setEditable(true);
|
||||||
|
m_combobox.setExpansive(true);
|
||||||
|
m_combobox.setMinSize(gfx::Size(256*guiscale(), 0));
|
||||||
|
|
||||||
|
m_action.addItem(theme->parts.iconUserData())->setMono(true);
|
||||||
|
m_action.addItem(theme->parts.iconClose())->setMono(true);
|
||||||
|
m_action.ItemChange.connect(
|
||||||
|
[this](ButtonSet::Item* item){
|
||||||
|
onAction(m_action.selectedItem());
|
||||||
|
});
|
||||||
|
|
||||||
|
addChild(&m_sel);
|
||||||
|
addChild(&m_combobox);
|
||||||
|
addChild(&m_action);
|
||||||
|
|
||||||
|
m_combobox.setVisible(false);
|
||||||
|
m_action.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupTooltips(TooltipManager* tooltipManager) {
|
||||||
|
tooltipManager->addTooltipFor(m_sel.at(0), "Select All Slices", BOTTOM);
|
||||||
|
tooltipManager->addTooltipFor(m_sel.at(1), "Deselect Slices", BOTTOM);
|
||||||
|
tooltipManager->addTooltipFor(m_action.at(0), "Slice Properties", BOTTOM);
|
||||||
|
tooltipManager->addTooltipFor(m_action.at(1), "Delete Slice", BOTTOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDoc(Doc* doc) {
|
||||||
|
m_doc = doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addSlice(const doc::Slice* slice) {
|
||||||
|
m_changeFromEntry = true;
|
||||||
|
m_combobox.setValue(slice->name());
|
||||||
|
updateLayout();
|
||||||
|
m_changeFromEntry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeSlice(const doc::Slice* slice) {
|
||||||
|
m_combobox.setValue(std::string());
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSlice(const doc::Slice* slice) {
|
||||||
|
m_combobox.setValue(slice->name());
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectSlices(const doc::Sprite* sprite,
|
||||||
|
const doc::SelectedObjects& slices) {
|
||||||
|
if (!slices.empty()) {
|
||||||
|
auto selected = slices.frontAs<doc::Slice>();
|
||||||
|
m_combobox.setValue(selected->name());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_combobox.setValue(std::string());
|
||||||
|
}
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeComboBox() {
|
||||||
|
m_combobox.closeListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onVisible(bool visible) override {
|
||||||
|
HBox::onVisible(visible);
|
||||||
|
m_combobox.closeListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillSlices() {
|
||||||
|
m_combobox.deleteAllItems();
|
||||||
|
if (m_doc && m_doc->sprite()) {
|
||||||
|
MatchWords match(m_filter);
|
||||||
|
|
||||||
|
std::vector<doc::Slice*> slices;
|
||||||
|
for (auto slice : m_doc->sprite()->slices()) {
|
||||||
|
if (match(slice->name()))
|
||||||
|
slices.push_back(slice);
|
||||||
|
}
|
||||||
|
std::sort(slices.begin(), slices.end(),
|
||||||
|
[](const doc::Slice* a, const doc::Slice* b){
|
||||||
|
return (base::compare_filenames(a->name(), b->name()) < 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto slice : slices) {
|
||||||
|
Item* item = new Item(slice);
|
||||||
|
m_combobox.addItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollToSlice(const Slice* slice) {
|
||||||
|
if (current_editor && slice) {
|
||||||
|
if (const SliceKey* key = slice->getByFrame(current_editor->frame())) {
|
||||||
|
current_editor->centerInSpritePoint(key->bounds().center());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLayout() {
|
||||||
|
const bool visible = (m_doc && !m_doc->sprite()->slices().empty());
|
||||||
|
m_combobox.setVisible(visible);
|
||||||
|
m_action.setVisible(visible);
|
||||||
|
|
||||||
|
parent()->layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSelAction(const int item) {
|
||||||
|
m_sel.deselectItems();
|
||||||
|
switch (item) {
|
||||||
|
case 0:
|
||||||
|
if (current_editor)
|
||||||
|
current_editor->selectAllSlices();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (current_editor)
|
||||||
|
current_editor->clearSlicesSelection();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSelectSliceFromComboBox() {
|
||||||
|
if (m_changeFromEntry)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_filter.clear();
|
||||||
|
|
||||||
|
if (auto item = dynamic_cast<Item*>(m_combobox.getSelectedItem())) {
|
||||||
|
if (current_editor) {
|
||||||
|
const doc::Slice* slice = item->slice();
|
||||||
|
current_editor->clearSlicesSelection();
|
||||||
|
current_editor->selectSlice(slice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onComboBoxEntryChange() {
|
||||||
|
m_changeFromEntry = true;
|
||||||
|
m_combobox.closeListBox();
|
||||||
|
|
||||||
|
m_filter = m_combobox.getValue();
|
||||||
|
|
||||||
|
m_combobox.openListBox();
|
||||||
|
m_changeFromEntry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAction(const int item) {
|
||||||
|
m_action.deselectItems();
|
||||||
|
|
||||||
|
Command* cmd = nullptr;
|
||||||
|
Params params;
|
||||||
|
|
||||||
|
switch (item) {
|
||||||
|
case 0:
|
||||||
|
cmd = Commands::instance()->byId(CommandId::SliceProperties());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cmd = Commands::instance()->byId(CommandId::RemoveSlice());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd)
|
||||||
|
UIContext::instance()->executeCommand(cmd, params);
|
||||||
|
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
Doc* m_doc;
|
||||||
|
ButtonSet m_sel;
|
||||||
|
Combo m_combobox;
|
||||||
|
ButtonSet m_action;
|
||||||
|
bool m_changeFromEntry;
|
||||||
|
std::string m_filter;
|
||||||
|
};
|
||||||
|
|
||||||
ContextBar::ContextBar(TooltipManager* tooltipManager)
|
ContextBar::ContextBar(TooltipManager* tooltipManager)
|
||||||
: Box(HORIZONTAL)
|
|
||||||
{
|
{
|
||||||
addChild(m_selectionOptionsBox = new HBox());
|
addChild(m_selectionOptionsBox = new HBox());
|
||||||
m_selectionOptionsBox->addChild(m_dropPixels = new DropPixelsField());
|
m_selectionOptionsBox->addChild(m_dropPixels = new DropPixelsField());
|
||||||
@ -1174,10 +1424,6 @@ ContextBar::ContextBar(TooltipManager* tooltipManager)
|
|||||||
|
|
||||||
addChild(m_autoSelectLayer = new AutoSelectLayerField());
|
addChild(m_autoSelectLayer = new AutoSelectLayerField());
|
||||||
|
|
||||||
// addChild(new InkChannelTargetField());
|
|
||||||
// addChild(new InkShadeField());
|
|
||||||
// addChild(new InkSelectionField());
|
|
||||||
|
|
||||||
addChild(m_sprayBox = new HBox());
|
addChild(m_sprayBox = new HBox());
|
||||||
m_sprayBox->addChild(m_sprayLabel = new Label("Spray:"));
|
m_sprayBox->addChild(m_sprayLabel = new Label("Spray:"));
|
||||||
m_sprayBox->addChild(m_sprayWidth = new SprayWidthField());
|
m_sprayBox->addChild(m_sprayWidth = new SprayWidthField());
|
||||||
@ -1191,9 +1437,12 @@ ContextBar::ContextBar(TooltipManager* tooltipManager)
|
|||||||
addChild(m_symmetry = new SymmetryField());
|
addChild(m_symmetry = new SymmetryField());
|
||||||
m_symmetry->setVisible(Preferences::instance().symmetryMode.enabled());
|
m_symmetry->setVisible(Preferences::instance().symmetryMode.enabled());
|
||||||
|
|
||||||
|
addChild(m_sliceFields = new SliceFields);
|
||||||
|
|
||||||
setupTooltips(tooltipManager);
|
setupTooltips(tooltipManager);
|
||||||
|
|
||||||
App::instance()->activeToolManager()->add_observer(this);
|
App::instance()->activeToolManager()->add_observer(this);
|
||||||
|
UIContext::instance()->add_observer(this);
|
||||||
|
|
||||||
auto& pref = Preferences::instance();
|
auto& pref = Preferences::instance();
|
||||||
pref.symmetryMode.enabled.AfterChange.connect(
|
pref.symmetryMode.enabled.AfterChange.connect(
|
||||||
@ -1216,6 +1465,7 @@ ContextBar::ContextBar(TooltipManager* tooltipManager)
|
|||||||
|
|
||||||
ContextBar::~ContextBar()
|
ContextBar::~ContextBar()
|
||||||
{
|
{
|
||||||
|
UIContext::instance()->remove_observer(this);
|
||||||
App::instance()->activeToolManager()->remove_observer(this);
|
App::instance()->activeToolManager()->remove_observer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,6 +1515,40 @@ void ContextBar::onToolSetContiguous()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ContextBar::onActiveSiteChange(const Site& site)
|
||||||
|
{
|
||||||
|
DocObserverWidget<ui::HBox>::onActiveSiteChange(site);
|
||||||
|
if (site.sprite())
|
||||||
|
m_sliceFields->selectSlices(site.sprite(),
|
||||||
|
site.selectedSlices());
|
||||||
|
else
|
||||||
|
m_sliceFields->closeComboBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextBar::onDocChange(Doc* doc)
|
||||||
|
{
|
||||||
|
DocObserverWidget<ui::HBox>::onDocChange(doc);
|
||||||
|
m_sliceFields->setDoc(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextBar::onAddSlice(DocEvent& ev)
|
||||||
|
{
|
||||||
|
if (ev.slice())
|
||||||
|
m_sliceFields->addSlice(ev.slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextBar::onRemoveSlice(DocEvent& ev)
|
||||||
|
{
|
||||||
|
if (ev.slice())
|
||||||
|
m_sliceFields->removeSlice(ev.slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextBar::onSliceNameChange(DocEvent& ev)
|
||||||
|
{
|
||||||
|
if (ev.slice())
|
||||||
|
m_sliceFields->updateSlice(ev.slice());
|
||||||
|
}
|
||||||
|
|
||||||
void ContextBar::onBrushSizeChange()
|
void ContextBar::onBrushSizeChange()
|
||||||
{
|
{
|
||||||
if (m_activeBrush->type() != kImageBrushType)
|
if (m_activeBrush->type() != kImageBrushType)
|
||||||
@ -1438,6 +1722,11 @@ void ContextBar::updateForTool(tools::Tool* tool)
|
|||||||
(tool->getInk(0)->isCelMovement() ||
|
(tool->getInk(0)->isCelMovement() ||
|
||||||
tool->getInk(1)->isCelMovement());
|
tool->getInk(1)->isCelMovement());
|
||||||
|
|
||||||
|
// True if the current tool is slice tool.
|
||||||
|
const bool isSlice = tool &&
|
||||||
|
(tool->getInk(0)->isSlice() ||
|
||||||
|
tool->getInk(1)->isSlice());
|
||||||
|
|
||||||
// True if the current tool is floodfill
|
// True if the current tool is floodfill
|
||||||
const bool isFloodfill = tool &&
|
const bool isFloodfill = tool &&
|
||||||
(tool->getPointShape(0)->isFloodFill() ||
|
(tool->getPointShape(0)->isFloodFill() ||
|
||||||
@ -1502,6 +1791,8 @@ void ContextBar::updateForTool(tools::Tool* tool)
|
|||||||
(isPaint || isEffect || hasSelectOptions));
|
(isPaint || isEffect || hasSelectOptions));
|
||||||
m_symmetry->updateWithCurrentDocument();
|
m_symmetry->updateWithCurrentDocument();
|
||||||
|
|
||||||
|
m_sliceFields->setVisible(isSlice);
|
||||||
|
|
||||||
// Update ink shades with the current selected palette entries
|
// Update ink shades with the current selected palette entries
|
||||||
if (updateShade)
|
if (updateShade)
|
||||||
m_inkShades->updateShadeFromColorBarPicks();
|
m_inkShades->updateShadeFromColorBarPicks();
|
||||||
@ -1815,6 +2106,7 @@ void ContextBar::setupTooltips(TooltipManager* tooltipManager)
|
|||||||
m_gradientType->setupTooltips(tooltipManager);
|
m_gradientType->setupTooltips(tooltipManager);
|
||||||
m_dropPixels->setupTooltips(tooltipManager);
|
m_dropPixels->setupTooltips(tooltipManager);
|
||||||
m_symmetry->setupTooltips(tooltipManager);
|
m_symmetry->setupTooltips(tooltipManager);
|
||||||
|
m_sliceFields->setupTooltips(tooltipManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextBar::registerCommands()
|
void ContextBar::registerCommands()
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "app/tools/ink_type.h"
|
#include "app/tools/ink_type.h"
|
||||||
#include "app/tools/tool_loop_modifiers.h"
|
#include "app/tools/tool_loop_modifiers.h"
|
||||||
#include "app/ui/context_bar_observer.h"
|
#include "app/ui/context_bar_observer.h"
|
||||||
|
#include "app/ui/doc_observer_widget.h"
|
||||||
#include "doc/brush.h"
|
#include "doc/brush.h"
|
||||||
#include "obs/connection.h"
|
#include "obs/connection.h"
|
||||||
#include "obs/observable.h"
|
#include "obs/observable.h"
|
||||||
@ -51,7 +52,7 @@ namespace app {
|
|||||||
class DitheringSelector;
|
class DitheringSelector;
|
||||||
class GradientTypeSelector;
|
class GradientTypeSelector;
|
||||||
|
|
||||||
class ContextBar : public ui::Box
|
class ContextBar : public DocObserverWidget<ui::HBox>
|
||||||
, public obs::observable<ContextBarObserver>
|
, public obs::observable<ContextBarObserver>
|
||||||
, public tools::ActiveToolObserver {
|
, public tools::ActiveToolObserver {
|
||||||
public:
|
public:
|
||||||
@ -97,6 +98,17 @@ namespace app {
|
|||||||
void onToolSetFreehandAlgorithm();
|
void onToolSetFreehandAlgorithm();
|
||||||
void onToolSetContiguous();
|
void onToolSetContiguous();
|
||||||
|
|
||||||
|
// ContextObserver impl
|
||||||
|
void onActiveSiteChange(const Site& site) override;
|
||||||
|
|
||||||
|
// DocObserverWidget overrides
|
||||||
|
void onDocChange(Doc* doc) override;
|
||||||
|
|
||||||
|
// DocObserver impl
|
||||||
|
void onAddSlice(DocEvent& ev) override;
|
||||||
|
void onRemoveSlice(DocEvent& ev) override;
|
||||||
|
void onSliceNameChange(DocEvent& ev) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onBrushSizeChange();
|
void onBrushSizeChange();
|
||||||
void onBrushAngleChange();
|
void onBrushAngleChange();
|
||||||
@ -135,6 +147,7 @@ namespace app {
|
|||||||
class DropPixelsField;
|
class DropPixelsField;
|
||||||
class AutoSelectLayerField;
|
class AutoSelectLayerField;
|
||||||
class SymmetryField;
|
class SymmetryField;
|
||||||
|
class SliceFields;
|
||||||
|
|
||||||
ZoomButtons* m_zoomButtons;
|
ZoomButtons* m_zoomButtons;
|
||||||
BrushBackField* m_brushBack;
|
BrushBackField* m_brushBack;
|
||||||
@ -169,6 +182,7 @@ namespace app {
|
|||||||
doc::BrushRef m_activeBrush;
|
doc::BrushRef m_activeBrush;
|
||||||
ui::Label* m_selectBoxHelp;
|
ui::Label* m_selectBoxHelp;
|
||||||
SymmetryField* m_symmetry;
|
SymmetryField* m_symmetry;
|
||||||
|
SliceFields* m_sliceFields;
|
||||||
obs::scoped_connection m_sizeConn;
|
obs::scoped_connection m_sizeConn;
|
||||||
obs::scoped_connection m_angleConn;
|
obs::scoped_connection m_angleConn;
|
||||||
obs::scoped_connection m_opacityConn;
|
obs::scoped_connection m_opacityConn;
|
||||||
|
@ -181,7 +181,7 @@ DitheringSelector::DitheringSelector(Type type)
|
|||||||
|
|
||||||
void DitheringSelector::regenerate()
|
void DitheringSelector::regenerate()
|
||||||
{
|
{
|
||||||
removeAllItems();
|
deleteAllItems();
|
||||||
|
|
||||||
Extensions& extensions = App::instance()->extensions();
|
Extensions& extensions = App::instance()->extensions();
|
||||||
auto ditheringMatrices = extensions.ditheringMatrices();
|
auto ditheringMatrices = extensions.ditheringMatrices();
|
||||||
|
90
src/app/ui/doc_observer_widget.h
Normal file
90
src/app/ui/doc_observer_widget.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_UI_DOC_OBSERVER_WIDGET_H_INCLUDED
|
||||||
|
#define APP_UI_DOC_OBSERVER_WIDGET_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "app/context_observer.h"
|
||||||
|
#include "app/doc.h"
|
||||||
|
#include "app/doc_observer.h"
|
||||||
|
#include "app/docs_observer.h"
|
||||||
|
#include "app/site.h"
|
||||||
|
#include "app/ui_context.h"
|
||||||
|
#include "base/debug.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
// A widget that observes the active document.
|
||||||
|
template<typename BaseWidget>
|
||||||
|
class DocObserverWidget : public BaseWidget
|
||||||
|
, public ContextObserver
|
||||||
|
, public DocsObserver
|
||||||
|
, public DocObserver {
|
||||||
|
public:
|
||||||
|
template<typename... Args>
|
||||||
|
DocObserverWidget(Args&&... args)
|
||||||
|
: BaseWidget(std::forward<Args>(args)...)
|
||||||
|
, m_doc(nullptr) {
|
||||||
|
UIContext::instance()->add_observer(this);
|
||||||
|
UIContext::instance()->documents().add_observer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DocObserverWidget() {
|
||||||
|
ASSERT(!m_doc);
|
||||||
|
UIContext::instance()->documents().remove_observer(this);
|
||||||
|
UIContext::instance()->remove_observer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Doc* doc() const { return m_doc; }
|
||||||
|
|
||||||
|
virtual void onDocChange(Doc* doc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextObserver impl
|
||||||
|
void onActiveSiteChange(const Site& site) override {
|
||||||
|
if (m_doc && site.document() != m_doc) {
|
||||||
|
m_doc->remove_observer(this);
|
||||||
|
m_doc = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (site.document() && site.sprite()) {
|
||||||
|
if (!m_doc) {
|
||||||
|
m_doc = const_cast<Doc*>(site.document());
|
||||||
|
m_doc->add_observer(this);
|
||||||
|
|
||||||
|
onDocChange(m_doc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSERT(m_doc == site.document());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSERT(m_doc == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocsObservers impl
|
||||||
|
void onRemoveDocument(Doc* doc) override {
|
||||||
|
if (m_doc &&
|
||||||
|
m_doc == doc) {
|
||||||
|
m_doc->remove_observer(this);
|
||||||
|
m_doc = nullptr;
|
||||||
|
|
||||||
|
onDocChange(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The DocObserver impl will be in the derived class.
|
||||||
|
|
||||||
|
private:
|
||||||
|
Doc* m_doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
@ -559,6 +559,16 @@ bool DocView::onPaste(Context* ctx)
|
|||||||
|
|
||||||
bool DocView::onClear(Context* ctx)
|
bool DocView::onClear(Context* ctx)
|
||||||
{
|
{
|
||||||
|
// First we check if there is a selected slice, so we'll delete
|
||||||
|
// those slices.
|
||||||
|
Site site = ctx->activeSite();
|
||||||
|
if (!site.selectedSlices().empty()) {
|
||||||
|
Command* removeSlices = Commands::instance()->byId(CommandId::RemoveSlice());
|
||||||
|
ctx->executeCommand(removeSlices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In other case we delete the mask or the cel.
|
||||||
ContextWriter writer(ctx);
|
ContextWriter writer(ctx);
|
||||||
Doc* document = writer.document();
|
Doc* document = writer.document();
|
||||||
bool visibleMask = document->isMaskVisible();
|
bool visibleMask = document->isMaskVisible();
|
||||||
|
@ -380,8 +380,10 @@ void Editor::getSite(Site* site) const
|
|||||||
site->sprite(m_sprite);
|
site->sprite(m_sprite);
|
||||||
site->layer(m_layer);
|
site->layer(m_layer);
|
||||||
site->frame(m_frame);
|
site->frame(m_frame);
|
||||||
if (!m_selectedSlices.empty())
|
if (!m_selectedSlices.empty() &&
|
||||||
|
getCurrentEditorInk()->isSlice()) {
|
||||||
site->selectedSlices(m_selectedSlices);
|
site->selectedSlices(m_selectedSlices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Site Editor::getSite() const
|
Site Editor::getSite() const
|
||||||
@ -1308,12 +1310,12 @@ gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir)
|
|||||||
return mousePos;
|
return mousePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
tools::Tool* Editor::getCurrentEditorTool()
|
tools::Tool* Editor::getCurrentEditorTool() const
|
||||||
{
|
{
|
||||||
return App::instance()->activeTool();
|
return App::instance()->activeTool();
|
||||||
}
|
}
|
||||||
|
|
||||||
tools::Ink* Editor::getCurrentEditorInk()
|
tools::Ink* Editor::getCurrentEditorInk() const
|
||||||
{
|
{
|
||||||
tools::Ink* ink = m_state->getStateInk();
|
tools::Ink* ink = m_state->getStateInk();
|
||||||
if (ink)
|
if (ink)
|
||||||
@ -1629,8 +1631,13 @@ bool Editor::isSliceSelected(const doc::Slice* slice) const
|
|||||||
|
|
||||||
void Editor::clearSlicesSelection()
|
void Editor::clearSlicesSelection()
|
||||||
{
|
{
|
||||||
m_selectedSlices.clear();
|
if (!m_selectedSlices.empty()) {
|
||||||
invalidate();
|
m_selectedSlices.clear();
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (isActive())
|
||||||
|
UIContext::instance()->notifyActiveSiteChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::selectSlice(const doc::Slice* slice)
|
void Editor::selectSlice(const doc::Slice* slice)
|
||||||
@ -1638,6 +1645,9 @@ void Editor::selectSlice(const doc::Slice* slice)
|
|||||||
ASSERT(slice);
|
ASSERT(slice);
|
||||||
m_selectedSlices.insert(slice->id());
|
m_selectedSlices.insert(slice->id());
|
||||||
invalidate();
|
invalidate();
|
||||||
|
|
||||||
|
if (isActive())
|
||||||
|
UIContext::instance()->notifyActiveSiteChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Editor::selectSliceBox(const gfx::Rect& box)
|
bool Editor::selectSliceBox(const gfx::Rect& box)
|
||||||
@ -1649,12 +1659,26 @@ bool Editor::selectSliceBox(const gfx::Rect& box)
|
|||||||
m_selectedSlices.insert(slice->id());
|
m_selectedSlices.insert(slice->id());
|
||||||
}
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
|
|
||||||
|
if (isActive())
|
||||||
|
UIContext::instance()->notifyActiveSiteChanged();
|
||||||
|
|
||||||
return !m_selectedSlices.empty();
|
return !m_selectedSlices.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Editor::selectAllSlices()
|
||||||
|
{
|
||||||
|
for (auto slice : m_sprite->slices())
|
||||||
|
m_selectedSlices.insert(slice->id());
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (isActive())
|
||||||
|
UIContext::instance()->notifyActiveSiteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void Editor::cancelSelections()
|
void Editor::cancelSelections()
|
||||||
{
|
{
|
||||||
m_selectedSlices.clear();
|
clearSlicesSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -201,8 +201,8 @@ namespace app {
|
|||||||
// Control scroll when cursor goes out of the editor viewport.
|
// Control scroll when cursor goes out of the editor viewport.
|
||||||
gfx::Point autoScroll(ui::MouseMessage* msg, AutoScroll dir);
|
gfx::Point autoScroll(ui::MouseMessage* msg, AutoScroll dir);
|
||||||
|
|
||||||
tools::Tool* getCurrentEditorTool();
|
tools::Tool* getCurrentEditorTool() const;
|
||||||
tools::Ink* getCurrentEditorInk();
|
tools::Ink* getCurrentEditorInk() const;
|
||||||
|
|
||||||
tools::ToolLoopModifiers getToolLoopModifiers() const { return m_toolLoopModifiers; }
|
tools::ToolLoopModifiers getToolLoopModifiers() const { return m_toolLoopModifiers; }
|
||||||
bool isAutoSelectLayer();
|
bool isAutoSelectLayer();
|
||||||
@ -283,6 +283,7 @@ namespace app {
|
|||||||
void clearSlicesSelection();
|
void clearSlicesSelection();
|
||||||
void selectSlice(const doc::Slice* slice);
|
void selectSlice(const doc::Slice* slice);
|
||||||
bool selectSliceBox(const gfx::Rect& box);
|
bool selectSliceBox(const gfx::Rect& box);
|
||||||
|
void selectAllSlices();
|
||||||
bool hasSelectedSlices() const { return !m_selectedSlices.empty(); }
|
bool hasSelectedSlices() const { return !m_selectedSlices.empty(); }
|
||||||
|
|
||||||
// Called by DocView's InputChainElement::onCancel() impl when Esc
|
// Called by DocView's InputChainElement::onCancel() impl when Esc
|
||||||
|
@ -123,7 +123,7 @@ namespace app {
|
|||||||
virtual bool acceptQuickTool(tools::Tool* tool) { return true; }
|
virtual bool acceptQuickTool(tools::Tool* tool) { return true; }
|
||||||
|
|
||||||
// Custom ink in this state.
|
// Custom ink in this state.
|
||||||
virtual tools::Ink* getStateInk() { return nullptr; }
|
virtual tools::Ink* getStateInk() const { return nullptr; }
|
||||||
|
|
||||||
// Called when a tag is deleted.
|
// Called when a tag is deleted.
|
||||||
virtual void onRemoveFrameTag(Editor* editor, doc::FrameTag* tag) { }
|
virtual void onRemoveFrameTag(Editor* editor, doc::FrameTag* tag) { }
|
||||||
|
@ -303,7 +303,7 @@ bool SelectBoxState::requireBrushPreview()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tools::Ink* SelectBoxState::getStateInk()
|
tools::Ink* SelectBoxState::getStateInk() const
|
||||||
{
|
{
|
||||||
if (hasFlag(Flags::QuickBox))
|
if (hasFlag(Flags::QuickBox))
|
||||||
return App::instance()->toolBox()->getInkById(
|
return App::instance()->toolBox()->getInkById(
|
||||||
|
@ -98,7 +98,7 @@ namespace app {
|
|||||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||||
virtual bool acceptQuickTool(tools::Tool* tool) override;
|
virtual bool acceptQuickTool(tools::Tool* tool) override;
|
||||||
virtual bool requireBrushPreview() override;
|
virtual bool requireBrushPreview() override;
|
||||||
virtual tools::Ink* getStateInk() override;
|
virtual tools::Ink* getStateInk() const override;
|
||||||
|
|
||||||
// EditorDecorator overrides
|
// EditorDecorator overrides
|
||||||
virtual void postRenderDecorator(EditorPostRender* render) override;
|
virtual void postRenderDecorator(EditorPostRender* render) override;
|
||||||
|
@ -242,6 +242,7 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||||||
// If we click outside all slices, we clear the selection of slices.
|
// If we click outside all slices, we clear the selection of slices.
|
||||||
if (!hit.slice() || !site.selectedSlices().contains(hit.slice()->id())) {
|
if (!hit.slice() || !site.selectedSlices().contains(hit.slice()->id())) {
|
||||||
editor->clearSlicesSelection();
|
editor->clearSlicesSelection();
|
||||||
|
editor->selectSlice(hit.slice());
|
||||||
|
|
||||||
site = Site();
|
site = Site();
|
||||||
editor->getSite(&site);
|
editor->getSite(&site);
|
||||||
|
@ -127,7 +127,7 @@ protected:
|
|||||||
if (m_fileList->multipleSelection())
|
if (m_fileList->multipleSelection())
|
||||||
m_fileList->deselectedFileItems();
|
m_fileList->deselectedFileItems();
|
||||||
|
|
||||||
removeAllItems();
|
deleteAllItems();
|
||||||
|
|
||||||
// String to be autocompleted
|
// String to be autocompleted
|
||||||
std::string left_part = getEntryWidget()->text();
|
std::string left_part = getEntryWidget()->text();
|
||||||
@ -413,7 +413,7 @@ bool FileSelector::show(
|
|||||||
updateNavigationButtons();
|
updateNavigationButtons();
|
||||||
|
|
||||||
// fill file-type combo-box
|
// fill file-type combo-box
|
||||||
fileType()->removeAllItems();
|
fileType()->deleteAllItems();
|
||||||
|
|
||||||
// Get the default extension from the given initial file name
|
// Get the default extension from the given initial file name
|
||||||
if (m_defExtension.empty())
|
if (m_defExtension.empty())
|
||||||
@ -662,7 +662,7 @@ void FileSelector::updateLocation()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the items from the combo-box
|
// Clear all the items from the combo-box
|
||||||
location()->removeAllItems();
|
location()->deleteAllItems();
|
||||||
|
|
||||||
// Add item by item (from root to the specific current folder)
|
// Add item by item (from root to the specific current folder)
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
@ -542,7 +542,6 @@ StatusBar::StatusBar(TooltipManager* tooltipManager)
|
|||||||
: m_timeout(0)
|
: m_timeout(0)
|
||||||
, m_indicators(new Indicators)
|
, m_indicators(new Indicators)
|
||||||
, m_docControls(new HBox)
|
, m_docControls(new HBox)
|
||||||
, m_doc(nullptr)
|
|
||||||
, m_tipwindow(nullptr)
|
, m_tipwindow(nullptr)
|
||||||
, m_snapToGridWindow(nullptr)
|
, m_snapToGridWindow(nullptr)
|
||||||
{
|
{
|
||||||
@ -586,8 +585,6 @@ StatusBar::StatusBar(TooltipManager* tooltipManager)
|
|||||||
tooltipManager->addTooltipFor(m_zoomEntry, "Zoom Level", BOTTOM);
|
tooltipManager->addTooltipFor(m_zoomEntry, "Zoom Level", BOTTOM);
|
||||||
tooltipManager->addTooltipFor(m_newFrame, "New Frame", BOTTOM);
|
tooltipManager->addTooltipFor(m_newFrame, "New Frame", BOTTOM);
|
||||||
|
|
||||||
UIContext::instance()->add_observer(this);
|
|
||||||
UIContext::instance()->documents().add_observer(this);
|
|
||||||
App::instance()->activeToolManager()->add_observer(this);
|
App::instance()->activeToolManager()->add_observer(this);
|
||||||
|
|
||||||
initTheme();
|
initTheme();
|
||||||
@ -596,8 +593,6 @@ StatusBar::StatusBar(TooltipManager* tooltipManager)
|
|||||||
StatusBar::~StatusBar()
|
StatusBar::~StatusBar()
|
||||||
{
|
{
|
||||||
App::instance()->activeToolManager()->remove_observer(this);
|
App::instance()->activeToolManager()->remove_observer(this);
|
||||||
UIContext::instance()->documents().remove_observer(this);
|
|
||||||
UIContext::instance()->remove_observer(this);
|
|
||||||
|
|
||||||
delete m_tipwindow; // widget
|
delete m_tipwindow; // widget
|
||||||
delete m_snapToGridWindow;
|
delete m_snapToGridWindow;
|
||||||
@ -719,9 +714,10 @@ void StatusBar::showTool(int msecs, tools::Tool* tool)
|
|||||||
void StatusBar::showSnapToGridWarning(bool state)
|
void StatusBar::showSnapToGridWarning(bool state)
|
||||||
{
|
{
|
||||||
if (state) {
|
if (state) {
|
||||||
// m_doc can be null if "snap to grid" command is pressed without
|
// this->doc() can be nullptr if "snap to grid" command is pressed
|
||||||
// an opened document. (E.g. to change the default setting)
|
// without an opened document. (E.g. to change the default
|
||||||
if (!m_doc)
|
// setting)
|
||||||
|
if (!doc())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_snapToGridWindow)
|
if (!m_snapToGridWindow)
|
||||||
@ -733,7 +729,7 @@ void StatusBar::showSnapToGridWarning(bool state)
|
|||||||
updateSnapToGridWindowPosition();
|
updateSnapToGridWindowPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_snapToGridWindow->setDocument(m_doc);
|
m_snapToGridWindow->setDocument(doc());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (m_snapToGridWindow)
|
if (m_snapToGridWindow)
|
||||||
@ -768,7 +764,7 @@ void StatusBar::onInitTheme(ui::InitThemeEvent& ev)
|
|||||||
void StatusBar::onResize(ResizeEvent& ev)
|
void StatusBar::onResize(ResizeEvent& ev)
|
||||||
{
|
{
|
||||||
Rect rc = ev.bounds();
|
Rect rc = ev.bounds();
|
||||||
m_docControls->setVisible(m_doc && rc.w > 300*ui::guiscale());
|
m_docControls->setVisible(doc() && rc.w > 300*ui::guiscale());
|
||||||
|
|
||||||
HBox::onResize(ev);
|
HBox::onResize(ev);
|
||||||
|
|
||||||
@ -779,21 +775,10 @@ void StatusBar::onResize(ResizeEvent& ev)
|
|||||||
|
|
||||||
void StatusBar::onActiveSiteChange(const Site& site)
|
void StatusBar::onActiveSiteChange(const Site& site)
|
||||||
{
|
{
|
||||||
if (m_doc && site.document() != m_doc) {
|
DocObserverWidget<ui::HBox>::onActiveSiteChange(site);
|
||||||
m_doc->remove_observer(this);
|
|
||||||
m_doc = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (site.document() && site.sprite()) {
|
if (doc()) {
|
||||||
if (!m_doc) {
|
auto& docPref = Preferences::instance().document(doc());
|
||||||
m_doc = const_cast<Doc*>(site.document());
|
|
||||||
m_doc->add_observer(this);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ASSERT(m_doc == site.document());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& docPref = Preferences::instance().document(m_doc);
|
|
||||||
|
|
||||||
m_docControls->setVisible(true);
|
m_docControls->setVisible(true);
|
||||||
showSnapToGridWarning(docPref.grid.snap());
|
showSnapToGridWarning(docPref.grid.snap());
|
||||||
@ -803,22 +788,12 @@ void StatusBar::onActiveSiteChange(const Site& site)
|
|||||||
"%d", site.frame()+docPref.timeline.firstFrame());
|
"%d", site.frame()+docPref.timeline.firstFrame());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ASSERT(m_doc == nullptr);
|
|
||||||
m_docControls->setVisible(false);
|
m_docControls->setVisible(false);
|
||||||
showSnapToGridWarning(false);
|
showSnapToGridWarning(false);
|
||||||
}
|
}
|
||||||
layout();
|
layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusBar::onRemoveDocument(Doc* doc)
|
|
||||||
{
|
|
||||||
if (m_doc &&
|
|
||||||
m_doc == doc) {
|
|
||||||
m_doc->remove_observer(this);
|
|
||||||
m_doc = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusBar::onPixelFormatChanged(DocEvent& ev)
|
void StatusBar::onPixelFormatChanged(DocEvent& ev)
|
||||||
{
|
{
|
||||||
// If this is called from the non-UI thread it means that the pixel
|
// If this is called from the non-UI thread it means that the pixel
|
||||||
|
@ -11,9 +11,8 @@
|
|||||||
|
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "app/context_observer.h"
|
#include "app/context_observer.h"
|
||||||
#include "app/doc_observer.h"
|
|
||||||
#include "app/docs_observer.h"
|
|
||||||
#include "app/tools/active_tool_observer.h"
|
#include "app/tools/active_tool_observer.h"
|
||||||
|
#include "app/ui/doc_observer_widget.h"
|
||||||
#include "base/time.h"
|
#include "base/time.h"
|
||||||
#include "ui/base.h"
|
#include "ui/base.h"
|
||||||
#include "ui/box.h"
|
#include "ui/box.h"
|
||||||
@ -43,10 +42,7 @@ namespace app {
|
|||||||
class Tool;
|
class Tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StatusBar : public ui::HBox
|
class StatusBar : public DocObserverWidget<ui::HBox>
|
||||||
, public ContextObserver
|
|
||||||
, public DocsObserver
|
|
||||||
, public DocObserver
|
|
||||||
, public tools::ActiveToolObserver {
|
, public tools::ActiveToolObserver {
|
||||||
static StatusBar* m_instance;
|
static StatusBar* m_instance;
|
||||||
public:
|
public:
|
||||||
@ -79,9 +75,6 @@ namespace app {
|
|||||||
// ContextObserver impl
|
// ContextObserver impl
|
||||||
void onActiveSiteChange(const Site& site) override;
|
void onActiveSiteChange(const Site& site) override;
|
||||||
|
|
||||||
// DocObservers impl
|
|
||||||
void onRemoveDocument(Doc* doc) override;
|
|
||||||
|
|
||||||
// DocObserver impl
|
// DocObserver impl
|
||||||
void onPixelFormatChanged(DocEvent& ev) override;
|
void onPixelFormatChanged(DocEvent& ev) override;
|
||||||
|
|
||||||
@ -108,7 +101,6 @@ namespace app {
|
|||||||
ui::Entry* m_currentFrame; // Current frame and go to frame entry
|
ui::Entry* m_currentFrame; // Current frame and go to frame entry
|
||||||
ui::Button* m_newFrame; // Button to create a new frame
|
ui::Button* m_newFrame; // Button to create a new frame
|
||||||
ZoomEntry* m_zoomEntry;
|
ZoomEntry* m_zoomEntry;
|
||||||
Doc* m_doc; // Document used to show the cel slider
|
|
||||||
|
|
||||||
// Tip window
|
// Tip window
|
||||||
class CustomizedTipWindow;
|
class CustomizedTipWindow;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2018 Igara Studio S.A.
|
// Copyright (C) 2018-2019 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -48,6 +48,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool onProcessMessage(Message* msg) override;
|
bool onProcessMessage(Message* msg) override;
|
||||||
void onPaint(PaintEvent& ev) override;
|
void onPaint(PaintEvent& ev) override;
|
||||||
|
void onChange() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ComboBox* m_comboBox;
|
ComboBox* m_comboBox;
|
||||||
@ -112,7 +113,7 @@ ComboBox::ComboBox()
|
|||||||
ComboBox::~ComboBox()
|
ComboBox::~ComboBox()
|
||||||
{
|
{
|
||||||
removeMessageFilters();
|
removeMessageFilters();
|
||||||
removeAllItems();
|
deleteAllItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComboBox::setEditable(bool state)
|
void ComboBox::setEditable(bool state)
|
||||||
@ -186,7 +187,7 @@ void ComboBox::removeItem(Widget* item)
|
|||||||
// Do not delete the given "item"
|
// Do not delete the given "item"
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComboBox::removeItem(int itemIndex)
|
void ComboBox::deleteItem(int itemIndex)
|
||||||
{
|
{
|
||||||
ASSERT(itemIndex >= 0 && (std::size_t)itemIndex < m_items.size());
|
ASSERT(itemIndex >= 0 && (std::size_t)itemIndex < m_items.size());
|
||||||
|
|
||||||
@ -196,7 +197,7 @@ void ComboBox::removeItem(int itemIndex)
|
|||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComboBox::removeAllItems()
|
void ComboBox::deleteAllItems()
|
||||||
{
|
{
|
||||||
for (Widget* item : m_items)
|
for (Widget* item : m_items)
|
||||||
delete item; // widget
|
delete item; // widget
|
||||||
@ -210,7 +211,7 @@ int ComboBox::getItemCount() const
|
|||||||
return m_items.size();
|
return m_items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* ComboBox::getItem(int itemIndex)
|
Widget* ComboBox::getItem(const int itemIndex) const
|
||||||
{
|
{
|
||||||
if (itemIndex >= 0 && (std::size_t)itemIndex < m_items.size()) {
|
if (itemIndex >= 0 && (std::size_t)itemIndex < m_items.size()) {
|
||||||
return m_items[itemIndex];
|
return m_items[itemIndex];
|
||||||
@ -268,7 +269,7 @@ int ComboBox::findItemIndexByValue(const std::string& value) const
|
|||||||
|
|
||||||
Widget* ComboBox::getSelectedItem() const
|
Widget* ComboBox::getSelectedItem() const
|
||||||
{
|
{
|
||||||
return (!m_items.empty() ? m_items[m_selected]: NULL);
|
return getItem(m_selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComboBox::setSelectedItem(Widget* item)
|
void ComboBox::setSelectedItem(Widget* item)
|
||||||
@ -467,6 +468,10 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (scancode == kKeyEnter ||
|
||||||
|
scancode == kKeyEnterPad) {
|
||||||
|
m_comboBox->onEnterOnEditableEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -538,6 +543,15 @@ void ComboBoxEntry::onPaint(PaintEvent& ev)
|
|||||||
theme()->paintComboBoxEntry(ev);
|
theme()->paintComboBoxEntry(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComboBoxEntry::onChange()
|
||||||
|
{
|
||||||
|
Entry::onChange();
|
||||||
|
if (m_comboBox &&
|
||||||
|
m_comboBox->isEditable()) {
|
||||||
|
m_comboBox->onEntryChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ComboBoxListBox::onProcessMessage(Message* msg)
|
bool ComboBoxListBox::onProcessMessage(Message* msg)
|
||||||
{
|
{
|
||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
@ -591,6 +605,8 @@ void ComboBox::openListBox()
|
|||||||
if (!isEnabled() || m_window)
|
if (!isEnabled() || m_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
onBeforeOpenListBox();
|
||||||
|
|
||||||
m_window = new Window(Window::WithoutTitleBar);
|
m_window = new Window(Window::WithoutTitleBar);
|
||||||
View* view = new View();
|
View* view = new View();
|
||||||
m_listbox = new ComboBoxListBox(this);
|
m_listbox = new ComboBoxListBox(this);
|
||||||
@ -678,6 +694,16 @@ void ComboBox::onChange()
|
|||||||
Change();
|
Change();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComboBox::onEntryChange()
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboBox::onBeforeOpenListBox()
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
void ComboBox::onOpenListBox()
|
void ComboBox::onOpenListBox()
|
||||||
{
|
{
|
||||||
OpenListBox();
|
OpenListBox();
|
||||||
@ -688,6 +714,11 @@ void ComboBox::onCloseListBox()
|
|||||||
CloseListBox();
|
CloseListBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComboBox::onEnterOnEditableEntry()
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
void ComboBox::filterMessages()
|
void ComboBox::filterMessages()
|
||||||
{
|
{
|
||||||
if (!m_filtering) {
|
if (!m_filtering) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
|
// Copyright (C) 2019 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2017 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -57,13 +58,13 @@ namespace ui {
|
|||||||
void removeItem(Widget* item);
|
void removeItem(Widget* item);
|
||||||
|
|
||||||
// Removes and deletes the given item.
|
// Removes and deletes the given item.
|
||||||
void removeItem(int itemIndex);
|
void deleteItem(int itemIndex);
|
||||||
|
|
||||||
void removeAllItems();
|
void deleteAllItems();
|
||||||
|
|
||||||
int getItemCount() const;
|
int getItemCount() const;
|
||||||
|
|
||||||
Widget* getItem(int itemIndex);
|
Widget* getItem(const int itemIndex) const;
|
||||||
const std::string& getItemText(int itemIndex) const;
|
const std::string& getItemText(int itemIndex) const;
|
||||||
void setItemText(int itemIndex, const std::string& text);
|
void setItemText(int itemIndex, const std::string& text);
|
||||||
int findItemIndex(const std::string& text) const;
|
int findItemIndex(const std::string& text) const;
|
||||||
@ -96,9 +97,21 @@ namespace ui {
|
|||||||
void onResize(ResizeEvent& ev) override;
|
void onResize(ResizeEvent& ev) override;
|
||||||
void onSizeHint(SizeHintEvent& ev) override;
|
void onSizeHint(SizeHintEvent& ev) override;
|
||||||
void onInitTheme(InitThemeEvent& ev) override;
|
void onInitTheme(InitThemeEvent& ev) override;
|
||||||
|
|
||||||
|
// When the selected item is changed.
|
||||||
virtual void onChange();
|
virtual void onChange();
|
||||||
|
|
||||||
|
// When the text of an editable ComboBox is changed.
|
||||||
|
virtual void onEntryChange();
|
||||||
|
|
||||||
|
// Before we open the list box, we can fill the combobox with the
|
||||||
|
// items to show. TODO replace all this with a MVC-like combobox
|
||||||
|
// model so we request items only when it's required.
|
||||||
|
virtual void onBeforeOpenListBox();
|
||||||
|
|
||||||
virtual void onOpenListBox();
|
virtual void onOpenListBox();
|
||||||
virtual void onCloseListBox();
|
virtual void onCloseListBox();
|
||||||
|
virtual void onEnterOnEditableEntry();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onButtonClick(Event& ev);
|
void onButtonClick(Event& ev);
|
||||||
|
Loading…
Reference in New Issue
Block a user