mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-28 18:32:50 +00:00
Add addition/subtract/divide blending modes
Changes: * Added SeparatorInView() to add separators inside a ListBox or ComboBox. * Added BlendModeItem() to represent each item in the blending modes ComboBox. * Now a ComboBox can contain any kind of widgets as children (not just ListItem). This is required to add separators in the blending modes ComboBox. Feature request: https://community.aseprite.org/t/additive-blending-feature/121
This commit is contained in:
parent
4f4b21a521
commit
14ba0ab411
@ -171,6 +171,9 @@ Ignore this chunk if you find the new palette chunk (0x2019)
|
||||
Saturation = 13
|
||||
Color = 14
|
||||
Luminosity = 15
|
||||
Addition = 16
|
||||
Subtract = 17
|
||||
Divide = 18
|
||||
BYTE Opacity
|
||||
Note: valid only if file header flags field has bit 1 set
|
||||
BYTE[3] For future (set to zero)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/search_entry.h"
|
||||
#include "app/ui/select_accelerator.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/fs.h"
|
||||
@ -502,10 +503,8 @@ private:
|
||||
continue;
|
||||
|
||||
if (!group) {
|
||||
group = new Separator(
|
||||
group = new SeparatorInView(
|
||||
section()->children()[sectionIdx]->text(), HORIZONTAL);
|
||||
group->setStyle(SkinTheme::instance()->styles.separatorInView());
|
||||
|
||||
searchList()->addChild(group);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "app/context_access.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/transaction.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "app/ui/user_data_popup.h"
|
||||
#include "app/ui_context.h"
|
||||
@ -54,6 +55,18 @@ class LayerPropertiesWindow : public app::gen::LayerProperties
|
||||
, public doc::ContextObserver
|
||||
, public doc::DocumentObserver {
|
||||
public:
|
||||
class BlendModeItem : public ListItem {
|
||||
public:
|
||||
BlendModeItem(const std::string& name,
|
||||
const doc::BlendMode mode)
|
||||
: ListItem(name)
|
||||
, m_mode(mode) {
|
||||
}
|
||||
doc::BlendMode mode() const { return m_mode; }
|
||||
private:
|
||||
doc::BlendMode m_mode;
|
||||
};
|
||||
|
||||
LayerPropertiesWindow()
|
||||
: m_timer(250, this)
|
||||
, m_document(nullptr)
|
||||
@ -62,22 +75,30 @@ public:
|
||||
name()->setMinSize(gfx::Size(128, 0));
|
||||
name()->setExpansive(true);
|
||||
|
||||
mode()->addItem("Normal");
|
||||
mode()->addItem("Multiply");
|
||||
mode()->addItem("Screen");
|
||||
mode()->addItem("Overlay");
|
||||
mode()->addItem("Darken");
|
||||
mode()->addItem("Lighten");
|
||||
mode()->addItem("Color Dodge");
|
||||
mode()->addItem("Color Burn");
|
||||
mode()->addItem("Hard Light");
|
||||
mode()->addItem("Soft Light");
|
||||
mode()->addItem("Difference");
|
||||
mode()->addItem("Exclusion");
|
||||
mode()->addItem("Hue");
|
||||
mode()->addItem("Saturation");
|
||||
mode()->addItem("Color");
|
||||
mode()->addItem("Luminosity");
|
||||
mode()->addItem(new BlendModeItem("Normal", doc::BlendMode::NORMAL));
|
||||
mode()->addItem(new SeparatorInView);
|
||||
mode()->addItem(new BlendModeItem("Darken", doc::BlendMode::DARKEN));
|
||||
mode()->addItem(new BlendModeItem("Multiply", doc::BlendMode::MULTIPLY));
|
||||
mode()->addItem(new BlendModeItem("Color Burn", doc::BlendMode::COLOR_BURN));
|
||||
mode()->addItem(new SeparatorInView);
|
||||
mode()->addItem(new BlendModeItem("Lighten", doc::BlendMode::LIGHTEN));
|
||||
mode()->addItem(new BlendModeItem("Screen", doc::BlendMode::SCREEN));
|
||||
mode()->addItem(new BlendModeItem("Color Dodge", doc::BlendMode::COLOR_DODGE));
|
||||
mode()->addItem(new BlendModeItem("Addition", doc::BlendMode::ADDITION));
|
||||
mode()->addItem(new SeparatorInView);
|
||||
mode()->addItem(new BlendModeItem("Overlay", doc::BlendMode::OVERLAY));
|
||||
mode()->addItem(new BlendModeItem("Soft Light", doc::BlendMode::SOFT_LIGHT));
|
||||
mode()->addItem(new BlendModeItem("Hard Light", doc::BlendMode::HARD_LIGHT));
|
||||
mode()->addItem(new SeparatorInView);
|
||||
mode()->addItem(new BlendModeItem("Difference", doc::BlendMode::DIFFERENCE));
|
||||
mode()->addItem(new BlendModeItem("Exclusion", doc::BlendMode::EXCLUSION));
|
||||
mode()->addItem(new BlendModeItem("Subtract", doc::BlendMode::SUBTRACT));
|
||||
mode()->addItem(new BlendModeItem("Divide", doc::BlendMode::DIVIDE));
|
||||
mode()->addItem(new SeparatorInView);
|
||||
mode()->addItem(new BlendModeItem("Hue", doc::BlendMode::HSL_HUE));
|
||||
mode()->addItem(new BlendModeItem("Saturation", doc::BlendMode::HSL_SATURATION));
|
||||
mode()->addItem(new BlendModeItem("Color", doc::BlendMode::HSL_COLOR));
|
||||
mode()->addItem(new BlendModeItem("Luminosity", doc::BlendMode::HSL_LUMINOSITY));
|
||||
|
||||
name()->Change.connect(base::Bind<void>(&LayerPropertiesWindow::onStartTimer, this));
|
||||
mode()->Change.connect(base::Bind<void>(&LayerPropertiesWindow::onStartTimer, this));
|
||||
@ -120,7 +141,11 @@ private:
|
||||
}
|
||||
|
||||
BlendMode blendModeValue() const {
|
||||
return (BlendMode)mode()->getSelectedItemIndex();
|
||||
BlendModeItem* item = dynamic_cast<BlendModeItem*>(mode()->getSelectedItem());
|
||||
if (item)
|
||||
return item->mode();
|
||||
else
|
||||
return doc::BlendMode::NORMAL;
|
||||
}
|
||||
|
||||
int opacityValue() const {
|
||||
@ -290,7 +315,15 @@ private:
|
||||
name()->setEnabled(true);
|
||||
|
||||
if (m_layer->isImage()) {
|
||||
mode()->setSelectedItemIndex((int)static_cast<LayerImage*>(m_layer)->blendMode());
|
||||
mode()->setSelectedItem(nullptr);
|
||||
for (auto item : *mode()) {
|
||||
if (auto blendModeItem = dynamic_cast<BlendModeItem*>(item)) {
|
||||
if (blendModeItem->mode() == static_cast<LayerImage*>(m_layer)->blendMode()) {
|
||||
mode()->setSelectedItem(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mode()->setEnabled(!m_layer->isBackground());
|
||||
opacity()->setValue(static_cast<LayerImage*>(m_layer)->opacity());
|
||||
opacity()->setEnabled(!m_layer->isBackground());
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/send_crash.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
@ -623,9 +624,8 @@ private:
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
auto sep = new Separator(base::normalize_path(path), HORIZONTAL);
|
||||
sep->setStyle(theme->styles.separatorInView());
|
||||
themeList()->addChild(sep);
|
||||
themeList()->addChild(
|
||||
new SeparatorInView(base::normalize_path(path), HORIZONTAL));
|
||||
}
|
||||
|
||||
ThemeItem* item = new ThemeItem(fullPath, fn);
|
||||
@ -648,9 +648,8 @@ private:
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
auto sep = new Separator("Extension Themes", HORIZONTAL);
|
||||
sep->setStyle(theme->styles.separatorInView());
|
||||
themeList()->addChild(sep);
|
||||
themeList()->addChild(
|
||||
new Separator("Extension Themes", HORIZONTAL));
|
||||
}
|
||||
|
||||
for (auto it : ext->themes()) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/ui/browser_view.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/workspace.h"
|
||||
#include "base/file_handle.h"
|
||||
@ -427,8 +428,7 @@ private:
|
||||
}
|
||||
|
||||
void addSeparator() {
|
||||
auto sep = new Separator("", HORIZONTAL);
|
||||
sep->setStyle(SkinTheme::instance()->styles.separatorInView());
|
||||
auto sep = new SeparatorInView(std::string(), HORIZONTAL);
|
||||
sep->setBorder(gfx::Border(0, font()->height(), 0, font()->height()));
|
||||
sep->setExpansive(true);
|
||||
addChild(sep);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "app/crash/session.h"
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/drop_down_button.h"
|
||||
#include "app/ui/separator_in_view.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui/workspace.h"
|
||||
#include "base/bind.h"
|
||||
@ -114,8 +115,7 @@ void DataRecoveryView::fillList()
|
||||
if (session->isEmpty())
|
||||
continue;
|
||||
|
||||
auto sep = new Separator(session->name(), HORIZONTAL);
|
||||
sep->setStyle(SkinTheme::instance()->styles.separatorInView());
|
||||
auto sep = new SeparatorInView(session->name(), HORIZONTAL);
|
||||
sep->setBorder(sep->border() + gfx::Border(0, 8, 0, 8)*guiscale());
|
||||
m_listBox.addChild(sep);
|
||||
|
||||
|
@ -263,11 +263,12 @@ public:
|
||||
std::string extrasLabel() const {
|
||||
std::string label = "Resize: " + m_extras->resize()->getSelectedItem()->text();
|
||||
|
||||
auto layerItem = m_extras->layers()->getSelectedItem();
|
||||
if (layerItem && !layerItem->getValue().empty())
|
||||
auto layerItem = dynamic_cast<ListItem*>(m_extras->layers()->getSelectedItem());
|
||||
if (layerItem &&
|
||||
!layerItem->getValue().empty())
|
||||
label += ", " + layerItem->text();
|
||||
|
||||
auto frameItem = m_extras->frames()->getSelectedItem();
|
||||
auto frameItem = dynamic_cast<ListItem*>(m_extras->frames()->getSelectedItem());
|
||||
if (frameItem && !frameItem->getValue().empty())
|
||||
label += ", " + frameItem->text();
|
||||
|
||||
@ -871,7 +872,8 @@ void FileSelector::onFileTypeChange()
|
||||
|
||||
if (m_type == FileSelectorType::Open ||
|
||||
m_type == FileSelectorType::OpenMultiple) {
|
||||
std::string origShowExtensions = fileType()->getItem(0)->getValue();
|
||||
std::string origShowExtensions =
|
||||
dynamic_cast<ListItem*>(fileType()->getItem(0))->getValue();
|
||||
preferred_open_extensions[origShowExtensions] = fileType()->getValue();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2016 David Capello
|
||||
// Copyright (C) 2016-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -58,10 +58,10 @@ FrameListItem::FrameListItem(doc::FrameTag* tag)
|
||||
void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer)
|
||||
{
|
||||
int i = layers->addItem("Visible layers");
|
||||
layers->getItem(i)->setValue(kAllLayers);
|
||||
dynamic_cast<LayerListItem*>(layers->getItem(i))->setValue(kAllLayers);
|
||||
|
||||
i = layers->addItem("Selected layers");
|
||||
layers->getItem(i)->setValue(kSelectedLayers);
|
||||
dynamic_cast<LayerListItem*>(layers->getItem(i))->setValue(kSelectedLayers);
|
||||
if (defLayer == kSelectedLayers)
|
||||
layers->setSelectedItemIndex(i);
|
||||
|
||||
@ -77,10 +77,10 @@ void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const
|
||||
void fill_frames_combobox(const doc::Sprite* sprite, ui::ComboBox* frames, const std::string& defFrame)
|
||||
{
|
||||
int i = frames->addItem("All frames");
|
||||
frames->getItem(i)->setValue(kAllFrames);
|
||||
dynamic_cast<FrameListItem*>(frames->getItem(i))->setValue(kAllFrames);
|
||||
|
||||
i = frames->addItem("Selected frames");
|
||||
frames->getItem(i)->setValue(kSelectedFrames);
|
||||
dynamic_cast<FrameListItem*>(frames->getItem(i))->setValue(kSelectedFrames);
|
||||
if (defFrame == kSelectedFrames)
|
||||
frames->setSelectedItemIndex(i);
|
||||
|
||||
|
29
src/app/ui/separator_in_view.h
Normal file
29
src/app/ui/separator_in_view.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_SEPARATOR_IN_VIEW_H_INCLUDED
|
||||
#define APP_UI_SEPARATOR_IN_VIEW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "ui/separator.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class SeparatorInView : public ui::Separator {
|
||||
public:
|
||||
SeparatorInView(const std::string& text = std::string(),
|
||||
int align = ui::HORIZONTAL)
|
||||
: Separator(text, align) {
|
||||
setStyle(skin::SkinTheme::instance()->styles.separatorInView());
|
||||
if (text.empty())
|
||||
setBorder(border() + gfx::Border(0, 2, 0, 2)*ui::guiscale());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -37,6 +37,16 @@ namespace {
|
||||
#define blend_difference(b, s) (ABS((b) - (s)))
|
||||
#define blend_exclusion(b, s, t) ((t) = MUL_UN8((b), (s), (t)), ((b) + (s) - 2*(t)))
|
||||
|
||||
inline uint32_t blend_divide(uint32_t b, uint32_t s)
|
||||
{
|
||||
if (b == 0)
|
||||
return 0;
|
||||
else if (b >= s)
|
||||
return 255;
|
||||
else
|
||||
return DIV_UN8(b, s); // return b / s
|
||||
}
|
||||
|
||||
inline uint32_t blend_color_dodge(uint32_t b, uint32_t s)
|
||||
{
|
||||
if (b == 0)
|
||||
@ -432,6 +442,33 @@ color_t rgba_blender_hsl_luminosity(color_t backdrop, color_t src, int opacity)
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_addition(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = rgba_getr(backdrop) + rgba_getr(src);
|
||||
int g = rgba_getg(backdrop) + rgba_getg(src);
|
||||
int b = rgba_getb(backdrop) + rgba_getb(src);
|
||||
src = rgba(MIN(r, 255), MIN(g, 255), MIN(b, 255), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_subtract(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = rgba_getr(backdrop) - rgba_getr(src);
|
||||
int g = rgba_getg(backdrop) - rgba_getg(src);
|
||||
int b = rgba_getb(backdrop) - rgba_getb(src);
|
||||
src = rgba(MAX(r, 0), MAX(g, 0), MAX(b, 0), 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t rgba_blender_divide(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int r = blend_divide(rgba_getr(backdrop), rgba_getr(src));
|
||||
int g = blend_divide(rgba_getg(backdrop), rgba_getg(src));
|
||||
int b = blend_divide(rgba_getb(backdrop), rgba_getb(src));
|
||||
src = rgba(r, g, b, 0) | (src & rgba_a_mask);
|
||||
return rgba_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// GRAY blenders
|
||||
|
||||
@ -591,6 +628,27 @@ color_t graya_blender_exclusion(color_t backdrop, color_t src, int opacity)
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_addition(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = graya_getv(backdrop) + graya_getv(src);
|
||||
src = graya(MIN(v, 255), 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_subtract(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = graya_getv(backdrop) - graya_getv(src);
|
||||
src = graya(MAX(v, 0), 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
color_t graya_blender_divide(color_t backdrop, color_t src, int opacity)
|
||||
{
|
||||
int v = blend_divide(graya_getv(backdrop), graya_getv(src));
|
||||
src = graya(v, 0) | (src & graya_a_mask);
|
||||
return graya_blender_normal(backdrop, src, opacity);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// indexed
|
||||
|
||||
@ -627,6 +685,9 @@ BlendFunc get_rgba_blender(BlendMode blendmode)
|
||||
case BlendMode::HSL_SATURATION: return rgba_blender_hsl_saturation;
|
||||
case BlendMode::HSL_COLOR: return rgba_blender_hsl_color;
|
||||
case BlendMode::HSL_LUMINOSITY: return rgba_blender_hsl_luminosity;
|
||||
case BlendMode::ADDITION: return rgba_blender_addition;
|
||||
case BlendMode::SUBTRACT: return rgba_blender_subtract;
|
||||
case BlendMode::DIVIDE: return rgba_blender_divide;
|
||||
}
|
||||
ASSERT(false);
|
||||
return rgba_blender_src;
|
||||
@ -657,6 +718,9 @@ BlendFunc get_graya_blender(BlendMode blendmode)
|
||||
case BlendMode::HSL_SATURATION: return graya_blender_normal;
|
||||
case BlendMode::HSL_COLOR: return graya_blender_normal;
|
||||
case BlendMode::HSL_LUMINOSITY: return graya_blender_normal;
|
||||
case BlendMode::ADDITION: return graya_blender_addition;
|
||||
case BlendMode::SUBTRACT: return graya_blender_subtract;
|
||||
case BlendMode::DIVIDE: return graya_blender_divide;
|
||||
}
|
||||
ASSERT(false);
|
||||
return graya_blender_src;
|
||||
|
@ -36,6 +36,9 @@ namespace doc {
|
||||
color_t rgba_blender_hsl_saturation(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_hsl_color(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_hsl_luminosity(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_addition(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_subtract(color_t backdrop, color_t src, int opacity);
|
||||
color_t rgba_blender_divide(color_t backdrop, color_t src, int opacity);
|
||||
|
||||
color_t graya_blender_src(color_t backdrop, color_t src, int opacity);
|
||||
color_t graya_blender_merge(color_t backdrop, color_t src, int opacity);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
// Copyright (c) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -37,7 +37,10 @@ namespace doc {
|
||||
HSL_HUE = 12,
|
||||
HSL_SATURATION = 13,
|
||||
HSL_COLOR = 14,
|
||||
HSL_LUMINOSITY = 15
|
||||
HSL_LUMINOSITY = 15,
|
||||
ADDITION = 16,
|
||||
SUBTRACT = 17,
|
||||
DIVIDE = 18
|
||||
};
|
||||
|
||||
std::string blend_mode_to_string(BlendMode blendMode);
|
||||
|
@ -146,7 +146,7 @@ void ComboBox::setUseCustomWidget(bool state)
|
||||
m_useCustomWidget = state;
|
||||
}
|
||||
|
||||
int ComboBox::addItem(ListItem* item)
|
||||
int ComboBox::addItem(Widget* item)
|
||||
{
|
||||
bool sel_first = m_items.empty();
|
||||
|
||||
@ -163,7 +163,7 @@ int ComboBox::addItem(const std::string& text)
|
||||
return addItem(new ListItem(text));
|
||||
}
|
||||
|
||||
void ComboBox::insertItem(int itemIndex, ListItem* item)
|
||||
void ComboBox::insertItem(int itemIndex, Widget* item)
|
||||
{
|
||||
bool sel_first = m_items.empty();
|
||||
|
||||
@ -178,12 +178,10 @@ void ComboBox::insertItem(int itemIndex, const std::string& text)
|
||||
insertItem(itemIndex, new ListItem(text));
|
||||
}
|
||||
|
||||
void ComboBox::removeItem(ListItem* item)
|
||||
void ComboBox::removeItem(Widget* item)
|
||||
{
|
||||
ListItems::iterator it = std::find(m_items.begin(), m_items.end(), item);
|
||||
|
||||
auto it = std::find(m_items.begin(), m_items.end(), item);
|
||||
ASSERT(it != m_items.end());
|
||||
|
||||
if (it != m_items.end())
|
||||
m_items.erase(it);
|
||||
|
||||
@ -194,7 +192,7 @@ void ComboBox::removeItem(int itemIndex)
|
||||
{
|
||||
ASSERT(itemIndex >= 0 && (std::size_t)itemIndex < m_items.size());
|
||||
|
||||
ListItem* item = m_items[itemIndex];
|
||||
Widget* item = m_items[itemIndex];
|
||||
|
||||
m_items.erase(m_items.begin() + itemIndex);
|
||||
delete item;
|
||||
@ -202,9 +200,8 @@ void ComboBox::removeItem(int itemIndex)
|
||||
|
||||
void ComboBox::removeAllItems()
|
||||
{
|
||||
ListItems::iterator it, end = m_items.end();
|
||||
for (it = m_items.begin(); it != end; ++it)
|
||||
delete *it;
|
||||
for (Widget* item : m_items)
|
||||
delete item; // widget
|
||||
|
||||
m_items.clear();
|
||||
m_selected = -1;
|
||||
@ -215,7 +212,7 @@ int ComboBox::getItemCount() const
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
ListItem* ComboBox::getItem(int itemIndex)
|
||||
Widget* ComboBox::getItem(int itemIndex)
|
||||
{
|
||||
if (itemIndex >= 0 && (std::size_t)itemIndex < m_items.size()) {
|
||||
return m_items[itemIndex];
|
||||
@ -227,7 +224,7 @@ ListItem* ComboBox::getItem(int itemIndex)
|
||||
const std::string& ComboBox::getItemText(int itemIndex) const
|
||||
{
|
||||
if (itemIndex >= 0 && (std::size_t)itemIndex < m_items.size()) {
|
||||
ListItem* item = m_items[itemIndex];
|
||||
Widget* item = m_items[itemIndex];
|
||||
return item->text();
|
||||
}
|
||||
else {
|
||||
@ -241,14 +238,14 @@ void ComboBox::setItemText(int itemIndex, const std::string& text)
|
||||
{
|
||||
ASSERT(itemIndex >= 0 && (std::size_t)itemIndex < m_items.size());
|
||||
|
||||
ListItem* item = m_items[itemIndex];
|
||||
Widget* item = m_items[itemIndex];
|
||||
item->setText(text);
|
||||
}
|
||||
|
||||
int ComboBox::findItemIndex(const std::string& text) const
|
||||
{
|
||||
int i = 0;
|
||||
for (const ListItem* item : m_items) {
|
||||
for (const Widget* item : m_items) {
|
||||
if ((m_casesensitive && item->text() == text) ||
|
||||
(!m_casesensitive && item->text() == text)) {
|
||||
return i;
|
||||
@ -261,27 +258,30 @@ int ComboBox::findItemIndex(const std::string& text) const
|
||||
int ComboBox::findItemIndexByValue(const std::string& value) const
|
||||
{
|
||||
int i = 0;
|
||||
for (const ListItem* item : m_items) {
|
||||
if (item->getValue() == value)
|
||||
return i;
|
||||
i++;
|
||||
for (const Widget* item : m_items) {
|
||||
if (auto listItem = dynamic_cast<const ListItem*>(item)) {
|
||||
if (listItem->getValue() == value)
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListItem* ComboBox::getSelectedItem() const
|
||||
Widget* ComboBox::getSelectedItem() const
|
||||
{
|
||||
return (!m_items.empty() ? m_items[m_selected]: NULL);
|
||||
}
|
||||
|
||||
void ComboBox::setSelectedItem(ListItem* item)
|
||||
void ComboBox::setSelectedItem(Widget* item)
|
||||
{
|
||||
ListItems::iterator it = std::find(m_items.begin(), m_items.end(), item);
|
||||
|
||||
ASSERT(it != m_items.end());
|
||||
|
||||
auto it = std::find(m_items.begin(), m_items.end(), item);
|
||||
if (it != m_items.end())
|
||||
setSelectedItemIndex(std::distance(m_items.begin(), it));
|
||||
else if (m_selected >= 0) {
|
||||
m_selected = -1;
|
||||
onChange();
|
||||
}
|
||||
}
|
||||
|
||||
int ComboBox::getSelectedItemIndex() const
|
||||
@ -296,8 +296,8 @@ void ComboBox::setSelectedItemIndex(int itemIndex)
|
||||
m_selected != itemIndex) {
|
||||
m_selected = itemIndex;
|
||||
|
||||
ListItems::iterator it = m_items.begin() + itemIndex;
|
||||
ListItem* item = *it;
|
||||
auto it = m_items.begin() + itemIndex;
|
||||
Widget* item = *it;
|
||||
m_entry->setText(item->text());
|
||||
if (isEditable())
|
||||
m_entry->setCaretToEnd();
|
||||
@ -310,13 +310,12 @@ std::string ComboBox::getValue() const
|
||||
{
|
||||
if (isEditable())
|
||||
return m_entry->text();
|
||||
else {
|
||||
int index = getSelectedItemIndex();
|
||||
if (index >= 0)
|
||||
return m_items[index]->getValue();
|
||||
else
|
||||
return std::string();
|
||||
int index = getSelectedItemIndex();
|
||||
if (index >= 0) {
|
||||
if (auto listItem = dynamic_cast<ListItem*>(m_items[index]))
|
||||
return listItem->getValue();
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void ComboBox::setValue(const std::string& value)
|
||||
@ -419,8 +418,8 @@ void ComboBox::onSizeHint(SizeHintEvent& ev)
|
||||
Size reqSize = entrySize;
|
||||
|
||||
// Get the text-length of every item
|
||||
ListItems::iterator it, end = m_items.end();
|
||||
for (it = m_items.begin(); it != end; ++it) {
|
||||
auto end = m_items.end();
|
||||
for (auto it = m_items.begin(); it != end; ++it) {
|
||||
int item_w =
|
||||
2*guiscale()+
|
||||
font()->textLength((*it)->text().c_str())+
|
||||
@ -603,7 +602,7 @@ void ComboBox::openListBox()
|
||||
gfx::Size size;
|
||||
size.w = m_button->bounds().x2() - entryBounds.x - view->border().width();
|
||||
size.h = viewport->border().height();
|
||||
for (ListItem* item : m_items)
|
||||
for (Widget* item : m_items)
|
||||
size.h += item->sizeHint().h;
|
||||
|
||||
int max = MAX(entryBounds.y, ui::display_h() - entryBounds.y2()) - 8*guiscale();
|
||||
@ -710,7 +709,7 @@ void ComboBox::putSelectedItemAsCustomWidget()
|
||||
if (!useCustomWidget())
|
||||
return;
|
||||
|
||||
ListItem* item = getSelectedItem();
|
||||
Widget* item = getSelectedItem();
|
||||
if (item && item->parent() == nullptr) {
|
||||
if (!m_listbox) {
|
||||
item->setBounds(m_entry->childrenBounds());
|
||||
|
@ -20,7 +20,6 @@ namespace ui {
|
||||
class Entry;
|
||||
class Event;
|
||||
class ListBox;
|
||||
class ListItem;
|
||||
class Window;
|
||||
|
||||
class ComboBoxEntry;
|
||||
@ -31,13 +30,13 @@ namespace ui {
|
||||
friend class ComboBoxListBox;
|
||||
|
||||
public:
|
||||
typedef std::vector<ListItem*> ListItems;
|
||||
typedef std::vector<Widget*> Items;
|
||||
|
||||
ComboBox();
|
||||
~ComboBox();
|
||||
|
||||
ListItems::iterator begin() { return m_items.begin(); }
|
||||
ListItems::iterator end() { return m_items.end(); }
|
||||
Items::iterator begin() { return m_items.begin(); }
|
||||
Items::iterator end() { return m_items.end(); }
|
||||
|
||||
void setEditable(bool state);
|
||||
void setClickOpen(bool state);
|
||||
@ -49,13 +48,13 @@ namespace ui {
|
||||
bool isCaseSensitive() const { return m_casesensitive; }
|
||||
bool useCustomWidget() const { return m_useCustomWidget; }
|
||||
|
||||
int addItem(ListItem* item);
|
||||
int addItem(Widget* item);
|
||||
int addItem(const std::string& text);
|
||||
void insertItem(int itemIndex, ListItem* item);
|
||||
void insertItem(int itemIndex, Widget* item);
|
||||
void insertItem(int itemIndex, const std::string& text);
|
||||
|
||||
// Removes the given item (you must delete it).
|
||||
void removeItem(ListItem* item);
|
||||
void removeItem(Widget* item);
|
||||
|
||||
// Removes and deletes the given item.
|
||||
void removeItem(int itemIndex);
|
||||
@ -64,14 +63,14 @@ namespace ui {
|
||||
|
||||
int getItemCount() const;
|
||||
|
||||
ListItem* getItem(int itemIndex);
|
||||
Widget* getItem(int itemIndex);
|
||||
const std::string& getItemText(int itemIndex) const;
|
||||
void setItemText(int itemIndex, const std::string& text);
|
||||
int findItemIndex(const std::string& text) const;
|
||||
int findItemIndexByValue(const std::string& value) const;
|
||||
|
||||
ListItem* getSelectedItem() const;
|
||||
void setSelectedItem(ListItem* item);
|
||||
Widget* getSelectedItem() const;
|
||||
void setSelectedItem(Widget* item);
|
||||
|
||||
int getSelectedItemIndex() const;
|
||||
void setSelectedItemIndex(int itemIndex);
|
||||
@ -110,7 +109,7 @@ namespace ui {
|
||||
Button* m_button;
|
||||
Window* m_window;
|
||||
ComboBoxListBox* m_listbox;
|
||||
ListItems m_items;
|
||||
Items m_items;
|
||||
int m_selected;
|
||||
bool m_editable;
|
||||
bool m_clickopen;
|
||||
|
@ -13,8 +13,9 @@
|
||||
#include "base/fs.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/resize_event.h"
|
||||
#include "ui/separator.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
#include "ui/view.h"
|
||||
@ -437,7 +438,11 @@ int ListBox::advanceIndexThroughVisibleItems(
|
||||
}
|
||||
else {
|
||||
Widget* item = getChildByIndex(index);
|
||||
if (item && !item->hasFlags(HIDDEN)) {
|
||||
if (item &&
|
||||
!item->hasFlags(HIDDEN) &&
|
||||
// We can completelly ignore separators from navigation
|
||||
// keys.
|
||||
!dynamic_cast<Separator*>(item)) {
|
||||
lastVisibleIndex = index;
|
||||
delta -= sgn;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user