1 /**
2 * File name: RkWidget.cpp
3 * Project: Redkite (A small GUI toolkit)
4 *
5 * Copyright (C) 2019 Iurie Nistor <http://geontime.com>
6 *
7 * This file is part of Redkite.
8 *
9 * Redkite is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "RkLog.h"
25 #include "RkWidget.h"
26 #include "RkEvent.h"
27 #include "RkWidgetImpl.h"
28 #include "RkPlatform.h"
29 #include "RkMain.h"
30
RkWidget(RkMain * mainApp,Rk::WindowFlags flags)31 RkWidget::RkWidget(RkMain *mainApp, Rk::WindowFlags flags)
32 : RkObject(nullptr, std::make_unique<RkWidgetImpl>(this, nullptr, flags, true))
33 , impl_ptr{static_cast<RkWidgetImpl*>(o_ptr.get())}
34 {
35 RK_LOG_DEBUG("called: " << this);
36 mainApp->setTopLevelWidget(this);
37 }
38
RkWidget(RkMain * mainApp,const RkNativeWindowInfo & parent,Rk::WindowFlags flags)39 RkWidget::RkWidget(RkMain *mainApp, const RkNativeWindowInfo &parent, Rk::WindowFlags flags)
40 : RkObject(nullptr, std::make_unique<RkWidgetImpl>(this, parent, flags, true))
41 , impl_ptr{static_cast<RkWidgetImpl*>(o_ptr.get())}
42 {
43 RK_LOG_DEBUG("called: " << this);
44 mainApp->setTopLevelWidget(this);
45 }
46
RkWidget(RkWidget * parent,Rk::WindowFlags flags)47 RkWidget::RkWidget(RkWidget *parent, Rk::WindowFlags flags)
48 : RkObject(parent, std::make_unique<RkWidgetImpl>(this, parent, flags))
49 , impl_ptr{static_cast<RkWidgetImpl*>(o_ptr.get())}
50 {
51 RK_LOG_DEBUG("called: " << this);
52 if (modality() == Rk::Modality::ModalTopWidget) {
53 auto topWidget = getTopWidget();
54 if (topWidget)
55 topWidget->disableInput();
56 else if (parentWidget() && modality() == Rk::Modality::ModalParent)
57 parentWidget()->disableInput();
58 }
59 }
60
RkWidget(RkWidget * parent,std::unique_ptr<RkWidgetImpl> impl)61 RkWidget::RkWidget(RkWidget *parent, std::unique_ptr<RkWidgetImpl> impl)
62 : RkObject(parent, std::move(impl))
63 , impl_ptr{static_cast<RkWidgetImpl*>(o_ptr.get())}
64 {
65 if (modality() == Rk::Modality::ModalTopWidget) {
66 auto topWidget = getTopWidget();
67 if (topWidget)
68 topWidget->disableInput();
69 else if (parentWidget() && modality() == Rk::Modality::ModalParent)
70 parentWidget()->disableInput();
71 }
72 }
73
~RkWidget()74 RkWidget::~RkWidget()
75 {
76 RK_LOG_DEBUG("called: " << this);
77 if (parentWidget()) {
78 if (modality() == Rk::Modality::ModalTopWidget) {
79 if (!parentWidget()->isModal()) {
80 auto topWidget = getTopWidget();
81 if (topWidget)
82 topWidget->enableInput();
83 } else {
84 // Enable inputs only for parent widget and its
85 // childs since it is modal.
86 parentWidget()->enableInput();
87 }
88 } else if (modality() == Rk::Modality::ModalParent) {
89 parentWidget()->enableInput();
90 }
91 }
92 }
93
windowFlags() const94 Rk::WindowFlags RkWidget::windowFlags() const
95 {
96 return impl_ptr->windowFlags();
97 }
98
setTitle(const std::string & title)99 void RkWidget::setTitle(const std::string &title)
100 {
101 impl_ptr->setTitle(title);
102 }
103
title() const104 const std::string& RkWidget::title() const
105 {
106 return impl_ptr->title();
107 }
108
109
show(bool b)110 void RkWidget::show(bool b)
111 {
112 impl_ptr->show(b);
113 }
114
isShown() const115 bool RkWidget::isShown() const
116 {
117 return impl_ptr->isShown();
118 }
119
hide()120 void RkWidget::hide()
121 {
122 impl_ptr->show(false);
123 }
124
nativeWindowInfo() const125 const RkNativeWindowInfo* RkWidget::nativeWindowInfo() const
126 {
127 return impl_ptr->nativeWindowInfo();
128 }
129
id() const130 RkWindowId RkWidget::id() const
131 {
132 return impl_ptr->id();
133 }
134
parentWidget() const135 RkWidget* RkWidget::parentWidget() const
136 {
137 return dynamic_cast<RkWidget*>(parent());
138 }
139
isClose() const140 bool RkWidget::isClose() const
141 {
142 return impl_ptr->isClose();
143 }
144
setSize(int w,int h)145 void RkWidget::setSize(int w, int h)
146 {
147 if (w > maximumWidth())
148 w = maximumWidth();
149 else if (w < minimumWidth())
150 w = minimumWidth();
151
152 if (h > maximumHeight())
153 h = maximumHeight();
154 else if (h < minimumHeight())
155 h = minimumHeight();
156
157 impl_ptr->setSize(RkSize(w, h));
158 }
159
setSize(const RkSize & size)160 void RkWidget::setSize(const RkSize &size)
161 {
162 impl_ptr->setSize(size);
163 }
164
size() const165 RkSize RkWidget::size() const
166 {
167 return impl_ptr->size();
168 }
169
setWidth(int w)170 void RkWidget::setWidth(int w)
171 {
172 if (w > maximumWidth())
173 impl_ptr->setSize(RkSize(maximumWidth(), impl_ptr->size().height()));
174 else if (w < minimumWidth())
175 impl_ptr->setSize(RkSize(minimumWidth(), impl_ptr->size().height()));
176 else
177 impl_ptr->setSize(RkSize(w, impl_ptr->size().height()));
178 }
179
width() const180 int RkWidget::width() const
181 {
182 return impl_ptr->size().width();
183 }
184
minimumWidth() const185 int RkWidget::minimumWidth() const
186 {
187 return impl_ptr->minimumWidth();
188 }
189
maximumWidth() const190 int RkWidget::maximumWidth() const
191 {
192 return impl_ptr->maximumWidth();
193 }
194
setHeight(int h)195 void RkWidget::setHeight(int h)
196 {
197 if (h > maximumHeight())
198 impl_ptr->setSize(RkSize(impl_ptr->size().width(), maximumHeight()));
199 else if (h < minimumHeight())
200 impl_ptr->setSize(RkSize(impl_ptr->size().width(), minimumHeight()));
201 else
202 impl_ptr->setSize(RkSize(impl_ptr->size().width(), h));
203 }
204
height() const205 int RkWidget::height() const
206 {
207 return impl_ptr->size().height();
208 }
209
minimumHeight() const210 int RkWidget::minimumHeight() const
211 {
212 return impl_ptr->minimumHeight();
213 }
214
maximumHeight() const215 int RkWidget::maximumHeight() const
216 {
217 return impl_ptr->maximumHeight();
218 }
219
setMinimumWidth(int width)220 void RkWidget::setMinimumWidth(int width)
221 {
222 impl_ptr->setMinimumWidth(width);
223 }
224
setMinimumHeight(int height)225 void RkWidget::setMinimumHeight(int height)
226 {
227 impl_ptr->setMinimumHeight(height);
228 }
229
setMaximumWidth(int width)230 void RkWidget::setMaximumWidth(int width)
231 {
232 impl_ptr->setMaximumWidth(width);
233 }
234
setMaximumHeight(int height)235 void RkWidget::setMaximumHeight(int height)
236 {
237 impl_ptr->setMaximumHeight(height);
238 }
239
setFixedWidth(int width)240 void RkWidget::setFixedWidth(int width)
241 {
242 setMinimumWidth(width);
243 setMaximumWidth(width);
244 setWidth(width);
245 }
246
setFixedHeight(int height)247 void RkWidget::setFixedHeight(int height)
248 {
249 setMinimumHeight(height);
250 setMaximumHeight(height);
251 setHeight(height);
252 }
253
setFixedSize(const RkSize & size)254 void RkWidget::setFixedSize(const RkSize &size)
255 {
256 setMinimumWidth(size.width());
257 setMaximumWidth(size.width());
258 setMinimumHeight(size.height());
259 setMaximumHeight(size.height());
260 setSize(size);
261 }
262
setFixedSize(int width,int height)263 void RkWidget::setFixedSize(int width, int height)
264 {
265 setFixedSize(RkSize(width, height));
266 }
267
x() const268 int RkWidget::x() const
269 {
270 return impl_ptr->position().x();
271 }
272
setX(int x)273 void RkWidget::setX(int x)
274 {
275 impl_ptr->setPosition(RkPoint(x, impl_ptr->position().y()));
276 }
277
y() const278 int RkWidget::y() const
279 {
280 return impl_ptr->position().y();
281 }
282
setY(int y)283 void RkWidget::setY(int y)
284 {
285 return impl_ptr->setPosition(RkPoint(impl_ptr->position().x(), y));
286 }
287
setPosition(int x,int y)288 void RkWidget::setPosition(int x, int y)
289 {
290 impl_ptr->setPosition(RkPoint(x, y));
291 }
292
setPosition(const RkPoint & p)293 void RkWidget::setPosition(const RkPoint &p)
294 {
295 impl_ptr->setPosition(p);
296 }
297
position() const298 RkPoint RkWidget::position() const
299 {
300 return impl_ptr->position();
301 }
302
setBorderWidth(int width)303 void RkWidget::setBorderWidth(int width)
304 {
305 impl_ptr->setBorderWidth(width);
306 }
307
borderWidth() const308 int RkWidget::borderWidth() const
309 {
310 return impl_ptr->borderWidth();
311 }
312
setBorderColor(int red,int green,int blue)313 void RkWidget::setBorderColor(int red, int green, int blue)
314 {
315 if (red > 255)
316 red = 255;
317 if (red < 0)
318 red = 0;
319
320 if (green > 255)
321 green = 255;
322 if (green < 0)
323 green = 0;
324
325 if (blue > 255)
326 blue = 255;
327 if (blue < 0)
328 blue = 0;
329 impl_ptr->setBorderColor(RkColor(red, green, blue));
330 }
331
borderColor() const332 const RkColor& RkWidget::borderColor() const
333 {
334 return impl_ptr->borderColor();
335 }
336
setBackgroundColor(int red,int green,int blue)337 void RkWidget::setBackgroundColor(int red, int green, int blue)
338 {
339 if (red > 255)
340 red = 255;
341 if (red < 0)
342 red = 0;
343
344 if (green > 255)
345 green = 255;
346 if (green < 0)
347 green = 0;
348
349 if (blue > 255)
350 blue = 255;
351 if (blue < 0)
352 blue = 0;
353
354 impl_ptr->setBackgroundColor(RkColor(red, green, blue));
355 }
356
setBackgroundColor(const RkColor & color)357 void RkWidget::setBackgroundColor(const RkColor &color)
358 {
359 impl_ptr->setBackgroundColor(color);
360 }
361
background() const362 const RkColor& RkWidget::background() const
363 {
364 return impl_ptr->background();
365 }
366
setTextColor(const RkColor & color)367 void RkWidget::setTextColor(const RkColor &color)
368 {
369 return impl_ptr->setTextColor(color);
370 }
371
textColor() const372 const RkColor& RkWidget::textColor() const
373 {
374 return impl_ptr->textColor();
375 }
376
color() const377 const RkColor& RkWidget::color() const
378 {
379 return impl_ptr->color();
380 }
381
setColor(const RkColor & color)382 void RkWidget::setColor(const RkColor &color)
383 {
384 return impl_ptr->setColor(color);
385 }
386
font() const387 const RkFont& RkWidget::font() const
388 {
389 return impl_ptr->font();
390 }
391
setFont(const RkFont & font)392 void RkWidget::setFont(const RkFont &font)
393 {
394 impl_ptr->setFont(font);
395 }
396
enableInput()397 void RkWidget::enableInput()
398 {
399 setWidgetAttribute(static_cast<Rk::WidgetAttribute>(static_cast<int>(Rk::WidgetAttribute::KeyInputEnabled)
400 | static_cast<int>(Rk::WidgetAttribute::MouseInputEnabled)
401 | static_cast<int>(Rk::WidgetAttribute::CloseInputEnabled)));
402 for (const auto &ch: children()) {
403 auto widget = dynamic_cast<RkWidget*>(ch);
404 if (widget)
405 widget->enableInput();
406 }
407 }
408
disableInput()409 void RkWidget::disableInput()
410 {
411 if (modality() == Rk::Modality::ModalParent || modality() == Rk::Modality::ModalTopWidget)
412 return;
413
414 clearWidgetAttribute(static_cast<Rk::WidgetAttribute>(static_cast<int>(Rk::WidgetAttribute::KeyInputEnabled)
415 | static_cast<int>(Rk::WidgetAttribute::MouseInputEnabled)
416 | static_cast<int>(Rk::WidgetAttribute::CloseInputEnabled)));
417 for (const auto &ch: children()) {
418 auto widget = dynamic_cast<RkWidget*>(ch);
419 if (widget)
420 widget->disableInput();
421 }
422 }
423
isInputEnabled() const424 bool RkWidget::isInputEnabled() const
425 {
426 return static_cast<int>(widgetAttributes()) & static_cast<int>(Rk::WidgetAttribute::KeyInputEnabled);
427 }
428
enableGrabKey(bool b)429 void RkWidget::enableGrabKey(bool b)
430 {
431 // For now only for top level window.
432 if (!parentWidget())
433 impl_ptr->enableGrabKey(b);
434 }
435
grabKeyEnabled() const436 bool RkWidget::grabKeyEnabled() const
437 {
438 return impl_ptr->grabKeyEnabled();
439 }
440
propagateGrabKey(bool b)441 void RkWidget::propagateGrabKey(bool b)
442 {
443 impl_ptr->propagateGrabKey(b);
444 }
445
propagateGrabKeyEnabled() const446 bool RkWidget::propagateGrabKeyEnabled() const
447 {
448 return impl_ptr->propagateGrabKeyEnabled();
449 }
450
event(RkEvent * event)451 void RkWidget::event(RkEvent *event)
452 {
453 impl_ptr->event(event);
454 RkObject::event(event);
455 }
456
closeEvent(RkCloseEvent * event)457 void RkWidget::closeEvent([[maybe_unused]] RkCloseEvent *event)
458 {
459 if (parentWidget()) {
460 auto event = std::make_unique<RkDeleteChild>(parentWidget(), this);
461 eventQueue()->postEvent(parentWidget(), std::move(event));
462 }
463 }
464
keyPressEvent(RkKeyEvent * event)465 void RkWidget::keyPressEvent(RkKeyEvent *event)
466 {
467 RK_UNUSED(event);
468 }
469
keyReleaseEvent(RkKeyEvent * event)470 void RkWidget::keyReleaseEvent(RkKeyEvent *event)
471 {
472 RK_UNUSED(event);
473 }
474
shortcutEvent(RkKeyEvent * event)475 void RkWidget::shortcutEvent(RkKeyEvent *event)
476 {
477 RK_UNUSED(event);
478 }
479
mouseMoveEvent(RkMouseEvent * event)480 void RkWidget::mouseMoveEvent(RkMouseEvent *event)
481 {
482 RK_UNUSED(event);
483 }
484
mouseButtonPressEvent(RkMouseEvent * event)485 void RkWidget::mouseButtonPressEvent(RkMouseEvent *event)
486 {
487 RK_UNUSED(event);
488 }
489
mouseButtonReleaseEvent(RkMouseEvent * event)490 void RkWidget::mouseButtonReleaseEvent(RkMouseEvent *event)
491 {
492 RK_UNUSED(event);
493 }
494
mouseDoubleClickEvent(RkMouseEvent * event)495 void RkWidget::mouseDoubleClickEvent(RkMouseEvent *event)
496 {
497 mouseButtonPressEvent(event);
498 }
499
wheelEvent(RkWheelEvent * event)500 void RkWidget::wheelEvent(RkWheelEvent *event)
501 {
502 RK_UNUSED(event);
503 }
504
dropEvent(RkDropEvent * event)505 void RkWidget::dropEvent(RkDropEvent *event)
506 {
507 if (parentWidget())
508 getTopWidget()->dropEvent(event);
509 }
510
moveEvent(RkMoveEvent * event)511 void RkWidget::moveEvent(RkMoveEvent *event)
512 {
513 RK_UNUSED(event);
514 }
515
resizeEvent(RkResizeEvent * event)516 void RkWidget::resizeEvent(RkResizeEvent *event)
517 {
518 RK_UNUSED(event);
519 }
520
paintEvent(RkPaintEvent * event)521 void RkWidget::paintEvent(RkPaintEvent *event)
522 {
523 RK_UNUSED(event);
524 }
525
showEvent(RkShowEvent * event)526 void RkWidget::showEvent(RkShowEvent *event)
527 {
528 RK_UNUSED(event);
529 }
530
hideEvent(RkHideEvent * event)531 void RkWidget::hideEvent(RkHideEvent *event)
532 {
533 RK_UNUSED(event);
534 }
535
focusEvent(RkFocusEvent * event)536 void RkWidget::focusEvent([[maybe_unused]] RkFocusEvent *event)
537 {
538 update();
539 }
540
hoverEvent(RkHoverEvent * event)541 void RkWidget::hoverEvent(RkHoverEvent *event)
542 {
543 RK_UNUSED(event);
544 }
545
update()546 void RkWidget::update()
547 {
548 impl_ptr->update();
549 }
550
getCanvasInfo() const551 const RkCanvasInfo* RkWidget::getCanvasInfo() const
552 {
553 return impl_ptr->getCanvasInfo();
554 }
555
rect() const556 RkRect RkWidget::rect() const
557 {
558 return impl_ptr->rect();
559 }
560
close()561 void RkWidget::close()
562 {
563 eventQueue()->postEvent(this, std::make_unique<RkCloseEvent>());
564 }
565
isModal() const566 bool RkWidget::isModal() const
567 {
568 return modality() != Rk::Modality::NonModal;
569 }
570
modality() const571 Rk::Modality RkWidget::modality() const
572 {
573 return impl_ptr->modality();
574 }
575
setWidgetAttribute(Rk::WidgetAttribute attribute)576 void RkWidget::setWidgetAttribute(Rk::WidgetAttribute attribute)
577 {
578 impl_ptr->setWidgetAttribute(attribute);
579 }
580
clearWidgetAttribute(Rk::WidgetAttribute attribute)581 void RkWidget::clearWidgetAttribute(Rk::WidgetAttribute attribute)
582 {
583 impl_ptr->clearWidgetAttribute(attribute);
584 }
585
widgetAttributes() const586 Rk::WidgetAttribute RkWidget::widgetAttributes() const
587 {
588 return impl_ptr->getWidgetAttributes();
589 }
590
getTopWidget()591 RkWidget* RkWidget::getTopWidget()
592 {
593 if (!parentWidget())
594 return this;
595 return parentWidget()->getTopWidget();
596 }
597
isTopWindow() const598 bool RkWidget::isTopWindow() const
599 {
600 return !parentWidget();
601 }
602
setFocus(bool b)603 void RkWidget::setFocus(bool b)
604 {
605 impl_ptr->setFocus(b);
606 }
607
hasFocus() const608 bool RkWidget::hasFocus() const
609 {
610 return impl_ptr->hasFocus();
611 }
612
setPointerShape(Rk::PointerShape shape)613 void RkWidget::setPointerShape(Rk::PointerShape shape)
614 {
615 impl_ptr->setPointerShape(shape);
616 }
617
pointerShape() const618 Rk::PointerShape RkWidget::pointerShape() const
619 {
620 return impl_ptr->pointerShape();
621 }
622
setScaleFactor(double factor)623 void RkWidget::setScaleFactor(double factor)
624 {
625 impl_ptr->setScaleFactor(factor);
626 for (const auto &ch: children()) {
627 auto widget = dynamic_cast<RkWidget*>(ch);
628 if (widget)
629 widget->setScaleFactor(factor);
630 }
631
632 if (this == getTopWidget())
633 eventQueue()->setScaleFactor(factor);
634 update();
635 }
636
scaleFactor() const637 double RkWidget::scaleFactor() const
638 {
639 return impl_ptr->scaleFactor();
640 }
641
642
pointerIsOverWindow() const643 bool RkWidget::pointerIsOverWindow() const
644 {
645 return impl_ptr->pointerIsOverWindow();
646 }
647