4#include <arkui/native_type.h>
5#include <arkui/ui_input_event.h>
7#include <qarkui/qembeddedwindownode.h>
9#include <ace/xcomponent/native_interface_xcomponent.h>
10#include <arkui/native_gesture.h>
11#include <arkui/native_interface.h>
12#include <arkui/native_node.h>
13#include <native_window/external_window.h>
14#include <qarkui/qarkuiutils.h>
15#include <qarkui/qohosdragaction.h>
16#include <qohosutils.h>
17#include <qpa/qplatformtheme.h>
18#include <private/qguiapplication_p.h>
19#include <render/qxcomponent.h>
28std::shared_ptr<ArkUI_DragPreviewOption> makeDragPreviewOption()
31 QArkUi::callArkUiOrFailOnNullResult(
32 Q_OHOS_NAMED_FUNC(::OH_ArkUI_CreateDragPreviewOption)),
33 [](ArkUI_DragPreviewOption *option) {
35 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragPreviewOption_Dispose),
41class NativeNodeCallbackDispatcher
44 static std::shared_ptr<
void> registerCallbackReceiver(
48 static void handleGestureEvent(
50 static void handlePinchGestureEvent(::ArkUI_GestureEvent *event,
void *extraParam);
51 static void handleRotationGestureEvent(::ArkUI_GestureEvent *event,
void *extraParam);
54std::shared_ptr<
void> NativeNodeCallbackDispatcher::registerCallbackReceiver(
57 auto *gestureApi =
reinterpret_cast<ArkUI_NativeGestureAPI_1 *>(
58 ::OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE,
"ArkUI_NativeGestureAPI_1"));
60 if (gestureApi ==
nullptr) {
62 "::OH_ArkUI_QueryModuleInterface failed to return ArkUI_NativeGestureAPI_1 module");
66 ArkUI_GestureEventActionTypeMask action_type = GESTURE_EVENT_ACTION_ACCEPT
67 | GESTURE_EVENT_ACTION_UPDATE | GESTURE_EVENT_ACTION_END | GESTURE_EVENT_ACTION_CANCEL;
69 constexpr int32_t fingersNum = 2;
70 constexpr double minimumDistanceToTriggerGesture = 5.0;
72 gestureApi->createPinchGesture(fingersNum, minimumDistanceToTriggerGesture);
73 gestureApi->setGestureEventTarget(
74 pinchGesture, action_type, embeddedWindowNode,
75 &NativeNodeCallbackDispatcher::handlePinchGestureEvent);
77 const double minimumAngleToTriggerGesture = 1.0;
78 auto *rotationGesture =
79 gestureApi->createRotationGesture(fingersNum, minimumAngleToTriggerGesture);
80 gestureApi->setGestureEventTarget(
81 rotationGesture, action_type, embeddedWindowNode,
82 &NativeNodeCallbackDispatcher::handleRotationGestureEvent);
84 auto *groupGesture = gestureApi->createGroupGesture(::PARALLEL_GROUP);
85 gestureApi->addChildGesture(groupGesture, pinchGesture);
86 gestureApi->addChildGesture(groupGesture, rotationGesture);
87 gestureApi->addGestureToNode(nodeHandle, groupGesture, ::PARALLEL, ::NORMAL_GESTURE_MASK);
89 return QtOhos::makeDestroyNotifier(
90 [nodeHandle, gestureApi, groupGesture, pinchGesture, rotationGesture]() {
91 qOhosPrintfDebug(
"Unregistering gestures for NativeNode %p", nodeHandle);
92 gestureApi->removeGestureFromNode(nodeHandle, groupGesture);
93 gestureApi->removeChildGesture(groupGesture, pinchGesture);
94 gestureApi->removeChildGesture(groupGesture, rotationGesture);
95 gestureApi->dispose(pinchGesture);
96 gestureApi->dispose(rotationGesture);
97 gestureApi->dispose(groupGesture);
101void NativeNodeCallbackDispatcher::handleGestureEvent(
104 const auto *embeddedWindowNode =
reinterpret_cast<
const QEmbeddedWindowNode *>(extraParams);
112void NativeNodeCallbackDispatcher::handlePinchGestureEvent(
113 ::ArkUI_GestureEvent *event,
void *extraParams)
115 handleGestureEvent(event, extraParams, NativeGestureInfo::GestureType::Pinch);
118void NativeNodeCallbackDispatcher::handleRotationGestureEvent(
119 ::ArkUI_GestureEvent *event,
void *extraParams)
121 handleGestureEvent(event, extraParams, NativeGestureInfo::GestureType::Rotation);
124void attachNativeRootNodeOrFail(
QXComponentNode parent, ::ArkUI_NodeHandle node)
126 qOhosPrintfDebug(
"%s: parentXc: %p node: %p", Q_FUNC_INFO, parent.handle(), node);
127 auto errorCode = ::OH_NativeXComponent_AttachNativeRootNode(parent.handle(), node);
128 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
129 qOhosReportFatalErrorAndAbort(
130 "OH_NativeXComponent_AttachNativeRootNode failed with error: %d", errorCode);
134void detachNativeRootNodeOrFail(
QXComponentNode parent, ::ArkUI_NodeHandle node)
136 qOhosPrintfDebug(
"%s: parentXc: %p node: %p", Q_FUNC_INFO, parent.handle(), node);
137 auto errorCode = ::OH_NativeXComponent_DetachNativeRootNode(parent.handle(), node);
138 if (errorCode != ARKUI_ERROR_CODE_NO_ERROR) {
139 qOhosReportFatalErrorAndAbort(
140 "OH_NativeXComponent_DetachNativeRootNode failed with error: %d", errorCode);
144std::shared_ptr<::OH_Pixelmap_ImageInfo> makeNativePixelMapImageInfo()
146 ::OH_Pixelmap_ImageInfo *imageInfo;
147 QArkUi::callArkUiOrFailOnErrorResult(
148 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_Create),
151 return {imageInfo, &OH_PixelmapImageInfo_Release};
154std::shared_ptr<OH_Pixelmap_ImageInfo> getNativePixelMapImageInfo(::OH_PixelmapNative *pixelMap)
156 auto imageInfo = makeNativePixelMapImageInfo();
158 QArkUi::callArkUiOrFailOnErrorResult(
159 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_GetImageInfo),
160 pixelMap, imageInfo.get());
165std::tuple<
std::uint32_t,
std::uint32_t> getNativePixelMapSize(::OH_PixelmapNative *pixelMap)
167 auto imageInfo = getNativePixelMapImageInfo(pixelMap);
170 QArkUi::callArkUiOrFailOnErrorResult(
171 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetWidth),
172 imageInfo.get(), &width);
174 std::uint32_t height;
175 QArkUi::callArkUiOrFailOnErrorResult(
176 Q_OHOS_NAMED_FUNC(::OH_PixelmapImageInfo_GetHeight),
177 imageInfo.get(), &height);
179 return {width, height};
182std::tuple<
std::uint32_t,
std::uint32_t> getNativePixelMapsIntersectionSize(
183 const std::vector<std::shared_ptr<::OH_PixelmapNative>> &pixelMaps)
185 if (pixelMaps.empty())
188 auto intersectionSize =
std::make_tuple(
189 std::numeric_limits<
std::uint32_t>::max(),
190 std::numeric_limits<
std::uint32_t>::max());
191 for (
const auto &pixelMap : pixelMaps) {
192 auto pixelMapSize = getNativePixelMapSize(pixelMap.get());
193 intersectionSize = std::make_tuple(
194 std::min(std::get<0>(intersectionSize), std::get<0>(pixelMapSize)),
195 std::min(std::get<1>(intersectionSize), std::get<1>(pixelMapSize)));
198 return intersectionSize;
201bool dragHotspotFitsInPixelMaps(
202 const std::vector<std::shared_ptr<::OH_PixelmapNative>> &pixelMaps,
203 const QPointF &hotspot)
205 if (hotspot.x() < 0 || hotspot.y() < 0)
208 auto bounds = getNativePixelMapsIntersectionSize(pixelMaps);
209 return hotspot.x() + 1 <=
std::get<0>(bounds) && hotspot.y() + 1 <=
std::get<1>(bounds);
212float mapValueFromRangeInToRangeOut(
float value,
float inMin,
float inMax,
float outMin,
float outMax)
214 return outMin + (value - inMin) * (outMax - outMin) / (inMax - inMin);
223 qOhosPrintfDebug(
"%s: %s", Q_FUNC_INFO, visible ?
"visible" :
"hidden");
224 m_stackNode->setAttributeOrFail(
227 ? ::ARKUI_VISIBILITY_VISIBLE
228 : ::ARKUI_VISIBILITY_HIDDEN);
233 qOhosPrintfDebug(
"%s: %f,%f", Q_FUNC_INFO, size.width(), size.height());
234 m_stackNode->setAttributeOrFail(
235 ::NODE_WIDTH_PERCENT,
236 static_cast<
float>(size.width()));
238 m_stackNode->setAttributeOrFail(
239 ::NODE_HEIGHT_PERCENT,
240 static_cast<
float>(size.height()));
245 qOhosPrintfDebug(
"%s: %f,%f", Q_FUNC_INFO, size.width(), size.height());
246 m_stackNode->setAttributeOrFail(
248 static_cast<
float>(size.width()));
249 m_stackNode->setAttributeOrFail(
251 static_cast<
float>(size.height()));
256 qOhosPrintfDebug(
"%s: %f,%f", Q_FUNC_INFO, position.x(), position.y());
257 m_stackNode->setAttributeOrFail(::NODE_POSITION, toFloatArray(position));
261 std::unique_ptr<Node> stack,
262 std::unique_ptr<Node> contentNode,
263 std::unique_ptr<QtOhos::WindowIdStruct> windowId)
274 if (m_parentDescriptor == parentDescriptor)
279 switch (parentDescriptor
.type()) {
284 "%s: EmbeddedWindowNode parent: %p",
288 ewParent->m_stackNode->addChildOrFail(*m_stackNode);
293 if (xComponentNode) {
295 "%s: XComponentNode parent: %p",
297 xComponentNode->handle());
298 attachNativeRootNodeOrFail(
300 m_stackNode->handle());
305 m_parentDescriptor = parentDescriptor;
310 if (!m_parentDescriptor.has_value())
313 qOhosPrintfDebug(
"%s", Q_FUNC_INFO);
315 auto parentDescriptor = m_parentDescriptor.value();
316 switch (parentDescriptor.type()) {
319 auto xComponentNode = parentDescriptor.xComponentNodeOrNull();
321 detachNativeRootNodeOrFail(*xComponentNode, m_stackNode->handle());
326 auto ewParent = parentDescriptor.embeddedWindowNodeOrNull();
328 ewParent->m_stackNode->removeChildOrFail(*m_stackNode);
338 if (m_gesturesHandler)
339 m_gesturesHandler(nativeGestureInfo);
344 return m_windowIdStruct.get();
366 return m_xComponentNode.value().lock();
371 return m_embeddedWindowNode.value().lock();
376 return m_type == other.m_type && [&]() {
378 case Type::EmbeddedWindowNode:
379 return (m_embeddedWindowNode.has_value() && other.m_embeddedWindowNode.has_value())
380 && m_embeddedWindowNode.value().lock() == other.m_embeddedWindowNode.value().lock();
381 case Type::XComponentNode:
382 return (m_xComponentNode.has_value() && other.m_xComponentNode.has_value())
383 && m_xComponentNode.value().lock() == other.m_xComponentNode.value().lock();
390 if (!m_stackNode->hasParent()) {
391 qOhosPrintfDebug(
"%s: stack node has no parent, ignore raising it", Q_FUNC_INFO);
395 m_stackNode->moveTo(m_stackNode->siblingsCount());
400 if (!m_stackNode->hasParent()) {
401 qOhosPrintfDebug(
"%s: stack node has no parent, ignore lowering it", Q_FUNC_INFO);
405 m_stackNode->moveTo(0);
410 m_contentNode->setAttributeOrFail(::NODE_FOCUS_STATUS, focused);
415 m_contentNode->setAttributeOrFail(::NODE_FOCUSABLE, focusable);
420 m_contentNode->setAttributeOrFail(::NODE_BACKGROUND_COLOR, color.rgba());
425 std::pair<
int,
int> qtBrightnessRange(-100, 100);
426 std::pair<
float,
float> ohosBrightnessRange(0, 2);
428 m_contentNode->setAttributeOrFail(
430 mapValueFromRangeInToRangeOut(
431 brightness, qtBrightnessRange.first, qtBrightnessRange.second,
432 ohosBrightnessRange.first, ohosBrightnessRange.second));
437 const int qtDefaultContrast = 0;
438 std::pair<
int,
int> qtContrastRange(-100, 100);
440 const int ohosDefaultContrast = 1;
441 constexpr auto safeReductionOfTheUpperLimit = 0.99f;
442 std::pair<
float,
float> ohosContrastRange(0, 10 * safeReductionOfTheUpperLimit);
444 const float ohosContrastValue = contrast <= 0
445 ? mapValueFromRangeInToRangeOut(
446 contrast, qtContrastRange.first, qtDefaultContrast, ohosContrastRange.first,
448 : mapValueFromRangeInToRangeOut(
449 contrast, qtDefaultContrast, qtContrastRange.second, ohosDefaultContrast,
450 ohosContrastRange.second);
451 m_contentNode->setAttributeOrFail(::NODE_CONTRAST, ohosContrastValue);
456 const int qtDefaultSaturation = 0;
457 std::pair<
int,
int> qtSaturationRange(-100, 100);
459 const int ohosDefaultSaturation = 1;
460 std::pair<
float,
float> ohosSaturationRange(0, 50);
462 const float ohosSaturationValue = saturation <= 0
463 ? mapValueFromRangeInToRangeOut(
464 saturation, qtSaturationRange.first, qtDefaultSaturation, ohosSaturationRange.first,
465 ohosDefaultSaturation)
466 : mapValueFromRangeInToRangeOut(
467 saturation, qtDefaultSaturation, qtSaturationRange.second, ohosDefaultSaturation,
468 ohosSaturationRange.second);
469 m_contentNode->setAttributeOrFail(::NODE_SATURATION, ohosSaturationValue);
473 QOhosConsumer<
const NativeGestureInfo &> gesturesHandler)
475 m_gesturesHandler = gesturesHandler;
479 QOhosConsumer<::ArkUI_NodeEvent *> dragEventsHandler)
481 static const ::ArkUI_NodeEventType dragEventTypes[] = {
482 ::NODE_ON_DRAG_ENTER,
484 ::NODE_ON_DRAG_LEAVE,
488 auto sharedDragEventsHandler = QtOhos::moveToSharedPtr(std::move(dragEventsHandler));
490 for (
auto dragEventType : dragEventTypes) {
491 contentNode().setEventHandler(
493 [sharedDragEventsHandler](::ArkUI_NodeEvent *nodeEvent) {
494 auto *dragEvent = QArkUi::callArkUi(
495 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeEvent_GetDragEvent), nodeEvent);
496 if (dragEvent ==
nullptr) {
497 qOhosPrintfError(
"Got illegal drag event as ArkUI_NodeEvent, ignoring");
500 (*sharedDragEventsHandler)(nodeEvent);
506 QOhosConsumer<::ArkUI_UIInputEvent *> keyEventsHandler)
508 setContentNodeEventHandler(::NODE_ON_KEY_EVENT,
"key", std::move(keyEventsHandler));
513 setContentNodeEventHandler(
514 ::NODE_ON_HOVER_EVENT,
516 [hoverEventsHandler = std::move(hoverEventsHandler)](::ArkUI_UIInputEvent *rawHoverEvent) {
517 hoverEventsHandler(NativeNodeHoverEvent::makeFromUiInputEvent(rawHoverEvent));
523 setContentNodeEventHandler(::NODE_ON_AXIS,
"axis", std::move(axisEventsHandler));
528 setContentNodeEventHandler(
531 [mouseEventsHandler = std::move(mouseEventsHandler)](::ArkUI_UIInputEvent *rawMouseEvent) {
532 mouseEventsHandler(NativeNodeMouseEvent::makeFromUiInputEvent(rawMouseEvent));
537 QOhosConsumer<::ArkUI_UIInputEvent *> coastingAxisEventsHandler)
539 setContentNodeEventHandler(
540 ::NODE_ON_COASTING_AXIS_EVENT,
"coasting axis", std::move(coastingAxisEventsHandler));
544 std::vector<std::shared_ptr<::OH_PixelmapNative>> pixelMaps,
const QPointF &hotspot,
545 QOhosUdmfData udmfData, std::function<
void(::ArkUI_DragAndDropInfo *)> statusListener)
547 bool hotspotFitsInPixelMaps = dragHotspotFitsInPixelMaps(pixelMaps, hotspot);
550 dragAction->setPointerId(0);
551 if (hotspotFitsInPixelMaps && !hotspot.isNull()) {
552 dragAction->setTouchPoint(
int(hotspot.x()),
int(hotspot.y()));
553 }
else if (!hotspot.isNull()) {
555 "%s: ignoring out-of-bounds hotspot: %fx%f",
556 Q_FUNC_INFO, hotspot.x(), hotspot.y());
558 dragAction->setPixelMaps(
std::move(pixelMaps));
559 dragAction->setData(
std::move(udmfData));
560 dragAction->setStatusListener(
std::move(statusListener));
562 auto previewOption = makeDragPreviewOption();
563 QArkUi::callArkUiOrFailOnErrorResult(
564 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragPreviewOption_SetNumberBadgeEnabled),
565 previewOption.get(),
false);
566 dragAction->setDragPreviewOption(*previewOption);
568 QArkUi::callArkUiOrFailOnErrorResult(
569 Q_OHOS_NAMED_FUNC(::OH_ArkUI_StartDrag),
570 dragAction->nativePtr());
579 return *m_contentNode;
584 return *m_contentNode;
599 m_stackNode->setAttributeOrFail(::NODE_HIT_TEST_BEHAVIOR, hitTestMode);
603 ::ArkUI_NodeEventType eventType,
const char *eventTypeName,
604 QOhosConsumer<::ArkUI_UIInputEvent *> inputEventsHandler)
608 [inputEventsHandler = std::move(inputEventsHandler), eventTypeName](::ArkUI_NodeEvent *nodeEvent) {
609 auto *inputEvent =
QArkUi::callArkUi(
610 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeEvent_GetInputEvent), nodeEvent);
611 if (inputEvent ==
nullptr) {
612 qOhosPrintfError(
"Got null %s event as ArkUI_NodeEvent, ignoring", eventTypeName);
615 inputEventsHandler(inputEvent);
ParentDescriptor(std::shared_ptr< QXComponentNode > node)
std::shared_ptr< QXComponentNode > xComponentNodeOrNull() const
ParentDescriptor(QEmbeddedWindowNode &node)
std::shared_ptr< QEmbeddedWindowNode > embeddedWindowNodeOrNull() const
bool operator==(const ParentDescriptor &) const
void setHitTestMode(::ArkUI_HitTestMode hitTestMode)
void setNodeVisibility(bool visible)
void setHoverEventsHandler(QOhosConsumer< NativeNodeHoverEvent > hoverEventsHandler)
void setGesturesHandler(QOhosConsumer< const NativeGestureInfo & > gesturesHandler)
virtual ~QEmbeddedWindowNode()
void setSizeParentFillPercentageNormalized(const QSizeF &size)
void setAxisEventsHandler(QOhosConsumer<::ArkUI_UIInputEvent * > axisEventsHandler)
const Node & stackNode() const
void setParentOrReparent(ParentDescriptor parent)
void setKeyEventsHandler(QOhosConsumer<::ArkUI_UIInputEvent * > keyEventsHandler)
void setBrightness(int brightness)
QEmbeddedWindowNode(std::unique_ptr< Node > stack, std::unique_ptr< Node > contentNode, std::unique_ptr< QtOhos::WindowIdStruct > windowId)
void setContrast(int contrast)
std::shared_ptr< void > startDrag(std::vector< std::shared_ptr<::OH_PixelmapNative > > pixelMaps, const QPointF &hotspot, QOhosUdmfData udmfData, std::function< void(::ArkUI_DragAndDropInfo *)> statusListener)
void setFocusable(bool focusable)
static const std::int32_t minimumNodeZIndexValue
void setSize(const QSizeF &size)
void setBackgroundColor(const QColor &color)
void handleGestureEvent(const NativeGestureInfo &nativeGestureInfo) const
void setDragEventsHandler(QOhosConsumer<::ArkUI_NodeEvent * > dragEventsHandler)
const Node & contentNode() const
bool detachFromParentIfPresent()
void setPosition(const QPointF &position)
void setSaturation(int saturation)
void setFocused(bool focused)
void setCoastingAxisEventsHandler(QOhosConsumer<::ArkUI_UIInputEvent * > coastingAxisEventsHandler)
void setMouseEventsHandler(QOhosConsumer< NativeNodeMouseEvent > mouseEventsHandler)
Combined button and popup list for selecting options.
QXComponent< QXComponentType::Node > QXComponentNode