2013-08-09 08:01:20 +08:00
|
|
|
// Aseprite UI Library
|
2017-02-07 04:58:55 +08:00
|
|
|
// Copyright (C) 2001-2017 David Capello
|
2013-03-31 00:11:35 +08:00
|
|
|
//
|
2014-03-30 07:08:05 +08:00
|
|
|
// This file is released under the terms of the MIT license.
|
|
|
|
// Read LICENSE.txt for more information.
|
2013-03-31 00:11:35 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2013-03-31 00:11:35 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2013-03-31 00:11:35 +08:00
|
|
|
|
|
|
|
#include "ui/int_entry.h"
|
|
|
|
|
2015-05-19 03:53:25 +08:00
|
|
|
#include "base/scoped_value.h"
|
2013-03-31 00:11:35 +08:00
|
|
|
#include "gfx/rect.h"
|
|
|
|
#include "gfx/region.h"
|
2015-08-15 06:46:48 +08:00
|
|
|
#include "she/font.h"
|
2014-02-09 06:39:36 +08:00
|
|
|
#include "ui/manager.h"
|
2013-03-31 00:11:35 +08:00
|
|
|
#include "ui/message.h"
|
|
|
|
#include "ui/popup_window.h"
|
2017-04-15 19:13:20 +08:00
|
|
|
#include "ui/scale.h"
|
2015-12-04 08:50:05 +08:00
|
|
|
#include "ui/size_hint_event.h"
|
2013-03-31 00:11:35 +08:00
|
|
|
#include "ui/slider.h"
|
|
|
|
#include "ui/system.h"
|
|
|
|
#include "ui/theme.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
namespace ui {
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
using namespace gfx;
|
|
|
|
|
2015-08-15 06:46:48 +08:00
|
|
|
IntEntry::IntEntry(int min, int max, SliderDelegate* sliderDelegate)
|
2016-12-17 01:53:26 +08:00
|
|
|
: Entry(int(std::floor(std::log10(double(max))))+1, "")
|
2013-03-31 00:11:35 +08:00
|
|
|
, m_min(min)
|
|
|
|
, m_max(max)
|
2015-08-15 06:46:48 +08:00
|
|
|
, m_slider(m_min, m_max, m_min, sliderDelegate)
|
2017-02-18 01:18:47 +08:00
|
|
|
, m_popupWindow(nullptr)
|
2015-05-19 03:53:25 +08:00
|
|
|
, m_changeFromSlider(false)
|
2013-03-31 00:11:35 +08:00
|
|
|
{
|
2015-08-15 06:46:48 +08:00
|
|
|
m_slider.setFocusStop(false); // In this way the IntEntry doesn't lost the focus
|
|
|
|
m_slider.setTransparent(true);
|
|
|
|
m_slider.Change.connect(&IntEntry::onChangeSlider, this);
|
2013-03-31 00:11:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
IntEntry::~IntEntry()
|
|
|
|
{
|
|
|
|
closePopup();
|
|
|
|
}
|
|
|
|
|
|
|
|
int IntEntry::getValue() const
|
|
|
|
{
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
int value = m_slider.convertTextToValue(text());
|
2013-03-31 00:11:35 +08:00
|
|
|
return MID(m_min, value, m_max);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry::setValue(int value)
|
|
|
|
{
|
|
|
|
value = MID(m_min, value, m_max);
|
|
|
|
|
2015-08-15 06:46:48 +08:00
|
|
|
setText(m_slider.convertValueToText(value));
|
2013-03-31 00:11:35 +08:00
|
|
|
|
2015-08-15 06:46:48 +08:00
|
|
|
if (m_popupWindow && !m_changeFromSlider)
|
|
|
|
m_slider.setValue(value);
|
2013-03-31 00:11:35 +08:00
|
|
|
|
|
|
|
onValueChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IntEntry::onProcessMessage(Message* msg)
|
|
|
|
{
|
2013-07-29 08:17:07 +08:00
|
|
|
switch (msg->type()) {
|
2013-03-31 00:11:35 +08:00
|
|
|
|
2013-11-30 06:22:57 +08:00
|
|
|
// Reset value if it's out of bounds when focus is lost
|
|
|
|
case kFocusLeaveMessage:
|
|
|
|
setValue(MID(m_min, getValue(), m_max));
|
2014-03-09 07:31:55 +08:00
|
|
|
deselectText();
|
2013-03-31 00:11:35 +08:00
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseDownMessage:
|
2014-03-09 07:31:55 +08:00
|
|
|
requestFocus();
|
|
|
|
captureMouse();
|
|
|
|
|
2013-03-31 00:11:35 +08:00
|
|
|
openPopup();
|
2014-03-09 07:31:55 +08:00
|
|
|
selectAllText();
|
|
|
|
return true;
|
2013-03-31 00:11:35 +08:00
|
|
|
|
2014-02-09 06:39:36 +08:00
|
|
|
case kMouseMoveMessage:
|
|
|
|
if (hasCapture()) {
|
|
|
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
Widget* pick = manager()->pick(mouseMsg->position());
|
2015-08-15 06:46:48 +08:00
|
|
|
if (pick == &m_slider) {
|
2014-02-09 06:39:36 +08:00
|
|
|
releaseMouse();
|
|
|
|
|
2014-02-24 19:30:43 +08:00
|
|
|
MouseMessage mouseMsg2(kMouseDownMessage,
|
2016-04-21 09:33:10 +08:00
|
|
|
mouseMsg->pointerType(),
|
2015-10-15 03:42:49 +08:00
|
|
|
mouseMsg->buttons(),
|
|
|
|
mouseMsg->modifiers(),
|
|
|
|
mouseMsg->position());
|
2015-08-15 06:46:48 +08:00
|
|
|
m_slider.sendMessage(&mouseMsg2);
|
2014-02-09 06:39:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseWheelMessage:
|
2013-03-31 00:11:35 +08:00
|
|
|
if (isEnabled()) {
|
|
|
|
int oldValue = getValue();
|
2014-04-29 09:02:56 +08:00
|
|
|
int newValue = oldValue
|
|
|
|
+ static_cast<MouseMessage*>(msg)->wheelDelta().x
|
|
|
|
- static_cast<MouseMessage*>(msg)->wheelDelta().y;
|
2013-03-31 00:11:35 +08:00
|
|
|
newValue = MID(m_min, newValue, m_max);
|
2014-02-09 05:58:28 +08:00
|
|
|
if (newValue != oldValue) {
|
2013-03-31 00:11:35 +08:00
|
|
|
setValue(newValue);
|
2014-02-09 05:58:28 +08:00
|
|
|
selectAllText();
|
|
|
|
}
|
2013-03-31 00:11:35 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
2014-03-09 07:31:55 +08:00
|
|
|
|
|
|
|
case kKeyDownMessage:
|
|
|
|
if (hasFocus() && !isReadOnly()) {
|
|
|
|
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
|
|
|
int chr = keymsg->unicodeChar();
|
2016-12-03 03:47:05 +08:00
|
|
|
if (chr >= 32 && (chr < '0' || chr > '9')) {
|
|
|
|
// "Eat" all keys that aren't number
|
|
|
|
return true;
|
2014-03-09 07:31:55 +08:00
|
|
|
}
|
2016-12-03 03:47:05 +08:00
|
|
|
// Else we use the default Entry processing function which
|
|
|
|
// will process keys like Left/Right arrows, clipboard
|
|
|
|
// handling, etc.
|
2014-03-09 07:31:55 +08:00
|
|
|
}
|
|
|
|
break;
|
2013-03-31 00:11:35 +08:00
|
|
|
}
|
|
|
|
return Entry::onProcessMessage(msg);
|
|
|
|
}
|
|
|
|
|
2015-12-04 08:50:05 +08:00
|
|
|
void IntEntry::onSizeHint(SizeHintEvent& ev)
|
2015-08-15 06:46:48 +08:00
|
|
|
{
|
2017-02-07 04:58:55 +08:00
|
|
|
int min_w = font()->textLength(m_slider.convertValueToText(m_min) + "%");
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
int max_w = font()->textLength(m_slider.convertValueToText(m_max));
|
2015-08-15 06:46:48 +08:00
|
|
|
|
2017-02-07 04:58:55 +08:00
|
|
|
int w = MAX(min_w, max_w);
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
int h = textHeight();
|
2015-08-15 06:46:48 +08:00
|
|
|
|
|
|
|
w += border().width();
|
|
|
|
h += border().height();
|
|
|
|
|
2015-12-04 08:50:05 +08:00
|
|
|
ev.setSizeHint(w, h);
|
2015-08-15 06:46:48 +08:00
|
|
|
}
|
|
|
|
|
2015-09-23 03:22:47 +08:00
|
|
|
void IntEntry::onChange()
|
2013-03-31 00:11:35 +08:00
|
|
|
{
|
2015-09-23 03:22:47 +08:00
|
|
|
Entry::onChange();
|
2013-03-31 00:11:35 +08:00
|
|
|
onValueChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry::onValueChange()
|
|
|
|
{
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry::openPopup()
|
|
|
|
{
|
2015-08-15 06:46:48 +08:00
|
|
|
m_slider.setValue(getValue());
|
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
m_popupWindow = new TransparentPopupWindow(PopupWindow::ClickBehavior::CloseOnClickInOtherWindow);
|
|
|
|
m_popupWindow->setAutoRemap(false);
|
|
|
|
m_popupWindow->addChild(&m_slider);
|
|
|
|
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
|
2015-08-15 06:46:48 +08:00
|
|
|
|
2017-02-18 01:18:47 +08:00
|
|
|
Rect rc = bounds();
|
|
|
|
gfx::Size sz = m_popupWindow->sizeHint();
|
2014-11-26 09:33:45 +08:00
|
|
|
rc.w = 128*guiscale();
|
2014-09-01 01:17:49 +08:00
|
|
|
if (rc.x+rc.w > ui::display_w())
|
2017-02-18 01:18:47 +08:00
|
|
|
rc.x = rc.x-rc.w+bounds().w;
|
|
|
|
if (rc.y+rc.h+sz.h < ui::display_h())
|
|
|
|
rc.y += rc.h;
|
|
|
|
else
|
|
|
|
rc.y -= sz.h;
|
2013-03-31 00:11:35 +08:00
|
|
|
m_popupWindow->setBounds(rc);
|
|
|
|
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
Region rgn(rc.createUnion(bounds()));
|
|
|
|
rgn.createUnion(rgn, Region(bounds()));
|
2013-03-31 00:11:35 +08:00
|
|
|
m_popupWindow->setHotRegion(rgn);
|
|
|
|
|
|
|
|
m_popupWindow->openWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry::closePopup()
|
|
|
|
{
|
|
|
|
if (m_popupWindow) {
|
2015-08-15 06:46:48 +08:00
|
|
|
removeSlider();
|
|
|
|
|
2013-03-31 00:11:35 +08:00
|
|
|
m_popupWindow->closeWindow(NULL);
|
|
|
|
delete m_popupWindow;
|
|
|
|
m_popupWindow = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntEntry::onChangeSlider()
|
|
|
|
{
|
2015-05-19 03:53:25 +08:00
|
|
|
base::ScopedValue<bool> lockFlag(m_changeFromSlider, true, false);
|
2015-08-15 06:46:48 +08:00
|
|
|
setValue(m_slider.getValue());
|
2014-02-09 05:58:28 +08:00
|
|
|
selectAllText();
|
2013-03-31 00:11:35 +08:00
|
|
|
}
|
|
|
|
|
2014-03-09 07:31:55 +08:00
|
|
|
void IntEntry::onPopupClose(CloseEvent& ev)
|
|
|
|
{
|
2015-08-15 06:46:48 +08:00
|
|
|
removeSlider();
|
|
|
|
|
2014-03-09 07:31:55 +08:00
|
|
|
deselectText();
|
|
|
|
releaseFocus();
|
|
|
|
}
|
|
|
|
|
2015-08-15 06:46:48 +08:00
|
|
|
void IntEntry::removeSlider()
|
|
|
|
{
|
|
|
|
if (m_popupWindow &&
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
m_slider.parent() == m_popupWindow) {
|
2015-08-15 06:46:48 +08:00
|
|
|
m_popupWindow->removeChild(&m_slider);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-31 00:11:35 +08:00
|
|
|
} // namespace ui
|