// Aseprite UI Library // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "ui/int_entry.h" #include "base/scoped_value.h" #include "gfx/rect.h" #include "gfx/region.h" #include "she/font.h" #include "ui/manager.h" #include "ui/message.h" #include "ui/popup_window.h" #include "ui/size_hint_event.h" #include "ui/slider.h" #include "ui/system.h" #include "ui/theme.h" #include namespace ui { using namespace gfx; IntEntry::IntEntry(int min, int max, SliderDelegate* sliderDelegate) : Entry(int(std::ceil(std::log10((double)max)))+1, "") , m_min(min) , m_max(max) , m_slider(m_min, m_max, m_min, sliderDelegate) , m_popupWindow(NULL) , m_changeFromSlider(false) { 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); } IntEntry::~IntEntry() { closePopup(); } int IntEntry::getValue() const { int value = m_slider.convertTextToValue(text()); return MID(m_min, value, m_max); } void IntEntry::setValue(int value) { value = MID(m_min, value, m_max); setText(m_slider.convertValueToText(value)); if (m_popupWindow && !m_changeFromSlider) m_slider.setValue(value); onValueChange(); } bool IntEntry::onProcessMessage(Message* msg) { switch (msg->type()) { // Reset value if it's out of bounds when focus is lost case kFocusLeaveMessage: setValue(MID(m_min, getValue(), m_max)); deselectText(); break; case kMouseDownMessage: requestFocus(); captureMouse(); openPopup(); selectAllText(); return true; case kMouseMoveMessage: if (hasCapture()) { MouseMessage* mouseMsg = static_cast(msg); Widget* pick = manager()->pick(mouseMsg->position()); if (pick == &m_slider) { releaseMouse(); MouseMessage mouseMsg2(kMouseDownMessage, mouseMsg->pointerType(), mouseMsg->buttons(), mouseMsg->modifiers(), mouseMsg->position()); m_slider.sendMessage(&mouseMsg2); } } break; case kMouseWheelMessage: if (isEnabled()) { int oldValue = getValue(); int newValue = oldValue + static_cast(msg)->wheelDelta().x - static_cast(msg)->wheelDelta().y; newValue = MID(m_min, newValue, m_max); if (newValue != oldValue) { setValue(newValue); selectAllText(); } return true; } break; case kKeyDownMessage: if (hasFocus() && !isReadOnly()) { KeyMessage* keymsg = static_cast(msg); int chr = keymsg->unicodeChar(); if (chr >= 32 && (chr < '0' || chr > '9')) { // "Eat" all keys that aren't number return true; } // Else we use the default Entry processing function which // will process keys like Left/Right arrows, clipboard // handling, etc. } break; } return Entry::onProcessMessage(msg); } void IntEntry::onSizeHint(SizeHintEvent& ev) { int min_w = font()->textLength(m_slider.convertValueToText(m_min)); int max_w = font()->textLength(m_slider.convertValueToText(m_max)); int w = MAX(min_w, max_w) + font()->charWidth('%'); int h = textHeight(); w += border().width(); h += border().height(); ev.setSizeHint(w, h); } void IntEntry::onChange() { Entry::onChange(); onValueChange(); } void IntEntry::onValueChange() { // Do nothing } void IntEntry::openPopup() { m_slider.setValue(getValue()); Rect rc = bounds(); int sliderH = m_slider.sizeHint().h; if (rc.y+rc.h+sliderH < ui::display_h()) rc.y += rc.h; else rc.y -= sliderH; rc.h = sliderH; rc.w = 128*guiscale(); if (rc.x+rc.w > ui::display_w()) rc.x = rc.x - rc.w + bounds().w; m_popupWindow = new PopupWindow("", PopupWindow::ClickBehavior::CloseOnClickInOtherWindow); m_popupWindow->setAutoRemap(false); m_popupWindow->setTransparent(true); m_popupWindow->setBgColor(gfx::ColorNone); m_popupWindow->setBounds(rc); m_popupWindow->Close.connect(&IntEntry::onPopupClose, this); Region rgn(rc.createUnion(bounds())); rgn.createUnion(rgn, Region(bounds())); m_popupWindow->setHotRegion(rgn); m_popupWindow->addChild(&m_slider); m_popupWindow->openWindow(); } void IntEntry::closePopup() { if (m_popupWindow) { removeSlider(); m_popupWindow->closeWindow(NULL); delete m_popupWindow; m_popupWindow = NULL; } } void IntEntry::onChangeSlider() { base::ScopedValue lockFlag(m_changeFromSlider, true, false); setValue(m_slider.getValue()); selectAllText(); } void IntEntry::onPopupClose(CloseEvent& ev) { removeSlider(); deselectText(); releaseFocus(); } void IntEntry::removeSlider() { if (m_popupWindow && m_slider.parent() == m_popupWindow) { m_popupWindow->removeChild(&m_slider); } } } // namespace ui