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