From 3ad44e3004338afa81fb2a01e296711d6c2dd9b7 Mon Sep 17 00:00:00 2001 From: David Capello Date: Tue, 29 Mar 2011 21:07:37 -0300 Subject: [PATCH] Add a "pin" in color selectors to make the popup window floating. + Added Frame::hitTest() and Frame::onHitTest(). + Added LookType enum for SkinProperty. --- data/skins/default_skin/sheet.png | Bin 8674 -> 8715 bytes data/skins/default_skin/skin.xml | 2 + src/CMakeLists.txt | 1 + src/gui/frame.cpp | 273 +++++++++++++++--------------- src/gui/frame.h | 40 +++-- src/gui/gui.h | 1 + src/gui/hit_test_event.h | 45 +++++ src/gui/manager.cpp | 16 +- src/gui/popup_frame.cpp | 83 +++++---- src/gui/popup_frame.h | 6 + src/modules/gui.cpp | 7 +- src/modules/gui.h | 2 + src/skin/skin_parts.h | 3 + src/skin/skin_property.cpp | 52 +----- src/skin/skin_property.h | 28 +-- src/skin/skin_theme.cpp | 38 +++-- src/widgets/color_button.cpp | 7 +- src/widgets/color_selector.cpp | 15 +- src/widgets/color_selector.h | 5 +- src/widgets/popup_frame_pin.cpp | 87 ++++++++++ src/widgets/popup_frame_pin.h | 45 +++++ 21 files changed, 486 insertions(+), 270 deletions(-) create mode 100644 src/gui/hit_test_event.h create mode 100644 src/widgets/popup_frame_pin.cpp create mode 100644 src/widgets/popup_frame_pin.h diff --git a/data/skins/default_skin/sheet.png b/data/skins/default_skin/sheet.png index 6b703ff16e761a611fedc9552a1248f8d46981a9..523cb1116e42f7b6f02ae64c90ad6a531eac462c 100644 GIT binary patch literal 8715 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 V?|Kk^k2=W%prNXbD^q?P@;^a4Pr?8I literal 8674 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 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