lib_ui/ui/abstract_button.h
Reza Bakhshi Laktasaraei 0459e12760 Use List/ListItem accessibility role for the folders strip
Rename AbstractButton's page-tab flag to list-item (setIsListItem /
isListItem), so a flagged button reports the ListItem role instead of
PageTab - mirroring how the menu-button flag maps to ButtonMenu. A list
of items matches NVDA's native single-selection list behaviour better
than a tab control for the chat-folders strip.

Add an explicit opt-in, RpWidget::accessibilitySelectionList() (default
false), for a single-selection list whose accessible focus tracks its
selected item. When set, Ui::Accessible::Widget exposes
QAccessibleSelectionInterface and forwards container SetFocus/focusChild
to the selected child - keyed on the opt-in, NOT on the List role, so
plain lists (e.g. message history, which keeps focus and selection
separate) are unaffected and don't advertise a single-selection interface
whose clear()/unselect()/selectAll() always fail.

select() invokes pressAction() - a list item only implements pressAction,
not the toggleAction() Qt's default ListItem path would call - and rejects
items that are not selectable, so a locked folder is never claimed as a
successful selection. A locked folder reports selectable = false.
2026-06-26 14:29:15 +04:00

142 lines
3.4 KiB
C++

// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include <rpl/event_stream.h>
#include "ui/rp_widget.h"
#include "base/flags.h"
namespace Ui {
class AbstractButton : public RpWidget {
public:
AbstractButton(QWidget *parent);
[[nodiscard]] Qt::KeyboardModifiers clickModifiers() const {
return _modifiers;
}
void setDisabled(bool disabled = true);
virtual void clearState();
[[nodiscard]] bool isOver() const {
return _state & StateFlag::Over;
}
[[nodiscard]] bool isDown() const {
return _state & StateFlag::Down;
}
[[nodiscard]] bool isDisabled() const {
return _state & StateFlag::Disabled;
}
void setSynteticOver(bool over) {
setOver(over, StateChangeSource::ByPress);
}
void setSynteticDown(bool down, Qt::MouseButton button = Qt::LeftButton) {
setDown(down, StateChangeSource::ByPress, {}, button);
}
void setPointerCursor(bool enablePointerCursor);
void setAcceptBoth(bool acceptBoth = true, bool triggerOnPress = false);
void setClickedCallback(Fn<void()> callback) {
_clickedCallback = std::move(callback);
}
rpl::producer<Qt::MouseButton> clicks() const {
return _clicks.events();
}
template <typename Handler>
void addClickHandler(Handler &&handler) {
clicks(
) | rpl::on_next(
std::forward<Handler>(handler),
lifetime());
}
void clicked(Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
void setIsMenuButton(bool value) {
_menuButton = value;
}
void setIsListItem(bool value) {
_listItem = value;
}
[[nodiscard]] bool isListItem() const {
return _listItem;
}
QAccessible::Role accessibilityRole() override {
return _listItem
? QAccessible::ListItem
: _menuButton
? QAccessible::ButtonMenu
: QAccessible::Button;
}
AccessibilityState accessibilityState() const override;
void accessibilityDoAction(const QString &name) override;
protected:
void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void keyReleaseEvent(QKeyEvent *e) override;
protected:
enum class StateFlag {
None = 0,
Over = (1 << 0),
Down = (1 << 1),
Disabled = (1 << 2),
};
friend constexpr bool is_flag_type(StateFlag) { return true; };
using State = base::flags<StateFlag>;
State state() const {
return _state;
}
enum class StateChangeSource {
ByUser = 0x00,
ByPress = 0x01,
ByHover = 0x02,
};
void setOver(bool over, StateChangeSource source = StateChangeSource::ByUser);
bool setDown(
bool down,
StateChangeSource source,
Qt::KeyboardModifiers modifiers,
Qt::MouseButton button);
virtual void onStateChanged(State was, StateChangeSource source) {
}
private:
void updateCursor();
void checkIfOver(QPoint localPos);
[[nodiscard]] bool isSubmitEvent(not_null<QKeyEvent*> e) const;
State _state = StateFlag::None;
Qt::KeyboardModifiers _modifiers;
bool _enablePointerCursor : 1 = true;
bool _pointerCursor : 1 = false;
bool _acceptBoth : 1 = false;
bool _triggerOnPress : 1 = false;
bool _menuButton : 1 = false;
bool _listItem : 1 = false;
Fn<void()> _clickedCallback;
rpl::event_stream<Qt::MouseButton> _clicks;
};
} // namespace Ui