diff --git a/data/skins/default_skin/sheet.png b/data/skins/default_skin/sheet.png index 6b703ff16..523cb1116 100644 Binary files a/data/skins/default_skin/sheet.png and b/data/skins/default_skin/sheet.png differ diff --git a/data/skins/default_skin/skin.xml b/data/skins/default_skin/skin.xml index bba20b71b..06b2164c6 100644 --- a/data/skins/default_skin/skin.xml +++ b/data/skins/default_skin/skin.xml @@ -168,6 +168,8 @@ + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d08dcd87a..3685e98ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -287,6 +287,7 @@ add_library(aseprite-library widgets/hex_color_entry.cpp widgets/menuitem.cpp widgets/palette_view.cpp + widgets/popup_frame_pin.cpp widgets/statebar.cpp widgets/tabs.cpp widgets/toolbar.cpp) diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index ddfc738ad..531c6559a 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -5,7 +5,6 @@ // read LICENSE.txt for more information. #define REDRAW_MOVEMENT -#define MOTION_CURSOR JI_CURSOR_NORMAL #include "config.h" @@ -86,6 +85,81 @@ void Frame::set_wantfocus(bool state) m_is_wantfocus = state; } +HitTest Frame::hitTest(const gfx::Point& point) +{ + HitTestEvent ev(this, point, HitTestNowhere); + onHitTest(ev); + return ev.getHit(); +} + +void Frame::onHitTest(HitTestEvent& ev) +{ + HitTest ht = HitTestNowhere; + + if (!m_is_moveable) { + ev.setHit(ht); + return; + } + + int x = ev.getPoint().x; + int y = ev.getPoint().y; + JRect pos = jwidget_get_rect(this); + JRect cpos = jwidget_get_child_rect(this); + + // Move + if ((this->hasText()) + && (((x >= cpos->x1) && + (x < cpos->x2) && + (y >= pos->y1+this->border_width.b) && + (y < cpos->y1)))) { + ht = HitTestCaption; + } + // Resize + else if (m_is_sizeable) { + if ((x >= pos->x1) && (x < cpos->x1)) { + if ((y >= pos->y1) && (y < cpos->y1)) + ht = HitTestBorderNW; + else if ((y > cpos->y2-1) && (y <= pos->y2-1)) + ht = HitTestBorderSW; + else + ht = HitTestBorderW; + } + else if ((y >= pos->y1) && (y < cpos->y1)) { + if ((x >= pos->x1) && (x < cpos->x1)) + ht = HitTestBorderNW; + else if ((x > cpos->x2-1) && (x <= pos->x2-1)) + ht = HitTestBorderNE; + else + ht = HitTestBorderN; + } + else if ((x > cpos->x2-1) && (x <= pos->x2-1)) { + if ((y >= pos->y1) && (y < cpos->y1)) + ht = HitTestBorderNE; + else if ((y > cpos->y2-1) && (y <= pos->y2-1)) + ht = HitTestBorderSE; + else + ht = HitTestBorderE; + } + else if ((y > cpos->y2-1) && (y <= pos->y2-1)) { + if ((x >= pos->x1) && (x < cpos->x1)) + ht = HitTestBorderSW; + else if ((x > cpos->x2-1) && (x <= pos->x2-1)) + ht = HitTestBorderSE; + else + ht = HitTestBorderS; + } + } + else { + // Client area + ht = HitTestClient; + } + + jrect_free(pos); + jrect_free(cpos); + + ev.setHit(ht); +} + void Frame::remap_window() { Size reqSize; @@ -186,26 +260,6 @@ bool Frame::is_toplevel() return false; } -bool Frame::is_foreground() const -{ - return m_is_foreground; -} - -bool Frame::is_desktop() const -{ - return m_is_desktop; -} - -bool Frame::is_ontop() const -{ - return m_is_ontop; -} - -bool Frame::is_wantfocus() const -{ - return m_is_wantfocus; -} - bool Frame::onProcessMessage(JMessage msg) { switch (msg->type) { @@ -237,9 +291,10 @@ bool Frame::onProcessMessage(JMessage msg) press_x = msg->mouse.x; press_y = msg->mouse.y; - m_windowAction = this->get_action(press_x, press_y); + m_hitTest = hitTest(gfx::Point(press_x, press_y)); - if (m_windowAction != WINDOW_NONE) { + if (m_hitTest != HitTestNowhere && + m_hitTest != HitTestClient) { if (click_pos == NULL) click_pos = jrect_new_copy(this->rc); else @@ -262,7 +317,7 @@ bool Frame::onProcessMessage(JMessage msg) click_pos = NULL; } - m_windowAction = WINDOW_NONE; + m_hitTest = HitTestNowhere; return true; } break; @@ -274,7 +329,7 @@ bool Frame::onProcessMessage(JMessage msg) // Does it have the mouse captured? if (hasCapture()) { // Reposition/resize - if (m_windowAction == WINDOW_MOVE) { + if (m_hitTest == HitTestCaption) { int x = click_pos->x1 + (msg->mouse.x - press_x); int y = click_pos->y1 + (msg->mouse.y - press_y); JRect rect = jrect_new(x, y, @@ -289,26 +344,43 @@ bool Frame::onProcessMessage(JMessage msg) w = jrect_w(click_pos); h = jrect_h(click_pos); - if (m_windowAction & WINDOW_RESIZE_LEFT) - w += press_x - msg->mouse.x; - else if (m_windowAction & WINDOW_RESIZE_RIGHT) - w += msg->mouse.x - press_x; + bool hitLeft = (m_hitTest == HitTestBorderNW || + m_hitTest == HitTestBorderW || + m_hitTest == HitTestBorderSW); + bool hitTop = (m_hitTest == HitTestBorderNW || + m_hitTest == HitTestBorderN || + m_hitTest == HitTestBorderNE); + bool hitRight = (m_hitTest == HitTestBorderNE || + m_hitTest == HitTestBorderE || + m_hitTest == HitTestBorderSE); + bool hitBottom = (m_hitTest == HitTestBorderSW || + m_hitTest == HitTestBorderS || + m_hitTest == HitTestBorderSE); - if (m_windowAction & WINDOW_RESIZE_TOP) + if (hitLeft) { + w += press_x - msg->mouse.x; + } + else if (hitRight) { + w += msg->mouse.x - press_x; + } + + if (hitTop) { h += (press_y - msg->mouse.y); - else if (m_windowAction & WINDOW_RESIZE_BOTTOM) + } + else if (hitBottom) { h += (msg->mouse.y - press_y); + } this->limit_size(&w, &h); if ((jrect_w(this->rc) != w) || (jrect_h(this->rc) != h)) { - if (m_windowAction & WINDOW_RESIZE_LEFT) + if (hitLeft) x = click_pos->x1 - (w - jrect_w(click_pos)); else x = this->rc->x1; - if (m_windowAction & WINDOW_RESIZE_TOP) + if (hitTop) y = click_pos->y1 - (h - jrect_h(click_pos)); else y = this->rc->y1; @@ -324,44 +396,52 @@ bool Frame::onProcessMessage(JMessage msg) } } } - - /* TODO */ -/* { */ -/* JWidget manager = get_manager(); */ -/* View* view = View::getView(manager); */ -/* if (view) { */ -/* jview_update(view); */ -/* } */ -/* } */ break; case JM_SETCURSOR: if (m_is_moveable) { - int action = this->get_action(msg->mouse.x, msg->mouse.y); + HitTest ht = hitTest(gfx::Point(msg->mouse.x, msg->mouse.y)); int cursor = JI_CURSOR_NORMAL; - if (action == WINDOW_MOVE) - cursor = MOTION_CURSOR; - else if (action & WINDOW_RESIZE_LEFT) { - if (action & WINDOW_RESIZE_TOP) + switch (ht) { + + case HitTestCaption: + cursor = JI_CURSOR_NORMAL; + break; + + case HitTestBorderNW: cursor = JI_CURSOR_SIZE_TL; - else if (action & WINDOW_RESIZE_BOTTOM) - cursor = JI_CURSOR_SIZE_BL; - else + break; + + case HitTestBorderW: cursor = JI_CURSOR_SIZE_L; - } - else if (action & WINDOW_RESIZE_RIGHT) { - if (action & WINDOW_RESIZE_TOP) + break; + + case HitTestBorderSW: + cursor = JI_CURSOR_SIZE_BL; + break; + + case HitTestBorderNE: cursor = JI_CURSOR_SIZE_TR; - else if (action & WINDOW_RESIZE_BOTTOM) - cursor = JI_CURSOR_SIZE_BR; - else + break; + + case HitTestBorderE: cursor = JI_CURSOR_SIZE_R; + break; + + case HitTestBorderSE: + cursor = JI_CURSOR_SIZE_BR; + break; + + case HitTestBorderN: + cursor = JI_CURSOR_SIZE_T; + break; + + case HitTestBorderS: + cursor = JI_CURSOR_SIZE_B; + break; + } - else if (action & WINDOW_RESIZE_TOP) - cursor = JI_CURSOR_SIZE_T; - else if (action & WINDOW_RESIZE_BOTTOM) - cursor = JI_CURSOR_SIZE_B; jmouse_set_cursor(cursor); return true; @@ -436,79 +516,6 @@ void Frame::window_set_position(JRect rect) jrect_free(cpos); } -int Frame::get_action(int x, int y) -{ - int action = WINDOW_NONE; - JRect pos; - JRect cpos; - - if (!m_is_moveable) - return action; - - pos = jwidget_get_rect(this); - cpos = jwidget_get_child_rect(this); - - /* move */ - if ((this->hasText()) - && (((x >= cpos->x1) && - (x < cpos->x2) && - (y >= pos->y1+this->border_width.b) && - (y < cpos->y1)) - || (key[KEY_ALT]))) { - action = WINDOW_MOVE; - } - /* resize */ - else if (m_is_sizeable) { - /* left *****************************************/ - if ((x >= pos->x1) && (x < cpos->x1)) { - action |= WINDOW_RESIZE_LEFT; - /* top */ - if ((y >= pos->y1) && (y < cpos->y1)) { - action |= WINDOW_RESIZE_TOP; - } - /* bottom */ - else if ((y > cpos->y2-1) && (y <= pos->y2-1)) - action |= WINDOW_RESIZE_BOTTOM; - } - /* top *****************************************/ - else if ((y >= pos->y1) && (y < cpos->y1)) { - action |= WINDOW_RESIZE_TOP; - /* left */ - if ((x >= pos->x1) && (x < cpos->x1)) - action |= WINDOW_RESIZE_LEFT; - /* right */ - else if ((x > cpos->x2-1) && (x <= pos->x2-1)) - action |= WINDOW_RESIZE_RIGHT; - } - /* right *****************************************/ - else if ((x > cpos->x2-1) && (x <= pos->x2-1)) { - action |= WINDOW_RESIZE_RIGHT; - /* top */ - if ((y >= pos->y1) && (y < cpos->y1)) { - action |= WINDOW_RESIZE_TOP; - } - /* bottom */ - else if ((y > cpos->y2-1) && (y <= pos->y2-1)) - action |= WINDOW_RESIZE_BOTTOM; - } - /* bottom *****************************************/ - else if ((y > cpos->y2-1) && (y <= pos->y2-1)) { - action |= WINDOW_RESIZE_BOTTOM; - /* left */ - if ((x >= pos->x1) && (x < cpos->x1)) - action |= WINDOW_RESIZE_LEFT; - /* right */ - else if ((x > cpos->x2-1) && (x <= pos->x2-1)) - action |= WINDOW_RESIZE_RIGHT; - } - } - - jrect_free(pos); - jrect_free(cpos); - - return action; -} - void Frame::limit_size(int *w, int *h) { *w = MAX(*w, this->border_width.l+this->border_width.r); diff --git a/src/gui/frame.h b/src/gui/frame.h index cd010378f..6c46f77d5 100644 --- a/src/gui/frame.h +++ b/src/gui/frame.h @@ -9,21 +9,15 @@ #include "base/compiler_specific.h" #include "base/signal.h" +#include "gfx/point.h" +#include "gui/event.h" +#include "gui/hit_test_event.h" #include "gui/widget.h" class CloseEvent { }; // TODO class Frame : public Widget { - JWidget m_killer; - bool m_is_desktop : 1; - bool m_is_moveable : 1; - bool m_is_sizeable : 1; - bool m_is_ontop : 1; - bool m_is_wantfocus : 1; - bool m_is_foreground : 1; - bool m_is_autoremap : 1; - public: Frame(bool is_desktop, const char* text); ~Frame(); @@ -47,18 +41,22 @@ public: void closeWindow(Widget* killer); bool is_toplevel(); - bool is_foreground() const; - bool is_desktop() const; - bool is_ontop() const; - bool is_wantfocus() const; + bool is_foreground() const { return m_is_foreground; } + bool is_desktop() const { return m_is_desktop; } + bool is_ontop() const { return m_is_ontop; } + bool is_wantfocus() const { return m_is_wantfocus; } + bool is_moveable() const { return m_is_moveable; } + + HitTest hitTest(const gfx::Point& point); // Signals Signal1 Close; protected: - bool onProcessMessage(JMessage msg) OVERRIDE; - void onPreferredSize(PreferredSizeEvent& ev) OVERRIDE; - void onPaint(PaintEvent& ev) OVERRIDE; + virtual bool onProcessMessage(JMessage msg) OVERRIDE; + virtual void onPreferredSize(PreferredSizeEvent& ev) OVERRIDE; + virtual void onPaint(PaintEvent& ev) OVERRIDE; + virtual void onHitTest(HitTestEvent& ev); private: void window_set_position(JRect rect); @@ -66,7 +64,15 @@ private: void limit_size(int* w, int* h); void move_window(JRect rect, bool use_blit); - int m_windowAction; + JWidget m_killer; + bool m_is_desktop : 1; + bool m_is_moveable : 1; + bool m_is_sizeable : 1; + bool m_is_ontop : 1; + bool m_is_wantfocus : 1; + bool m_is_foreground : 1; + bool m_is_autoremap : 1; + int m_hitTest; }; #endif diff --git a/src/gui/gui.h b/src/gui/gui.h index 118708613..d56f3b85a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -23,6 +23,7 @@ #include "gui/frame.h" #include "gui/graphics.h" #include "gui/grid.h" +#include "gui/hit_test_event.h" #include "gui/hook.h" #include "gui/image_view.h" #include "gui/label.h" diff --git a/src/gui/hit_test_event.h b/src/gui/hit_test_event.h new file mode 100644 index 000000000..9f272781e --- /dev/null +++ b/src/gui/hit_test_event.h @@ -0,0 +1,45 @@ +// ASE gui library +// Copyright (C) 2001-2011 David Capello +// +// This source file is ditributed under a BSD-like license, please +// read LICENSE.txt for more information. + +#ifndef GUI_HIT_TEST_EVENT_H_INCLUDED +#define GUI_HIT_TEST_EVENT_H_INCLUDED + +#include "gui/event.h" + +enum HitTest +{ + HitTestNowhere, + HitTestCaption, + HitTestClient, + HitTestBorderNW, + HitTestBorderN, + HitTestBorderNE, + HitTestBorderE, + HitTestBorderSE, + HitTestBorderS, + HitTestBorderSW, + HitTestBorderW, +}; + +class HitTestEvent : public Event +{ +public: + HitTestEvent(Component* source, const gfx::Point& point, HitTest hit) + : Event(source) + , m_point(point) + , m_hit(hit) { } + + gfx::Point getPoint() const { return m_point; } + + HitTest getHit() const { return m_hit; } + void setHit(HitTest hit) { m_hit = hit; } + +private: + gfx::Point m_point; + HitTest m_hit; +}; + +#endif // GUI_HIT_TEST_EVENT_H_INCLUDED diff --git a/src/gui/manager.cpp b/src/gui/manager.cpp index e582ad7a7..c1f726744 100644 --- a/src/gui/manager.cpp +++ b/src/gui/manager.cpp @@ -402,18 +402,24 @@ bool jmanager_generate_messages(JWidget manager) } } - /* Z-Order: - Send the window to top (only when you click in a window - that aren't the desktop) */ + // Handle Z order: Send the window to top (only when you click in + // a window that aren't the desktop). if (msg->type == JM_BUTTONPRESSED && !capture_widget && mouse_widget) { + // The clicked window Frame* window = static_cast(mouse_widget->getRoot()); JWidget win_manager = window ? window->getManager(): NULL; if ((window) && + // We cannot change Z-order of desktop windows (!window->is_desktop()) && + // We cannot change Z order of foreground windows because a + // foreground window can launch other background windows + // which should be kept on top of the foreground one. + (!window->is_foreground()) && + // If the window is not already the top window of the manager. (window != TOPWND(win_manager))) { - /* put it in the top of the list */ + // Put it in the top of the list jlist_remove(win_manager->children, window); if (window->is_ontop()) @@ -432,7 +438,7 @@ bool jmanager_generate_messages(JWidget manager) window->invalidate(); } - /* put the focus */ + // Put the focus jmanager_set_focus(mouse_widget); } diff --git a/src/gui/popup_frame.cpp b/src/gui/popup_frame.cpp index 09a93a41c..76454f27c 100644 --- a/src/gui/popup_frame.cpp +++ b/src/gui/popup_frame.cpp @@ -40,15 +40,10 @@ PopupFrame::PopupFrame(const char* text, bool close_on_buttonpressed) PopupFrame::~PopupFrame() { - if (m_filtering) { - m_filtering = false; - jmanager_remove_msg_filter(JM_MOTION, this); - jmanager_remove_msg_filter(JM_BUTTONPRESSED, this); - jmanager_remove_msg_filter(JM_KEYPRESSED, this); - } - if (m_hot_region != NULL) { + stopFilteringMessages(); + + if (m_hot_region != NULL) jregion_free(m_hot_region); - } } /** @@ -62,26 +57,29 @@ void PopupFrame::setHotRegion(JRegion region) if (m_hot_region != NULL) jregion_free(m_hot_region); - if (!m_filtering) { - m_filtering = true; - jmanager_add_msg_filter(JM_MOTION, this); - jmanager_add_msg_filter(JM_BUTTONPRESSED, this); - jmanager_add_msg_filter(JM_KEYPRESSED, this); - } + startFilteringMessages(); + m_hot_region = region; } +void PopupFrame::makeFloating() +{ + stopFilteringMessages(); + set_moveable(true); +} + +void PopupFrame::makeFixed() +{ + startFilteringMessages(); + set_moveable(false); +} + bool PopupFrame::onProcessMessage(JMessage msg) { switch (msg->type) { case JM_CLOSE: - if (m_filtering) { - m_filtering = false; - jmanager_remove_msg_filter(JM_MOTION, this); - jmanager_remove_msg_filter(JM_BUTTONPRESSED, this); - jmanager_remove_msg_filter(JM_KEYPRESSED, this); - } + stopFilteringMessages(); break; case JM_SIGNAL: @@ -95,7 +93,7 @@ bool PopupFrame::onProcessMessage(JMessage msg) break; case JM_MOUSELEAVE: - if (m_hot_region == NULL) + if (m_hot_region == NULL && !is_moveable()) closeWindow(NULL); break; @@ -109,31 +107,30 @@ bool PopupFrame::onProcessMessage(JMessage msg) return false; case JM_BUTTONPRESSED: - /* if the user click outside the window, we have to close the - tooltip window */ + // If the user click outside the window, we have to close the + // tooltip window. if (m_filtering) { Widget* picked = this->pick(msg->mouse.x, msg->mouse.y); if (!picked || picked->getRoot() != this) { - this->closeWindow(NULL); + closeWindow(NULL); } } - /* this is used when the user click inside a small text - tooltip */ + // This is used when the user click inside a small text tooltip. if (m_close_on_buttonpressed) - this->closeWindow(NULL); + closeWindow(NULL); break; case JM_MOTION: - if (m_hot_region != NULL && + if (!is_moveable() && + m_hot_region != NULL && jmanager_get_capture() == NULL) { struct jrect box; - /* if the mouse is outside the hot-region we have to close the window */ - if (!jregion_point_in(m_hot_region, - msg->mouse.x, msg->mouse.y, &box)) { - this->closeWindow(NULL); - } + // If the mouse is outside the hot-region we have to close the + // window. + if (!jregion_point_in(m_hot_region, msg->mouse.x, msg->mouse.y, &box)) + closeWindow(NULL); } break; @@ -191,3 +188,23 @@ void PopupFrame::onPaint(PaintEvent& ev) g->drawString(getText(), ji_color_foreground(), this->getBgColor(), pos, getAlign()); } + +void PopupFrame::startFilteringMessages() +{ + if (!m_filtering) { + m_filtering = true; + jmanager_add_msg_filter(JM_MOTION, this); + jmanager_add_msg_filter(JM_BUTTONPRESSED, this); + jmanager_add_msg_filter(JM_KEYPRESSED, this); + } +} + +void PopupFrame::stopFilteringMessages() +{ + if (m_filtering) { + m_filtering = false; + jmanager_remove_msg_filter(JM_MOTION, this); + jmanager_remove_msg_filter(JM_BUTTONPRESSED, this); + jmanager_remove_msg_filter(JM_KEYPRESSED, this); + } +} diff --git a/src/gui/popup_frame.h b/src/gui/popup_frame.h index 620db106b..3f3ba9740 100644 --- a/src/gui/popup_frame.h +++ b/src/gui/popup_frame.h @@ -18,12 +18,18 @@ public: void setHotRegion(JRegion region); + void makeFloating(); + void makeFixed(); + protected: bool onProcessMessage(JMessage msg) OVERRIDE; void onPreferredSize(PreferredSizeEvent& ev) OVERRIDE; void onPaint(PaintEvent& ev) OVERRIDE; private: + void startFilteringMessages(); + void stopFilteringMessages(); + bool m_close_on_buttonpressed; JRegion m_hot_region; bool m_filtering; diff --git a/src/modules/gui.cpp b/src/modules/gui.cpp index c6cd9395c..417ff4af5 100644 --- a/src/modules/gui.cpp +++ b/src/modules/gui.cpp @@ -810,6 +810,11 @@ void get_widgets(JWidget window, ...) } void setup_mini_look(Widget* widget) +{ + setup_look(widget, MiniLook); +} + +void setup_look(Widget* widget, LookType lookType) { SharedPtr skinProp; @@ -817,7 +822,7 @@ void setup_mini_look(Widget* widget) if (skinProp == NULL) skinProp.reset(new SkinProperty); - skinProp->setMiniLook(true); + skinProp->setLook(lookType); widget->setProperty(skinProp); } diff --git a/src/modules/gui.h b/src/modules/gui.h index 4fffce1c2..c87938f86 100644 --- a/src/modules/gui.h +++ b/src/modules/gui.h @@ -24,6 +24,7 @@ #include "base/exception.h" #include "gui/base.h" #include "gui/accel.h" +#include "skin/skin_property.h" class ButtonBase; class CheckBox; @@ -93,6 +94,7 @@ void hook_signal(Widget* widget, void get_widgets(Widget* window, ...); void setup_mini_look(Widget* widget); +void setup_look(Widget* widget, LookType lookType); void setup_bevels(Widget* widget, int b1, int b2, int b3, int b4); void set_gfxicon_to_button(ButtonBase* button, diff --git a/src/skin/skin_parts.h b/src/skin/skin_parts.h index 490978b44..4b6cd68a4 100644 --- a/src/skin/skin_parts.h +++ b/src/skin/skin_parts.h @@ -465,6 +465,9 @@ enum { PART_LAYER_LOCKED, PART_LAYER_LOCKED_SELECTED, + PART_UNPINNED, + PART_PINNED, + PARTS }; diff --git a/src/skin/skin_property.cpp b/src/skin/skin_property.cpp index 7787b75d6..3d472ab6c 100644 --- a/src/skin/skin_property.cpp +++ b/src/skin/skin_property.cpp @@ -25,7 +25,7 @@ const char* SkinProperty::SkinPropertyName = "SkinProperty"; SkinProperty::SkinProperty() : Property(SkinPropertyName) { - m_isMiniLook = false; + m_look = NormalLook; m_upperLeft = 0; m_upperRight = 0; m_lowerLeft = 0; @@ -35,53 +35,3 @@ SkinProperty::SkinProperty() SkinProperty::~SkinProperty() { } - -bool SkinProperty::isMiniLook() const -{ - return m_isMiniLook; -} - -void SkinProperty::setMiniLook(bool state) -{ - m_isMiniLook = state; -} - -int SkinProperty::getUpperLeft() const -{ - return m_upperLeft; -} - -int SkinProperty::getUpperRight() const -{ - return m_upperRight; -} - -int SkinProperty::getLowerLeft() const -{ - return m_lowerLeft; -} - -int SkinProperty::getLowerRight() const -{ - return m_lowerRight; -} - -void SkinProperty::setUpperLeft(int value) -{ - m_upperLeft = value; -} - -void SkinProperty::setUpperRight(int value) -{ - m_upperRight = value; -} - -void SkinProperty::setLowerLeft(int value) -{ - m_lowerLeft = value; -} - -void SkinProperty::setLowerRight(int value) -{ - m_lowerRight = value; -} diff --git a/src/skin/skin_property.h b/src/skin/skin_property.h index 5ee0028cb..507b7d2ed 100644 --- a/src/skin/skin_property.h +++ b/src/skin/skin_property.h @@ -21,6 +21,12 @@ #include "gui/property.h" +enum LookType { + NormalLook, + MiniLook, + WithoutBordersLook, +}; + // Property to show widgets with a special look (e.g.: buttons or sliders with mini-borders) class SkinProperty : public Property { @@ -30,21 +36,21 @@ public: SkinProperty(); ~SkinProperty(); - bool isMiniLook() const; - void setMiniLook(bool state); + LookType getLook() const { return m_look; } + void setLook(LookType look) { m_look = look; } - int getUpperLeft() const; - int getUpperRight() const; - int getLowerLeft() const; - int getLowerRight() const; + int getUpperLeft() const { return m_upperLeft; } + int getUpperRight() const { return m_upperRight; } + int getLowerLeft() const { return m_lowerLeft; } + int getLowerRight() const { return m_lowerRight; } - void setUpperLeft(int value); - void setUpperRight(int value); - void setLowerLeft(int value); - void setLowerRight(int value); + void setUpperLeft(int value) { m_upperLeft = value; } + void setUpperRight(int value) { m_upperRight = value; } + void setLowerLeft(int value) { m_lowerLeft = value; } + void setLowerRight(int value) { m_lowerRight = value; } private: - bool m_isMiniLook; + LookType m_look; int m_upperLeft; int m_upperRight; int m_lowerLeft; diff --git a/src/skin/skin_theme.cpp b/src/skin/skin_theme.cpp index b6da2c24e..0703dd95f 100644 --- a/src/skin/skin_theme.cpp +++ b/src/skin/skin_theme.cpp @@ -198,6 +198,8 @@ SkinTheme::SkinTheme() sheet_mapping["layer_editable_selected"] = PART_LAYER_EDITABLE_SELECTED; sheet_mapping["layer_locked"] = PART_LAYER_LOCKED; sheet_mapping["layer_locked_selected"] = PART_LAYER_LOCKED_SELECTED; + sheet_mapping["unpinned"] = PART_UNPINNED; + sheet_mapping["pinned"] = PART_PINNED; reload_skin(); } @@ -719,24 +721,24 @@ void SkinTheme::paintButton(PaintEvent& ev) iconInterface ? iconInterface->getHeight() : 0); // Tool buttons are smaller - bool isMiniLook = false; + LookType look = NormalLook; SharedPtr skinPropery = widget->getProperty(SkinProperty::SkinPropertyName); if (skinPropery != NULL) - isMiniLook = skinPropery->isMiniLook(); + look = skinPropery->getLook(); // selected if (widget->isSelected()) { fg = get_button_selected_text_color(); bg = get_button_selected_face_color(); - part_nw = isMiniLook ? PART_TOOLBUTTON_NORMAL_NW: - PART_BUTTON_SELECTED_NW; + part_nw = (look == MiniLook ? PART_TOOLBUTTON_NORMAL_NW: + PART_BUTTON_SELECTED_NW); } // with mouse else if (widget->isEnabled() && widget->hasMouseOver()) { fg = get_button_hot_text_color(); bg = get_button_hot_face_color(); - part_nw = isMiniLook ? PART_TOOLBUTTON_HOT_NW: - PART_BUTTON_HOT_NW; + part_nw = (look == MiniLook ? PART_TOOLBUTTON_HOT_NW: + PART_BUTTON_HOT_NW); } // without mouse else { @@ -744,11 +746,11 @@ void SkinTheme::paintButton(PaintEvent& ev) bg = get_button_normal_face_color(); if (widget->hasFocus()) - part_nw = isMiniLook ? PART_TOOLBUTTON_HOT_NW: - PART_BUTTON_FOCUSED_NW; + part_nw = (look == MiniLook ? PART_TOOLBUTTON_HOT_NW: + PART_BUTTON_FOCUSED_NW); else - part_nw = isMiniLook ? PART_TOOLBUTTON_NORMAL_NW: - PART_BUTTON_NORMAL_NW; + part_nw = (look == MiniLook ? PART_TOOLBUTTON_NORMAL_NW: + PART_BUTTON_NORMAL_NW); } // widget position @@ -791,10 +793,16 @@ void SkinTheme::paintCheckBox(PaintEvent& ev) iconInterface ? iconInterface->getWidth() : 0, iconInterface ? iconInterface->getHeight() : 0); - // background + // Check box look + LookType look = NormalLook; + SharedPtr skinPropery = widget->getProperty(SkinProperty::SkinPropertyName); + if (skinPropery != NULL) + look = skinPropery->getLook(); + + // Background jdraw_rectfill(widget->rc, bg = BGCOLOR); - // mouse + // Mouse if (widget->isEnabled()) { if (widget->hasMouseOver()) jdraw_rectfill(widget->rc, bg = get_check_hot_face_color()); @@ -802,7 +810,7 @@ void SkinTheme::paintCheckBox(PaintEvent& ev) jdraw_rectfill(widget->rc, bg = get_check_focus_face_color()); } - /* text */ + // Text draw_textstring(NULL, -1, bg, false, widget, &text, 0); // Paint the icon @@ -810,7 +818,7 @@ void SkinTheme::paintCheckBox(PaintEvent& ev) paintIcon(widget, ev.getGraphics(), iconInterface, icon.x1-widget->rc->x1, icon.y1-widget->rc->y1); // draw focus - if (widget->hasFocus()) { + if (look != WithoutBordersLook && widget->hasFocus()) { draw_bounds_nw(ji_screen, widget->rc->x1, widget->rc->y1, @@ -1222,7 +1230,7 @@ void SkinTheme::paintSlider(PaintEvent& ev) SharedPtr skinPropery = widget->getProperty(SkinProperty::SkinPropertyName); if (skinPropery != NULL) - isMiniLook = skinPropery->isMiniLook(); + isMiniLook = (skinPropery->getLook() == MiniLook); if (SkinSliderProperty* sliderProperty = dynamic_cast(skinPropery.get())) bgPainter = sliderProperty->getBgPainter(); diff --git a/src/widgets/color_button.cpp b/src/widgets/color_button.cpp index 794808458..ab0945881 100644 --- a/src/widgets/color_button.cpp +++ b/src/widgets/color_button.cpp @@ -86,6 +86,11 @@ bool ColorButton::onProcessMessage(JMessage msg) { switch (msg->type) { + case JM_CLOSE: + if (m_frame && m_frame->isVisible()) + m_frame->closeWindow(NULL); + break; + case JM_MOUSEENTER: app_get_statusbar()->showColor(0, "", m_color, 255); break; @@ -101,7 +106,7 @@ bool ColorButton::onProcessMessage(JMessage msg) // Open it openSelectorDialog(); } - else { + else if (!m_frame->is_moveable()) { // If it is visible, close it closeSelectorDialog(); } diff --git a/src/widgets/color_selector.cpp b/src/widgets/color_selector.cpp index c1effdfd3..036dedbe5 100644 --- a/src/widgets/color_selector.cpp +++ b/src/widgets/color_selector.cpp @@ -36,7 +36,7 @@ #include "widgets/palette_view.h" ColorSelector::ColorSelector() - : PopupFrame("Color Selector", false) + : PopupFramePin("Color Selector", false) , m_color(Color::fromMask()) , m_vbox(JI_VERTICAL) , m_topBox(JI_HORIZONTAL) @@ -70,6 +70,14 @@ ColorSelector::ColorSelector() jwidget_add_child(&m_topBox, &m_grayButton); jwidget_add_child(&m_topBox, &m_maskButton); jwidget_add_child(&m_topBox, &m_hexColorEntry); + { + Box* filler = new Box(JI_HORIZONTAL); + Box* miniVbox = new Box(JI_VERTICAL); + jwidget_expansive(filler, true); + jwidget_add_child(&m_topBox, filler); + jwidget_add_child(&m_topBox, miniVbox); + jwidget_add_child(miniVbox, getPin()); + } jwidget_add_child(&m_vbox, &m_topBox); jwidget_add_child(&m_vbox, &m_colorPaletteContainer); jwidget_add_child(&m_vbox, &m_rgbSliders); @@ -96,6 +104,11 @@ ColorSelector::ColorSelector() initTheme(); } +ColorSelector::~ColorSelector() +{ + jwidget_remove_child(getPin()->getParent(), getPin()); +} + void ColorSelector::setColor(const Color& color) { m_color = color; diff --git a/src/widgets/color_selector.h b/src/widgets/color_selector.h index 086717c42..4c804162c 100644 --- a/src/widgets/color_selector.h +++ b/src/widgets/color_selector.h @@ -24,16 +24,17 @@ #include "gui/button.h" #include "gui/grid.h" #include "gui/label.h" -#include "gui/popup_frame.h" #include "gui/view.h" #include "widgets/color_sliders.h" +#include "widgets/popup_frame_pin.h" #include "widgets/hex_color_entry.h" #include "widgets/palette_view.h" -class ColorSelector : public PopupFrame +class ColorSelector : public PopupFramePin { public: ColorSelector(); + ~ColorSelector(); void setColor(const Color& color); Color getColor() const; diff --git a/src/widgets/popup_frame_pin.cpp b/src/widgets/popup_frame_pin.cpp new file mode 100644 index 000000000..4a3d5dfde --- /dev/null +++ b/src/widgets/popup_frame_pin.cpp @@ -0,0 +1,87 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2011 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "widgets/popup_frame_pin.h" + +#include "base/bind.h" +#include "gfx/border.h" +#include "gfx/size.h" +#include "gui/gui.h" +#include "modules/gfx.h" +#include "modules/gui.h" +#include "skin/skin_theme.h" + +#include +#include + +PopupFramePin::PopupFramePin(const char* text, bool close_on_buttonpressed) + : PopupFrame(text, close_on_buttonpressed) + , m_pin("") +{ + // Configure the micro check-box look without borders, only the "pin" icon is shown. + setup_look(&m_pin, WithoutBordersLook); + m_pin.child_spacing = 0; + m_pin.setBorder(gfx::Border(0)); + + m_pin.Click.connect(&PopupFramePin::onPinClick, this); + + set_gfxicon_to_button(&m_pin, PART_UNPINNED, PART_PINNED, PART_UNPINNED, JI_CENTER | JI_MIDDLE); +} + +void PopupFramePin::onPinClick(Event& ev) +{ + if (m_pin.isSelected()) { + makeFloating(); + } + else { + JRect rc = jrect_new(this->rc->x1-8, this->rc->y1-8, this->rc->x2+8, this->rc->y2+8); + JRegion rgn = jregion_new(rc, 1); + jrect_free(rc); + + setHotRegion(rgn); + makeFixed(); + } +} + +bool PopupFramePin::onProcessMessage(JMessage msg) +{ + switch (msg->type) { + + case JM_OPEN: + m_pin.setSelected(false); + makeFixed(); + break; + + case JM_CLOSE: + m_pin.setSelected(false); + break; + + } + + return PopupFrame::onProcessMessage(msg); +} + +void PopupFramePin::onHitTest(HitTestEvent& ev) +{ + PopupFrame::onHitTest(ev); + + if (m_pin.isSelected() && ev.getHit() == HitTestClient) + ev.setHit(HitTestCaption); +} diff --git a/src/widgets/popup_frame_pin.h b/src/widgets/popup_frame_pin.h new file mode 100644 index 000000000..c797a6394 --- /dev/null +++ b/src/widgets/popup_frame_pin.h @@ -0,0 +1,45 @@ +/* ASE - Allegro Sprite Editor + * Copyright (C) 2001-2011 David Capello + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef WIDGETS_POPUP_FRAME_PIN_H_INCLUDED +#define WIDGETS_POPUP_FRAME_PIN_H_INCLUDED + +#include "gui/button.h" +#include "gui/popup_frame.h" + +class PopupFramePin : public PopupFrame +{ +public: + PopupFramePin(const char* text, bool close_on_buttonpressed); + +protected: + virtual bool onProcessMessage(JMessage msg) OVERRIDE; + virtual void onHitTest(HitTestEvent& ev) OVERRIDE; + + // The pin. Your derived class must add this pin in some place of + // the frame as a children, and you must to remove the pin from the + // parent in your class's dtor. + CheckBox* getPin() { return &m_pin; } + +private: + void onPinClick(Event& ev); + + CheckBox m_pin; +}; + +#endif