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