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.hasValue())
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.hasValue() && other.m_embeddedWindowNode.hasValue())
380 && m_embeddedWindowNode.value().lock() == other.m_embeddedWindowNode.value().lock();
381 case Type::XComponentNode:
382 return (m_xComponentNode.hasValue() && other.m_xComponentNode.hasValue())
383 && m_xComponentNode.value().lock() == other.m_xComponentNode.value().lock();
390 return m_stackNode->getAttributeOrFail<std::int32_t>(::NODE_Z_INDEX);
395 m_stackNode->setAttributeOrFail(::NODE_Z_INDEX, index);
400 m_contentNode->setAttributeOrFail(::NODE_FOCUS_STATUS, focused);
405 m_contentNode->setAttributeOrFail(::NODE_FOCUSABLE, focusable);
410 m_contentNode->setAttributeOrFail(::NODE_BACKGROUND_COLOR, color.rgba());
415 std::pair<
int,
int> qtBrightnessRange(-100, 100);
416 std::pair<
float,
float> ohosBrightnessRange(0, 2);
418 m_contentNode->setAttributeOrFail(
420 mapValueFromRangeInToRangeOut(
421 brightness, qtBrightnessRange.first, qtBrightnessRange.second,
422 ohosBrightnessRange.first, ohosBrightnessRange.second));
427 const int qtDefaultContrast = 0;
428 std::pair<
int,
int> qtContrastRange(-100, 100);
430 const int ohosDefaultContrast = 1;
431 constexpr auto safeReductionOfTheUpperLimit = 0.99f;
432 std::pair<
float,
float> ohosContrastRange(0, 10 * safeReductionOfTheUpperLimit);
434 const float ohosContrastValue = contrast <= 0
435 ? mapValueFromRangeInToRangeOut(
436 contrast, qtContrastRange.first, qtDefaultContrast, ohosContrastRange.first,
438 : mapValueFromRangeInToRangeOut(
439 contrast, qtDefaultContrast, qtContrastRange.second, ohosDefaultContrast,
440 ohosContrastRange.second);
441 m_contentNode->setAttributeOrFail(::NODE_CONTRAST, ohosContrastValue);
446 const int qtDefaultSaturation = 0;
447 std::pair<
int,
int> qtSaturationRange(-100, 100);
449 const int ohosDefaultSaturation = 1;
450 std::pair<
float,
float> ohosSaturationRange(0, 50);
452 const float ohosSaturationValue = saturation <= 0
453 ? mapValueFromRangeInToRangeOut(
454 saturation, qtSaturationRange.first, qtDefaultSaturation, ohosSaturationRange.first,
455 ohosDefaultSaturation)
456 : mapValueFromRangeInToRangeOut(
457 saturation, qtDefaultSaturation, qtSaturationRange.second, ohosDefaultSaturation,
458 ohosSaturationRange.second);
459 m_contentNode->setAttributeOrFail(::NODE_SATURATION, ohosSaturationValue);
463 QOhosConsumer<
const NativeGestureInfo &> gesturesHandler)
465 m_gesturesHandler = gesturesHandler;
469 QOhosConsumer<::ArkUI_NodeEventType, ::ArkUI_DragEvent *> dragEventsHandler)
471 static const ::ArkUI_NodeEventType dragEventTypes[] = {
472 ::NODE_ON_DRAG_ENTER,
474 ::NODE_ON_DRAG_LEAVE,
478 auto sharedDragEventsHandler = QtOhos::moveToSharedPtr(std::move(dragEventsHandler));
480 for (
auto dragEventType : dragEventTypes) {
481 contentNode().setEventHandler(
483 [dragEventType, sharedDragEventsHandler](::ArkUI_NodeEvent *nodeEvent) {
484 auto *dragEvent = QArkUi::callArkUi(
485 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeEvent_GetDragEvent), nodeEvent);
486 if (dragEvent ==
nullptr) {
487 qOhosPrintfError(
"Got illegal drag event as ArkUI_NodeEvent, ignoring");
490 (*sharedDragEventsHandler)(dragEventType, dragEvent);
496 QOhosConsumer<::ArkUI_UIInputEvent *> keyEventsHandler)
498 setContentNodeEventHandler(::NODE_ON_KEY_EVENT,
"key", std::move(keyEventsHandler));
503 setContentNodeEventHandler(::NODE_ON_HOVER_EVENT,
"hover", std::move(hoverEventsHandler));
508 setContentNodeEventHandler(::NODE_ON_AXIS,
"axis", std::move(axisEventsHandler));
513 setContentNodeEventHandler(::NODE_ON_MOUSE,
"mouse", std::move(mouseEventsHandler));
517 std::vector<std::shared_ptr<::OH_PixelmapNative>> pixelMaps,
const QPointF &hotspot,
518 QOhosUdmfData udmfData, std::function<
void(::ArkUI_DragAndDropInfo *)> statusListener)
520 bool hotspotFitsInPixelMaps = dragHotspotFitsInPixelMaps(pixelMaps, hotspot);
523 dragAction->setPointerId(0);
524 if (hotspotFitsInPixelMaps && !hotspot.isNull()) {
525 dragAction->setTouchPoint(
int(hotspot.x()),
int(hotspot.y()));
526 }
else if (!hotspot.isNull()) {
528 "%s: ignoring out-of-bounds hotspot: %fx%f",
529 Q_FUNC_INFO, hotspot.x(), hotspot.y());
531 dragAction->setPixelMaps(
std::move(pixelMaps));
532 dragAction->setData(
std::move(udmfData));
533 dragAction->setStatusListener(
std::move(statusListener));
535 auto previewOption = makeDragPreviewOption();
536 QArkUi::callArkUiOrFailOnErrorResult(
537 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragPreviewOption_SetNumberBadgeEnabled),
538 previewOption.get(),
false);
539 dragAction->setDragPreviewOption(*previewOption);
541 QArkUi::callArkUiOrFailOnErrorResult(
542 Q_OHOS_NAMED_FUNC(::OH_ArkUI_StartDrag),
543 dragAction->nativePtr());
552 return *m_contentNode;
557 return *m_contentNode;
572 m_stackNode->setAttributeOrFail(::NODE_HIT_TEST_BEHAVIOR, hitTestMode);
576 ::ArkUI_NodeEventType eventType,
const char *eventTypeName,
577 QOhosConsumer<::ArkUI_UIInputEvent *> inputEventsHandler)
581 [inputEventsHandler = std::move(inputEventsHandler), eventTypeName](::ArkUI_NodeEvent *nodeEvent) {
582 auto *inputEvent =
QArkUi::callArkUi(
583 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeEvent_GetInputEvent), nodeEvent);
584 if (inputEvent ==
nullptr) {
585 qOhosPrintfError(
"Got null %s event as ArkUI_NodeEvent, ignoring", eventTypeName);
588 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 setDragEventsHandler(QOhosConsumer<::ArkUI_NodeEventType, ::ArkUI_DragEvent * > dragEventsHandler)
void setMouseEventsHandler(QOhosConsumer<::ArkUI_UIInputEvent * > mouseEventsHandler)
void setGesturesHandler(QOhosConsumer< const NativeGestureInfo & > gesturesHandler)
virtual ~QEmbeddedWindowNode()
void setSizeParentFillPercentageNormalized(const QSizeF &size)
void setZIndex(std::int32_t index)
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)
std::int32_t zIndex() const
void setBackgroundColor(const QColor &color)
void handleGestureEvent(const NativeGestureInfo &nativeGestureInfo) const
const Node & contentNode() const
bool detachFromParentIfPresent()
void setPosition(const QPointF &position)
void setSaturation(int saturation)
void setFocused(bool focused)
void setHoverEventsHandler(QOhosConsumer<::ArkUI_UIInputEvent * > hoverEventsHandler)
Combined button and popup list for selecting options.
QXComponent< QXComponentType::Node > QXComponentNode