diff --git a/docs/ase-file-specs.md b/docs/ase-file-specs.md index eefcbe0c5..1e2fab9c3 100644 --- a/docs/ase-file-specs.md +++ b/docs/ase-file-specs.md @@ -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) diff --git a/src/app/commands/cmd_keyboard_shortcuts.cpp b/src/app/commands/cmd_keyboard_shortcuts.cpp index b3fdf63a5..a1513b31f 100644 --- a/src/app/commands/cmd_keyboard_shortcuts.cpp +++ b/src/app/commands/cmd_keyboard_shortcuts.cpp @@ -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); } diff --git a/src/app/commands/cmd_layer_properties.cpp b/src/app/commands/cmd_layer_properties.cpp index d39e65c59..1f1461ab7 100644 --- a/src/app/commands/cmd_layer_properties.cpp +++ b/src/app/commands/cmd_layer_properties.cpp @@ -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()); diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp index 2737381ea..c73ad9763 100644 --- a/src/app/commands/cmd_options.cpp +++ b/src/app/commands/cmd_options.cpp @@ -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()) { diff --git a/src/app/ui/browser_view.cpp b/src/app/ui/browser_view.cpp index 23c6a608d..00e6325e8 100644 --- a/src/app/ui/browser_view.cpp +++ b/src/app/ui/browser_view.cpp @@ -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); diff --git a/src/app/ui/data_recovery_view.cpp b/src/app/ui/data_recovery_view.cpp index 7f74fc664..04e6c8ac2 100644 --- a/src/app/ui/data_recovery_view.cpp +++ b/src/app/ui/data_recovery_view.cpp @@ -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); diff --git a/src/app/ui/file_selector.cpp b/src/app/ui/file_selector.cpp index 63570a6d2..539889641 100644 --- a/src/app/ui/file_selector.cpp +++ b/src/app/ui/file_selector.cpp @@ -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(); } } diff --git a/src/app/ui/layer_frame_comboboxes.cpp b/src/app/ui/layer_frame_comboboxes.cpp index dd5c93e65..e89949f9c 100644 --- a/src/app/ui/layer_frame_comboboxes.cpp +++ b/src/app/ui/layer_frame_comboboxes.cpp @@ -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); diff --git a/src/app/ui/separator_in_view.h b/src/app/ui/separator_in_view.h new file mode 100644 index 000000000..2b85e1759 --- /dev/null +++ b/src/app/ui/separator_in_view.h @@ -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 diff --git a/src/doc/blend_funcs.cpp b/src/doc/blend_funcs.cpp index 91f5376b0..3dfdaa9d9 100644 --- a/src/doc/blend_funcs.cpp +++ b/src/doc/blend_funcs.cpp @@ -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; diff --git a/src/doc/blend_funcs.h b/src/doc/blend_funcs.h index 595bb3b30..d4b91beee 100644 --- a/src/doc/blend_funcs.h +++ b/src/doc/blend_funcs.h @@ -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); diff --git a/src/doc/blend_mode.h b/src/doc/blend_mode.h index f26e04c56..f62e49d9e 100644 --- a/src/doc/blend_mode.h +++ b/src/doc/blend_mode.h @@ -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); diff --git a/src/ui/combobox.cpp b/src/ui/combobox.cpp index 27b9faca4..98741d9f0 100644 --- a/src/ui/combobox.cpp +++ b/src/ui/combobox.cpp @@ -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()); diff --git a/src/ui/combobox.h b/src/ui/combobox.h index b01f8f089..9a3a0785a 100644 --- a/src/ui/combobox.h +++ b/src/ui/combobox.h @@ -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; diff --git a/src/ui/listbox.cpp b/src/ui/listbox.cpp index ff669b487..655e72025 100644 --- a/src/ui/listbox.cpp +++ b/src/ui/listbox.cpp @@ -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; }