aseprite/src/ui/combobox.cpp

539 lines
11 KiB
C++
Raw Normal View History

// ASEPRITE gui library
2013-01-27 15:13:13 +00:00
// Copyright (C) 2001-2013 David Capello
//
// This source file is distributed under a BSD-like license, please
// read LICENSE.txt for more information.
2007-09-18 23:57:02 +00:00
2009-07-12 20:29:16 +00:00
#include "config.h"
#include "base/compiler_specific.h"
#include "gfx/size.h"
2012-06-18 01:49:58 +00:00
#include "ui/gui.h"
2007-09-18 23:57:02 +00:00
#include <allegro.h>
using namespace gfx;
namespace ui {
class ComboBoxButton : public Button
{
public:
ComboBoxButton() : Button("") {
setFocusStop(false);
}
void onPaint(PaintEvent& ev) OVERRIDE {
getTheme()->paintComboBoxButton(ev);
}
};
class ComboBoxEntry : public Entry
{
public:
ComboBoxEntry(ComboBox* comboBox)
: Entry(256, ""),
m_comboBox(comboBox) {
}
protected:
bool onProcessMessage(Message* msg) OVERRIDE;
private:
ComboBox* m_comboBox;
};
class ComboBoxListBox : public ListBox
{
public:
ComboBoxListBox(ComboBox* comboBox)
: m_comboBox(comboBox)
{
for (ComboBox::ListItems::iterator
it = comboBox->begin(), end = comboBox->end(); it != end; ++it)
addChild(*it);
}
void clean()
{
// Remove all added items so ~Widget() don't delete them.
while (getLastChild())
removeChild(getLastChild());
ASSERT(getChildren().empty());
selectChild(NULL);
}
protected:
bool onProcessMessage(Message* msg) OVERRIDE;
void onChangeSelectedItem() OVERRIDE;
private:
bool isValidItem(int index) const {
return (index >= 0 && index < m_comboBox->getItemCount());
}
ComboBox* m_comboBox;
};
ComboBox::ComboBox()
: Widget(kComboBoxWidget)
2007-09-18 23:57:02 +00:00
{
m_entry = new ComboBoxEntry(this);
m_button = new ComboBoxButton();
m_window = NULL;
m_selected = 0;
m_editable = false;
m_clickopen = true;
m_casesensitive = true;
2007-09-18 23:57:02 +00:00
// TODO this separation should be from the Theme*
this->child_spacing = 0;
2007-09-18 23:57:02 +00:00
m_entry->setExpansive(true);
// When the "m_button" is clicked ("Click" signal) call onButtonClick() method
m_button->Click.connect(&ComboBox::onButtonClick, this);
2007-09-18 23:57:02 +00:00
addChild(m_entry);
addChild(m_button);
2007-09-18 23:57:02 +00:00
setFocusStop(true);
setEditable(m_editable);
initTheme();
2007-09-18 23:57:02 +00:00
}
ComboBox::~ComboBox()
2007-09-18 23:57:02 +00:00
{
removeAllItems();
}
2007-09-18 23:57:02 +00:00
void ComboBox::setEditable(bool state)
{
m_editable = state;
2007-09-18 23:57:02 +00:00
if (state) {
2010-12-08 17:28:13 +00:00
m_entry->setReadOnly(false);
m_entry->showCaret();
2007-09-18 23:57:02 +00:00
}
else {
2010-12-08 17:28:13 +00:00
m_entry->setReadOnly(true);
m_entry->hideCaret();
2007-09-18 23:57:02 +00:00
}
}
void ComboBox::setClickOpen(bool state)
2007-09-18 23:57:02 +00:00
{
m_clickopen = state;
2007-09-18 23:57:02 +00:00
}
void ComboBox::setCaseSensitive(bool state)
2007-09-18 23:57:02 +00:00
{
m_casesensitive = state;
2007-09-18 23:57:02 +00:00
}
bool ComboBox::isEditable()
2007-09-18 23:57:02 +00:00
{
return m_editable;
2007-09-18 23:57:02 +00:00
}
bool ComboBox::isClickOpen()
2007-09-18 23:57:02 +00:00
{
return m_clickopen;
2007-09-18 23:57:02 +00:00
}
bool ComboBox::isCaseSensitive()
2007-09-18 23:57:02 +00:00
{
return m_casesensitive;
2007-09-18 23:57:02 +00:00
}
int ComboBox::addItem(ListItem* item)
2007-09-18 23:57:02 +00:00
{
bool sel_first = m_items.empty();
2007-09-18 23:57:02 +00:00
m_items.push_back(item);
2007-09-18 23:57:02 +00:00
if (sel_first)
setSelectedItemIndex(0);
return m_items.size()-1;
2007-09-18 23:57:02 +00:00
}
int ComboBox::addItem(const char* text)
{
return addItem(new ListItem(text));
}
void ComboBox::insertItem(int itemIndex, ListItem* item)
{
bool sel_first = m_items.empty();
m_items.insert(m_items.begin() + itemIndex, item);
if (sel_first)
setSelectedItemIndex(0);
}
void ComboBox::insertItem(int itemIndex, const char* text)
{
insertItem(itemIndex, new ListItem(text));
}
void ComboBox::removeItem(ListItem* item)
{
ListItems::iterator it = std::find(m_items.begin(), m_items.end(), item);
ASSERT(it != m_items.end());
if (it != m_items.end())
m_items.erase(it);
// Do not delete the given "item"
}
void ComboBox::removeItem(int itemIndex)
2007-09-18 23:57:02 +00:00
{
ASSERT(itemIndex >= 0 && (size_t)itemIndex < m_items.size());
2007-09-18 23:57:02 +00:00
ListItem* item = m_items[itemIndex];
2007-09-18 23:57:02 +00:00
m_items.erase(m_items.begin() + itemIndex);
delete item;
}
void ComboBox::removeAllItems()
{
ListItems::iterator it, end = m_items.end();
for (it = m_items.begin(); it != end; ++it)
delete *it;
m_items.clear();
2007-09-18 23:57:02 +00:00
}
int ComboBox::getItemCount() const
2007-09-18 23:57:02 +00:00
{
return m_items.size();
}
ListItem* ComboBox::getItem(int itemIndex)
{
if (itemIndex >= 0 && (size_t)itemIndex < m_items.size()) {
return m_items[itemIndex];
}
else
return NULL;
}
const char* ComboBox::getItemText(int itemIndex) const
{
if (itemIndex >= 0 && (size_t)itemIndex < m_items.size()) {
ListItem* item = m_items[itemIndex];
return item->getText();
2007-09-18 23:57:02 +00:00
}
else
return "";
2007-09-18 23:57:02 +00:00
}
void ComboBox::setItemText(int itemIndex, const char* text)
2007-09-18 23:57:02 +00:00
{
ASSERT(itemIndex >= 0 && (size_t)itemIndex < m_items.size());
ListItem* item = m_items[itemIndex];
item->setText(text);
2007-09-18 23:57:02 +00:00
}
int ComboBox::findItemIndex(const char* text)
2007-09-18 23:57:02 +00:00
{
int itemIndex = 0;
2007-09-18 23:57:02 +00:00
ListItems::iterator it, end = m_items.end();
for (it = m_items.begin(); it != end; ++it) {
ListItem* item = *it;
if ((m_casesensitive && ustrcmp(item->getText(), text) == 0) ||
(!m_casesensitive && ustricmp(item->getText(), text) == 0)) {
return itemIndex;
}
itemIndex++;
}
return -1;
2007-09-18 23:57:02 +00:00
}
ListItem* ComboBox::getSelectedItem() const
2007-09-18 23:57:02 +00:00
{
return (!m_items.empty() ? m_items[m_selected]: NULL);
2007-09-18 23:57:02 +00:00
}
void ComboBox::setSelectedItem(ListItem* item)
2007-09-18 23:57:02 +00:00
{
ListItems::iterator it = std::find(m_items.begin(), m_items.end(), item);
2007-09-18 23:57:02 +00:00
ASSERT(it != m_items.end());
if (it != m_items.end())
setSelectedItemIndex(std::distance(m_items.begin(), it));
}
int ComboBox::getSelectedItemIndex() const
{
return (!m_items.empty() ? m_selected: -1);
2007-09-18 23:57:02 +00:00
}
void ComboBox::setSelectedItemIndex(int itemIndex)
2007-09-18 23:57:02 +00:00
{
if (itemIndex >= 0 && (size_t)itemIndex < m_items.size()) {
m_selected = itemIndex;
2007-09-18 23:57:02 +00:00
ListItems::iterator it = m_items.begin() + itemIndex;
ListItem* item = *it;
m_entry->setText(item->getText());
}
2007-09-18 23:57:02 +00:00
}
2010-12-08 17:28:13 +00:00
Entry* ComboBox::getEntryWidget()
2007-09-18 23:57:02 +00:00
{
return m_entry;
2007-09-18 23:57:02 +00:00
}
Button* ComboBox::getButtonWidget()
2007-09-18 23:57:02 +00:00
{
return m_button;
2007-09-18 23:57:02 +00:00
}
bool ComboBox::onProcessMessage(Message* msg)
{
2007-09-18 23:57:02 +00:00
switch (msg->type) {
case kCloseMessage:
closeListBox();
break;
case kWinMoveMessage:
if (m_window)
m_window->moveWindow(getListBoxPos());
2007-09-18 23:57:02 +00:00
break;
case kMouseDownMessage:
if (m_window != NULL) {
if (!View::getView(m_listbox)->hasMouse()) {
closeListBox();
return true;
}
2007-09-18 23:57:02 +00:00
}
break;
2007-09-18 23:57:02 +00:00
}
return Widget::onProcessMessage(msg);
2007-09-18 23:57:02 +00:00
}
void ComboBox::onResize(ResizeEvent& ev)
{
gfx::Rect bounds = ev.getBounds();
setBoundsQuietly(bounds);
// Button
Size buttonSize = m_button->getPreferredSize();
m_button->setBounds(Rect(bounds.x2() - buttonSize.w, bounds.y,
buttonSize.w, bounds.h));
// Entry
m_entry->setBounds(Rect(bounds.x, bounds.y,
bounds.w - buttonSize.w, bounds.h));
}
void ComboBox::onPreferredSize(PreferredSizeEvent& ev)
{
Size reqSize(0, 0);
Size entrySize = m_entry->getPreferredSize();
// Get the text-length of every item and put in 'w' the maximum value
ListItems::iterator it, end = m_items.end();
for (it = m_items.begin(); it != end; ++it) {
int item_w =
2*jguiscale()+
text_length(this->getFont(), (*it)->getText())+
10*jguiscale();
reqSize.w = MAX(reqSize.w, item_w);
}
reqSize.w += entrySize.w;
reqSize.h += entrySize.h;
Size buttonSize = m_button->getPreferredSize();
reqSize.w += buttonSize.w;
reqSize.h = MAX(reqSize.h, buttonSize.h);
ev.setPreferredSize(reqSize);
}
bool ComboBoxEntry::onProcessMessage(Message* msg)
2007-09-18 23:57:02 +00:00
{
switch (msg->type) {
case kKeyDownMessage:
if (hasFocus()) {
if (!m_comboBox->isEditable()) {
if (msg->key.scancode == KEY_SPACE ||
msg->key.scancode == KEY_ENTER ||
msg->key.scancode == KEY_ENTER_PAD) {
m_comboBox->switchListBox();
return true;
}
}
else {
if (msg->key.scancode == KEY_ENTER ||
msg->key.scancode == KEY_ENTER_PAD) {
m_comboBox->switchListBox();
return true;
}
}
2007-09-18 23:57:02 +00:00
}
break;
case kMouseDownMessage:
if (m_comboBox->isClickOpen()) {
m_comboBox->switchListBox();
2007-12-04 21:50:31 +00:00
}
2007-09-18 23:57:02 +00:00
if (m_comboBox->isEditable()) {
getManager()->setFocus(this);
2007-09-18 23:57:02 +00:00
}
else
return true;
2007-09-18 23:57:02 +00:00
break;
2009-11-22 00:26:58 +00:00
case kPaintMessage:
getTheme()->draw_combobox_entry(this, &msg->draw.rect);
2009-11-22 00:26:58 +00:00
return true;
2010-12-08 17:28:13 +00:00
2007-09-18 23:57:02 +00:00
}
return Entry::onProcessMessage(msg);
2007-09-18 23:57:02 +00:00
}
bool ComboBoxListBox::onProcessMessage(Message* msg)
2007-09-18 23:57:02 +00:00
{
switch (msg->type) {
case kMouseUpMessage:
2007-09-18 23:57:02 +00:00
{
int index = m_comboBox->getSelectedItemIndex();
if (isValidItem(index))
m_comboBox->onChange();
m_comboBox->closeListBox();
2007-09-18 23:57:02 +00:00
}
return true;
2007-09-18 23:57:02 +00:00
case kKeyDownMessage:
if (hasFocus()) {
if (msg->key.scancode == KEY_SPACE ||
msg->key.scancode == KEY_ENTER ||
msg->key.scancode == KEY_ENTER_PAD) {
m_comboBox->closeListBox();
return true;
}
2007-09-18 23:57:02 +00:00
}
break;
}
return ListBox::onProcessMessage(msg);
}
void ComboBoxListBox::onChangeSelectedItem()
{
ListBox::onChangeSelectedItem();
int index = getSelectedIndex();
if (isValidItem(index))
m_comboBox->setSelectedItemIndex(index);
2007-09-18 23:57:02 +00:00
}
// When the mouse is clicked we switch the visibility-status of the list-box
void ComboBox::onButtonClick(Event& ev)
2007-09-18 23:57:02 +00:00
{
switchListBox();
2007-09-18 23:57:02 +00:00
}
void ComboBox::openListBox()
2007-09-18 23:57:02 +00:00
{
if (!m_window) {
2012-07-09 02:24:42 +00:00
m_window = new Window(false, NULL);
View* view = new View();
m_listbox = new ComboBoxListBox(this);
m_window->setOnTop(true);
jwidget_noborders(m_window);
2007-09-18 23:57:02 +00:00
Widget* viewport = view->getViewport();
int size = getItemCount();
jwidget_set_min_size
(viewport,
m_button->rc->x2 - m_entry->rc->x1 - view->border_width.l - view->border_width.r,
+viewport->border_width.t
+(2*jguiscale()+jwidget_get_text_height(m_listbox))*MID(1, size, 16)+
+viewport->border_width.b);
2007-09-18 23:57:02 +00:00
m_window->addChild(view);
view->attachToView(m_listbox);
2007-09-18 23:57:02 +00:00
m_listbox->selectIndex(m_selected);
2007-09-18 23:57:02 +00:00
m_window->remapWindow();
2007-09-18 23:57:02 +00:00
gfx::Rect rc = getListBoxPos();
m_window->positionWindow(rc.x, rc.y);
2007-09-18 23:57:02 +00:00
getManager()->addMessageFilter(kMouseDownMessage, this);
2012-07-09 02:24:42 +00:00
m_window->openWindow();
getManager()->setFocus(m_listbox);
2007-09-18 23:57:02 +00:00
}
}
void ComboBox::closeListBox()
2007-09-18 23:57:02 +00:00
{
if (m_window) {
m_listbox->clean();
m_window->closeWindow(this);
delete m_window; // window, frame
m_window = NULL;
2007-09-18 23:57:02 +00:00
getManager()->removeMessageFilter(kMouseDownMessage, this);
getManager()->setFocus(m_entry);
2007-09-18 23:57:02 +00:00
}
}
void ComboBox::switchListBox()
2007-09-18 23:57:02 +00:00
{
if (!m_window)
openListBox();
2007-09-18 23:57:02 +00:00
else
closeListBox();
2007-09-18 23:57:02 +00:00
}
gfx::Rect ComboBox::getListBoxPos() const
2007-09-18 23:57:02 +00:00
{
gfx::Rect rc(gfx::Point(m_entry->rc->x1,
m_entry->rc->y2),
gfx::Point(m_button->rc->x2,
m_entry->rc->y2+jrect_h(m_window->rc)));
if (rc.y2() > JI_SCREEN_H)
rc.offset(0, -(rc.h+jrect_h(m_entry->rc)));
2007-09-18 23:57:02 +00:00
return rc;
}
void ComboBox::onChange()
{
Change();
}
} // namespace ui