diff --git a/src/app/modules/gfx.cpp b/src/app/modules/gfx.cpp index 554d6a9ba..118364f2c 100644 --- a/src/app/modules/gfx.cpp +++ b/src/app/modules/gfx.cpp @@ -195,18 +195,6 @@ static void rectgrid(ui::Graphics* g, const gfx::Rect& rc, const gfx::Size& tile } } -void draw_emptyset_symbol(BITMAP* bmp, const Rect& rc, ui::Color color) -{ - Point center = rc.getCenter(); - int size = MIN(rc.w, rc.h) - 8; - size = MID(4, size, 64); - - circle(bmp, center.x, center.y, size*4/10, ui::to_system(color)); - line(bmp, - center.x-size/2, center.y+size/2, - center.x+size/2, center.y-size/2, ui::to_system(color)); -} - static void draw_color(ui::Graphics* g, const Rect& rc, PixelFormat pixelFormat, const app::Color& color) { if (rc.w < 1 || rc.h < 1) diff --git a/src/app/modules/gfx.h b/src/app/modules/gfx.h index 9ab585929..53bac81c8 100644 --- a/src/app/modules/gfx.h +++ b/src/app/modules/gfx.h @@ -33,7 +33,6 @@ namespace app { void dotted_mode(int offset); - void draw_emptyset_symbol(BITMAP* bmp, const gfx::Rect& rc, ui::Color color); void draw_color_button(ui::Graphics* g, const gfx::Rect& rc, bool outer_nw, bool outer_n, bool outer_ne, bool outer_e, diff --git a/src/app/settings/document_settings.h b/src/app/settings/document_settings.h index 90e0941c6..1d0e76462 100644 --- a/src/app/settings/document_settings.h +++ b/src/app/settings/document_settings.h @@ -25,6 +25,7 @@ #include "gfx/rect.h" namespace app { + class DocumentSettingsObserver; enum SnapBehavior { NormalSnap = 0, @@ -75,6 +76,9 @@ namespace app { virtual void setOnionskinNextFrames(int frames) = 0; virtual void setOnionskinOpacityBase(int base) = 0; virtual void setOnionskinOpacityStep(int step) = 0; + + virtual void addObserver(DocumentSettingsObserver* observer) = 0; + virtual void removeObserver(DocumentSettingsObserver* observer) = 0; }; } // namespace app diff --git a/src/app/settings/settings_observers.h b/src/app/settings/settings_observers.h index b67ed3a9f..0e025b53a 100644 --- a/src/app/settings/settings_observers.h +++ b/src/app/settings/settings_observers.h @@ -24,9 +24,12 @@ #include "app/settings/ink_type.h" #include "app/settings/rotation_algorithm.h" #include "app/settings/selection_mode.h" +#include "filters/tiled_mode.h" +#include "gfx/fwd.h" #include "raster/pen_type.h" namespace app { + class Color; namespace tools { class Tool; @@ -77,6 +80,17 @@ namespace app { virtual void onSetColorSwatches(ColorSwatches* swaches) {} }; + class DocumentSettingsObserver { + public: + virtual ~DocumentSettingsObserver() { } + + virtual void onSetTiledMode(filters::TiledMode mode) { } + virtual void onSetSnapToGrid(bool state) { } + virtual void onSetGridVisible(bool state) { } + virtual void onSetGridBounds(const gfx::Rect& rect) { } + virtual void onSetGridColor(const app::Color& color) { } + }; + } // namespace app #endif // APP_SETTINGS_SETTINGS_OBSERVERS_H_INCLUDED diff --git a/src/app/settings/ui_settings_impl.cpp b/src/app/settings/ui_settings_impl.cpp index 2092fbcbf..4b7891128 100644 --- a/src/app/settings/ui_settings_impl.cpp +++ b/src/app/settings/ui_settings_impl.cpp @@ -47,7 +47,8 @@ using namespace filters; namespace { -class UIDocumentSettingsImpl : public IDocumentSettings { +class UIDocumentSettingsImpl : public IDocumentSettings, + public base::Observable { public: UIDocumentSettingsImpl() : m_tiledMode((TiledMode)get_config_int("Tools", "Tiled", (int)TILED_NONE)) @@ -124,6 +125,9 @@ public: virtual void setOnionskinOpacityBase(int base) OVERRIDE; virtual void setOnionskinOpacityStep(int step) OVERRIDE; + virtual void addObserver(DocumentSettingsObserver* observer) OVERRIDE; + virtual void removeObserver(DocumentSettingsObserver* observer) OVERRIDE; + private: void redrawDocumentViews() { // TODO Redraw only document's views @@ -343,6 +347,7 @@ TiledMode UIDocumentSettingsImpl::getTiledMode() void UIDocumentSettingsImpl::setTiledMode(TiledMode mode) { m_tiledMode = mode; + notifyObservers(&DocumentSettingsObserver::onSetTiledMode, mode); } bool UIDocumentSettingsImpl::getSnapToGrid() @@ -368,24 +373,25 @@ app::Color UIDocumentSettingsImpl::getGridColor() void UIDocumentSettingsImpl::setSnapToGrid(bool state) { m_snapToGrid = state; + notifyObservers(&DocumentSettingsObserver::onSetSnapToGrid, state); } void UIDocumentSettingsImpl::setGridVisible(bool state) { m_gridVisible = state; - redrawDocumentViews(); + notifyObservers(&DocumentSettingsObserver::onSetGridVisible, state); } void UIDocumentSettingsImpl::setGridBounds(const Rect& rect) { m_gridBounds = rect; - redrawDocumentViews(); + notifyObservers(&DocumentSettingsObserver::onSetGridBounds, rect); } void UIDocumentSettingsImpl::setGridColor(const app::Color& color) { m_gridColor = color; - redrawDocumentViews(); + notifyObservers(&DocumentSettingsObserver::onSetGridColor, color); } void UIDocumentSettingsImpl::snapToGrid(gfx::Point& point, SnapBehavior snapBehavior) const @@ -482,6 +488,16 @@ void UIDocumentSettingsImpl::setOnionskinOpacityStep(int step) redrawDocumentViews(); } +void UIDocumentSettingsImpl::addObserver(DocumentSettingsObserver* observer) +{ + base::Observable::addObserver(observer); +} + +void UIDocumentSettingsImpl::removeObserver(DocumentSettingsObserver* observer) +{ + base::Observable::removeObserver(observer); +} + ////////////////////////////////////////////////////////////////////// // Tools & pen settings diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 56d63368a..a91ca8910 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -16,8 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// #define DRAWSPRITE_DOUBLEBUFFERED - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -165,10 +163,18 @@ Editor::Editor(Document* document, EditorFlags flags) m_fgColorChangeSlot = ColorBar::instance()->FgColorChange.connect(Bind(&Editor::onFgColorChange, this)); + + UIContext::instance()->getSettings() + ->getDocumentSettings(m_document) + ->addObserver(this); } Editor::~Editor() { + UIContext::instance()->getSettings() + ->getDocumentSettings(m_document) + ->removeObserver(this); + setCustomizationDelegate(NULL); m_mask_timer.stop(); @@ -327,89 +333,54 @@ void Editor::updateEditor() View::getView(this)->updateView(); } -void Editor::drawSpriteUnclippedRect(const gfx::Rect& rc) +void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy) { - View* view = View::getView(this); - Rect vp = view->getViewportBounds(); - int source_x, source_y, dest_x, dest_y, width, height; - - // Get scroll - - Point scroll = view->getViewScroll(); - // Output information + int source_x = rc.x << m_zoom; + int source_y = rc.y << m_zoom; + int dest_x = dx + m_offset_x + source_x; + int dest_y = dy + m_offset_y + source_y; + int width = rc.w << m_zoom; + int height = rc.h << m_zoom; - source_x = rc.x << m_zoom; - source_y = rc.y << m_zoom; - dest_x = vp.x - scroll.x + m_offset_x + source_x; - dest_y = vp.y - scroll.y + m_offset_y + source_y; - width = rc.w << m_zoom; - height = rc.h << m_zoom; - - // Clip from viewport - - if (dest_x < vp.x) { - source_x += vp.x - dest_x; - width -= vp.x - dest_x; - dest_x = vp.x; + // Clip from graphics/screen + const gfx::Rect& clip = g->getClipBounds(); + if (dest_x < clip.x) { + source_x += clip.x - dest_x; + width -= clip.x - dest_x; + dest_x = clip.x; } - - if (dest_y < vp.y) { - source_y += vp.y - dest_y; - height -= vp.y - dest_y; - dest_y = vp.y; + if (dest_y < clip.y) { + source_y += clip.y - dest_y; + height -= clip.y - dest_y; + dest_y = clip.y; } - - if (dest_x+width-1 > vp.x + vp.w-1) - width = vp.x + vp.w - dest_x; - - if (dest_y+height-1 > vp.y + vp.h-1) - height = vp.y + vp.h - dest_y; - - // Clip from screen - - if (dest_x < ji_screen->cl) { - source_x += ji_screen->cl - dest_x; - width -= ji_screen->cl - dest_x; - dest_x = ji_screen->cl; + if (dest_x+width > clip.x+clip.w) { + width = clip.x+clip.w-dest_x; } - - if (dest_y < ji_screen->ct) { - source_y += ji_screen->ct - dest_y; - height -= ji_screen->ct - dest_y; - dest_y = ji_screen->ct; + if (dest_y+height > clip.y+clip.h) { + height = clip.y+clip.h-dest_y; } - if (dest_x+width-1 >= ji_screen->cr) - width = ji_screen->cr-dest_x; - - if (dest_y+height-1 >= ji_screen->cb) - height = ji_screen->cb-dest_y; - // Clip from sprite - if (source_x < 0) { width += source_x; dest_x -= source_x; source_x = 0; } - if (source_y < 0) { height += source_y; dest_y -= source_y; source_y = 0; } - if (source_x+width > (m_sprite->getWidth() << m_zoom)) { width = (m_sprite->getWidth() << m_zoom) - source_x; } - if (source_y+height > (m_sprite->getHeight() << m_zoom)) { height = (m_sprite->getHeight() << m_zoom) - source_y; } // Draw the sprite - if ((width > 0) && (height > 0)) { RenderEngine renderEngine(m_document, m_sprite, m_layer, m_frame); @@ -426,23 +397,14 @@ void Editor::drawSpriteUnclippedRect(const gfx::Rect& rc) m_decorator->preRenderDecorator(&preRender); } -#ifdef DRAWSPRITE_DOUBLEBUFFERED - BITMAP *bmp = create_bitmap(width, height); + SharedPtr tmp(create_bitmap(width, height), destroy_bitmap); + convert_image_to_allegro(rendered, tmp, 0, 0, m_sprite->getPalette(m_frame)); - image_to_allegro(rendered, bmp, 0, 0, m_sprite->getPalette(m_frame)); - blit(bmp, ji_screen, 0, 0, dest_x, dest_y, width, height); - - destroy_bitmap(bmp); -#else - acquire_bitmap(ji_screen); - convert_image_to_allegro(rendered, ji_screen, dest_x, dest_y, - m_sprite->getPalette(m_frame)); - release_bitmap(ji_screen); -#endif + g->blit(tmp, 0, 0, dest_x, dest_y, width, height); } } - // Draw grids + // Document settings IDocumentSettings* docSettings = UIContext::instance()->getSettings()->getDocumentSettings(m_document); @@ -469,6 +431,72 @@ void Editor::drawSpriteUnclippedRect(const gfx::Rect& rc) } } +void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc) +{ + gfx::Rect client = getClientBounds(); + gfx::Rect spriteRect( + client.x + m_offset_x, + client.y + m_offset_y, + (m_sprite->getWidth() << m_zoom), + (m_sprite->getHeight() << m_zoom)); + gfx::Rect enclosingRect = spriteRect; + + // Draw the main sprite at the center. + drawOneSpriteUnclippedRect(g, rc, 0, 0); + + gfx::Region outside(client); + outside.createSubtraction(outside, gfx::Region(spriteRect)); + + // Document settings + IDocumentSettings* docSettings = + UIContext::instance()->getSettings()->getDocumentSettings(m_document); + + if (docSettings->getTiledMode() & filters::TILED_X_AXIS) { + drawOneSpriteUnclippedRect(g, rc, -spriteRect.w, 0); + drawOneSpriteUnclippedRect(g, rc, +spriteRect.w, 0); + + enclosingRect = gfx::Rect(spriteRect.x-spriteRect.w, spriteRect.y, spriteRect.w*3, spriteRect.h); + outside.createSubtraction(outside, gfx::Region(enclosingRect)); + } + + if (docSettings->getTiledMode() & filters::TILED_Y_AXIS) { + drawOneSpriteUnclippedRect(g, rc, 0, -spriteRect.h); + drawOneSpriteUnclippedRect(g, rc, 0, +spriteRect.h); + + enclosingRect = gfx::Rect(spriteRect.x, spriteRect.y-spriteRect.h, spriteRect.w, spriteRect.h*3); + outside.createSubtraction(outside, gfx::Region(enclosingRect)); + } + + if (docSettings->getTiledMode() == filters::TILED_BOTH) { + drawOneSpriteUnclippedRect(g, rc, -spriteRect.w, -spriteRect.h); + drawOneSpriteUnclippedRect(g, rc, +spriteRect.w, -spriteRect.h); + drawOneSpriteUnclippedRect(g, rc, -spriteRect.w, +spriteRect.h); + drawOneSpriteUnclippedRect(g, rc, +spriteRect.w, +spriteRect.h); + + enclosingRect = gfx::Rect( + spriteRect.x-spriteRect.w, + spriteRect.y-spriteRect.h, spriteRect.w*3, spriteRect.h*3); + outside.createSubtraction(outside, gfx::Region(enclosingRect)); + } + + // Fill the outside (parts of the editor that aren't covered by the + // sprite). + SkinTheme* theme = static_cast(this->getTheme()); + g->fillRegion(theme->getColor(ThemeColor::EditorFace), outside); + + // Draw the borders that enclose the sprite. + enclosingRect.enlarge(1); + g->drawRect(theme->getColor(ThemeColor::EditorSpriteBorder), enclosingRect); + g->drawHLine( + theme->getColor(ThemeColor::EditorSpriteBottomBorder), + enclosingRect.x, enclosingRect.y+enclosingRect.h, enclosingRect.w); +} + +void Editor::drawSpriteUnclippedRect(const gfx::Rect& rc) +{ + drawSpriteUnclippedRect(getGraphics(getClientBounds()), rc); +} + void Editor::drawSpriteClipped(const gfx::Region& updateRegion) { Region region; @@ -881,72 +909,6 @@ bool Editor::onProcessMessage(Message* msg) { switch (msg->type()) { - case kPaintMessage: { - SkinTheme* theme = static_cast(this->getTheme()); - - int old_cursor_thick = m_cursor_thick; - if (m_cursor_thick) - editor_clean_cursor(); - - // Editor without sprite - if (!m_sprite) { - View* view = View::getView(this); - Rect vp = view->getViewportBounds(); - - jdraw_rectfill(vp, theme->getColor(ThemeColor::EditorFace)); - draw_emptyset_symbol(ji_screen, vp, ui::rgba(64, 64, 64)); - } - // Editor with sprite - else { - try { - // Lock the sprite to read/render it. - DocumentReader documentReader(m_document); - int x1, y1, x2, y2; - - // Draw the background outside of sprite's bounds - x1 = getBounds().x + m_offset_x; - y1 = getBounds().y + m_offset_y; - x2 = x1 + (m_sprite->getWidth() << m_zoom) - 1; - y2 = y1 + (m_sprite->getHeight() << m_zoom) - 1; - - jdraw_rectexclude(getBounds(), - gfx::Rect(gfx::Point(x1-1, y1-1), - gfx::Point(x2+1, y2+2)), - theme->getColor(ThemeColor::EditorFace)); - - // Draw the sprite in the editor - drawSpriteUnclippedRect(gfx::Rect(0, 0, m_sprite->getWidth(), m_sprite->getHeight())); - - // Draw the sprite boundary - rect(ji_screen, x1-1, y1-1, x2+1, y2+1, to_system(theme->getColor(ThemeColor::EditorSpriteBorder))); - hline(ji_screen, x1-1, y2+2, x2+1, to_system(theme->getColor(ThemeColor::EditorSpriteBottomBorder))); - - // Draw the mask boundaries - if (m_document->getBoundariesSegments()) { - drawMask(); - m_mask_timer.start(); - } - else { - m_mask_timer.stop(); - } - - // Draw the cursor again - if (old_cursor_thick != 0) { - editor_draw_cursor(jmouse_x(0), jmouse_y(0)); - } - } - catch (const LockedDocumentException&) { - // The sprite is locked to be read, so we can draw an opaque - // background only. - - View* view = View::getView(this); - Rect vp = view->getViewportBounds(); - jdraw_rectfill(vp, theme->getColor(ThemeColor::EditorFace)); - } - } - return true; - } - case kTimerMessage: if (static_cast(msg)->timer() == &m_mask_timer) { if (isVisible() && m_sprite) { @@ -1070,6 +1032,51 @@ void Editor::onPreferredSize(PreferredSizeEvent& ev) ev.setPreferredSize(sz); } +void Editor::onPaint(ui::PaintEvent& ev) +{ + Graphics* g = ev.getGraphics(); + gfx::Rect rc = getClientBounds(); + SkinTheme* theme = static_cast(this->getTheme()); + + int old_cursor_thick = m_cursor_thick; + if (m_cursor_thick) + editor_clean_cursor(); + + // Editor without sprite + if (!m_sprite) { + g->fillRect(theme->getColor(ThemeColor::EditorFace), rc); + } + // Editor with sprite + else { + try { + // Lock the sprite to read/render it. + DocumentReader documentReader(m_document); + + // Draw the sprite in the editor + drawSpriteUnclippedRect(g, gfx::Rect(0, 0, m_sprite->getWidth(), m_sprite->getHeight())); + + // Draw the mask boundaries + if (m_document->getBoundariesSegments()) { + drawMask(); + m_mask_timer.start(); + } + else { + m_mask_timer.stop(); + } + + // Draw the cursor again + if (old_cursor_thick != 0) { + editor_draw_cursor(jmouse_x(0), jmouse_y(0)); + } + } + catch (const LockedDocumentException&) { + // The sprite is locked to be read, so we can draw an opaque + // background only. + g->fillRect(theme->getColor(ThemeColor::EditorFace), rc); + } + } +} + // When the current tool is changed void Editor::onCurrentToolChange() { @@ -1211,4 +1218,24 @@ void Editor::pasteImage(const Image* image, int x, int y) setState(EditorStatePtr(new MovingPixelsState(this, NULL, pixelsMovement, NoHandle))); } +void Editor::onSetTiledMode(filters::TiledMode mode) +{ + invalidate(); +} + +void Editor::onSetGridVisible(bool state) +{ + invalidate(); +} + +void Editor::onSetGridBounds(const gfx::Rect& rect) +{ + invalidate(); +} + +void Editor::onSetGridColor(const app::Color& color) +{ + invalidate(); +} + } // namespace app diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h index 76f4444f2..9ef2c049f 100644 --- a/src/app/ui/editor/editor.h +++ b/src/app/ui/editor/editor.h @@ -21,6 +21,7 @@ #include "app/color.h" #include "app/document.h" +#include "app/settings/settings_observers.h" #include "app/ui/editor/editor_observers.h" #include "app/ui/editor/editor_state.h" #include "app/ui/editor/editor_states_history.h" @@ -43,6 +44,7 @@ namespace gfx { class Region; } namespace ui { + class Graphics; class View; } @@ -57,7 +59,8 @@ namespace app { class Tool; } - class Editor : public ui::Widget { + class Editor : public ui::Widget, + public DocumentSettingsObserver { public: enum EditorFlags { kNoneFlag = 0, @@ -175,9 +178,15 @@ namespace app { protected: bool onProcessMessage(ui::Message* msg) OVERRIDE; void onPreferredSize(ui::PreferredSizeEvent& ev) OVERRIDE; + void onPaint(ui::PaintEvent& ev) OVERRIDE; void onCurrentToolChange(); void onFgColorChange(); + void onSetTiledMode(filters::TiledMode mode); + void onSetGridVisible(bool state); + void onSetGridBounds(const gfx::Rect& rect); + void onSetGridColor(const app::Color& color); + private: void setStateInternal(const EditorStatePtr& newState); void editor_update_quicktool(); @@ -197,6 +206,8 @@ namespace app { // Draws the specified portion of sprite in the editor. Warning: // You should setup the clip of the screen before calling this // routine. + void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy); + void drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc); void drawSpriteUnclippedRect(const gfx::Rect& rc); // Stack of states. The top element in the stack is the current state (m_state). diff --git a/src/app/ui/file_list.cpp b/src/app/ui/file_list.cpp index e16f6595f..a1c615a3d 100644 --- a/src/app/ui/file_list.cpp +++ b/src/app/ui/file_list.cpp @@ -237,10 +237,6 @@ bool FileList::onProcessMessage(Message* msg) x-1, y-1, x+thumbnail->w, y+thumbnail->h, makecol(0, 0, 0)); } - - // is the current folder empty? - if (m_list.empty()) - draw_emptyset_symbol(ji_screen, vp, ui::rgba(194, 194, 194)); return true; }