23 #include "freertos/FreeRTOS.h" 24 #include "freertos/timers.h" 35 #include "images/bitmaps.h" 120 uiObject::~uiObject()
134 uiEvtHandler::uiEvtHandler(uiApp * app)
137 objectType().uiEvtHandler =
true;
141 uiEvtHandler::~uiEvtHandler()
146 void uiEvtHandler::processEvent(uiEvent * event)
167 : uiEvtHandler(nullptr),
168 m_rootWindow(nullptr),
169 m_activeWindow(nullptr),
170 m_focusedWindow(nullptr),
171 m_capturedMouseWindow(nullptr),
172 m_freeMouseWindow(nullptr),
173 m_modalWindow(nullptr),
174 m_combineMouseMoveEvents(false),
175 m_caretWindow(nullptr),
176 m_caretTimer(nullptr),
177 m_caretInvertState(-1),
178 m_lastMouseUpTimeMS(0),
181 objectType().uiApp =
true;
193 m_displayController = displayController;
195 m_canvas =
new Canvas(m_displayController);
197 m_keyboard = keyboard;
201 if (m_keyboard ==
nullptr)
203 if (m_mouse ==
nullptr)
207 m_eventsQueue = xQueueCreate(FABGLIB_UI_EVENTS_QUEUE_SIZE,
sizeof(uiEvent));
219 m_rootWindow->setApp(
this);
220 m_rootWindow->setCanvas(m_canvas);
237 m_activeWindow = m_rootWindow;
240 uiEvent evt = uiEvent(
this, UIEVT_APPINIT);
248 if (getEvent(&event, -1)) {
253 preprocessEvent(&event);
256 event.dest->processEvent(&event);
258 if (event.id == UIEVT_QUIT) {
259 exitCode =
event.params.exitCode;
275 m_rootWindow =
nullptr;
283 vQueueDelete(m_eventsQueue);
284 m_eventsQueue =
nullptr;
292 void uiApp::asyncRunTask(
void * arg)
302 m_displayController = displayController;
303 m_keyboard = keyboard;
306 if (CoreUsage::busiestCore() == -1)
307 xTaskCreate(&asyncRunTask,
"", taskStack,
this, 5,
nullptr);
309 xTaskCreatePinnedToCore(&asyncRunTask,
"", taskStack,
this, 5,
nullptr, CoreUsage::quietCore());
316 while (getEvent(&event, 0)) {
318 preprocessEvent(&event);
321 event.dest->processEvent(&event);
328 for (
auto child = m_rootWindow->
lastChild(); child; child = child->
prev())
330 uiEvent evt = uiEvent(
nullptr, UIEVT_QUIT);
331 evt.params.exitCode = exitCode;
336 void uiApp::preprocessEvent(uiEvent * event)
338 if (event->dest ==
nullptr) {
341 case UIEVT_MOUSEMOVE:
342 case UIEVT_MOUSEWHEEL:
343 case UIEVT_MOUSEBUTTONDOWN:
344 case UIEVT_MOUSEBUTTONUP:
345 preprocessMouseEvent(event);
349 preprocessKeyboardEvent(event);
358 if (event->params.timerHandle == m_caretTimer) {
360 event->dest =
nullptr;
370 if (m_modalWindow !=
nullptr)
371 filterModalEvent(event);
376 void uiApp::filterModalEvent(uiEvent * event)
378 if (event->dest !=
nullptr && event->dest->objectType().uiWindow &&
event->dest != m_modalWindow && !m_modalWindow->isChild((uiWindow*)event->dest)) {
380 case UIEVT_MOUSEMOVE:
381 case UIEVT_MOUSEWHEEL:
382 case UIEVT_MOUSEBUTTONDOWN:
383 case UIEVT_MOUSEBUTTONUP:
384 case UIEVT_MOUSEENTER:
387 event->dest =
nullptr;
388 if (event->id == UIEVT_MOUSEENTER) {
403 void uiApp::preprocessMouseEvent(uiEvent * event)
406 if (m_combineMouseMoveEvents && event->id == UIEVT_MOUSEMOVE) {
408 while (peekEvent(&nextEvent, 0) && nextEvent.id == UIEVT_MOUSEMOVE)
412 Point mousePos = Point(event->params.mouse.status.X, event->params.mouse.status.Y);
416 uiWindow * oldFreeMouseWindow = m_freeMouseWindow;
417 Point winMousePos = mousePos;
418 if (m_capturedMouseWindow) {
420 for (uiWindow * cur = m_capturedMouseWindow; cur != m_rootWindow; cur = cur->
parent())
421 winMousePos = winMousePos.sub(cur->pos());
422 event->dest = m_capturedMouseWindow;
424 if (event->id == UIEVT_MOUSEBUTTONUP && event->params.mouse.changedButton == 1) {
428 uiEvent evt = uiEvent(m_capturedMouseWindow, UIEVT_MOUSELEAVE);
430 m_freeMouseWindow = oldFreeMouseWindow =
nullptr;
435 event->dest = m_freeMouseWindow;
437 event->params.mouse.status.X = winMousePos.X;
438 event->params.mouse.status.Y = winMousePos.Y;
441 if (oldFreeMouseWindow != m_freeMouseWindow) {
442 if (m_freeMouseWindow) {
443 uiEvent evt = uiEvent(m_freeMouseWindow, UIEVT_MOUSEENTER);
446 if (oldFreeMouseWindow) {
447 uiEvent evt = uiEvent(oldFreeMouseWindow, UIEVT_MOUSELEAVE);
453 if (event->id == UIEVT_MOUSEBUTTONUP && event->params.mouse.changedButton == 1) {
454 int curTime = esp_timer_get_time() / 1000;
455 if (m_lastMouseUpPos == mousePos && curTime - m_lastMouseUpTimeMS <= m_appProps.
doubleClickTime) {
457 uiEvent evt = *event;
458 evt.id = UIEVT_DBLCLICK;
461 m_lastMouseUpTimeMS = curTime;
462 m_lastMouseUpPos = mousePos;
467 void uiApp::preprocessKeyboardEvent(uiEvent * event)
470 if (m_focusedWindow) {
471 event->dest = m_focusedWindow;
474 if (m_focusedWindow != m_activeWindow) {
475 uiEvent evt = *event;
476 evt.dest = m_activeWindow;
483 void uiApp::captureMouse(uiWindow * window)
485 m_capturedMouseWindow = window;
486 if (m_capturedMouseWindow)
500 for (; child; child = child->
prev()) {
503 point = point.sub(child->
pos());
507 if (child ==
nullptr)
521 return xQueueSendToBack(m_eventsQueue, event, 0) == pdTRUE;
527 return xQueueSendToFront(m_eventsQueue, event, 0) == pdTRUE;
531 void uiApp::postDebugMsg(
char const * msg)
533 uiEvent evt = uiEvent(
nullptr, UIEVT_DEBUGMSG);
534 evt.params.debugMsg = msg;
539 bool uiApp::getEvent(uiEvent * event,
int timeOutMS)
541 return xQueueReceive(m_eventsQueue, event, msToTicks(timeOutMS)) == pdTRUE;
545 bool uiApp::peekEvent(uiEvent * event,
int timeOutMS)
547 return xQueuePeek(m_eventsQueue, event, msToTicks(timeOutMS)) == pdTRUE;
551 void uiApp::processEvent(uiEvent * event)
553 uiEvtHandler::processEvent(event);
562 onTimer(event->params.timerHandle);
577 if (value != m_activeWindow) {
579 while (value && !value->m_windowProps.activable) {
580 value = value->m_parent;
584 if (value == m_activeWindow)
593 m_activeWindow = value;
597 uiEvent evt = uiEvent(prev, UIEVT_DEACTIVATE);
601 if (m_activeWindow) {
603 uiEvent evt = uiEvent(m_activeWindow, UIEVT_ACTIVATE);
619 if (value && !value->isFocusable())
622 if (m_focusedWindow != value) {
625 uiEvent evt = uiEvent(prev, UIEVT_KILLFOCUS);
626 evt.params.focusInfo.oldFocused = prev;
627 evt.params.focusInfo.newFocused = value;
631 evt = uiEvent(prev->
parent(), UIEVT_CHILDKILLFOCUS);
632 evt.params.focusInfo.oldFocused = prev;
633 evt.params.focusInfo.newFocused = value;
638 m_focusedWindow = value;
643 if (m_focusedWindow) {
644 uiEvent evt = uiEvent(m_focusedWindow, UIEVT_SETFOCUS);
645 evt.params.focusInfo.oldFocused = prev;
646 evt.params.focusInfo.newFocused = m_focusedWindow;
648 if (m_focusedWindow->
parent()) {
650 evt = uiEvent(m_focusedWindow->
parent(), UIEVT_CHILDSETFOCUS);
651 evt.params.focusInfo.oldFocused = prev;
652 evt.params.focusInfo.newFocused = m_focusedWindow;
668 int startingIndex = m_focusedWindow ? m_focusedWindow->
focusIndex() + delta : 0;
669 int newIndex = startingIndex;
672 uiWindow * newFocusedCtrl = parent->findChildWithFocusIndex(newIndex, &maxIndex);
674 return m_focusedWindow;
675 if (newFocusedCtrl) {
677 return newFocusedCtrl;
680 newIndex = (newIndex >= maxIndex ? 0 : newIndex + delta);
682 newIndex = (newIndex <= 0 ? maxIndex : newIndex + delta);
683 }
while (newIndex != startingIndex);
684 return m_focusedWindow;
696 uiEvent evt = uiEvent(m_rootWindow, UIEVT_GENPAINTEVENTS);
697 evt.params.rect = rect;
724 uiEvent evt = uiEvent(window, UIEVT_RESHAPEWINDOW);
725 evt.params.rect = rect;
732 window->m_state.
visible = value;
733 uiEvent evt = uiEvent(window, value ? UIEVT_SHOW : UIEVT_HIDE);
742 auto state =
new ModalWindowState;
743 state->window = window;
744 state->modalResult = -1;
747 state->prevModal = m_modalWindow;
760 while (getEvent(&event, timeout)) {
762 if (m_modalWindow != state->window && event.dest == state->window) {
764 m_modalWindow = state->window;
766 if (event.id == UIEVT_EXITMODAL) {
768 state->modalResult =
event.params.modalResult;
770 }
else if (event.id == UIEVT_CLOSE) {
775 preprocessEvent(&event);
778 event.dest->processEvent(&event);
788 m_modalWindow = state->prevModal;
792 int result = state->modalResult;
809 uiEvent evt = uiEvent(window, value ? UIEVT_MAXIMIZE : UIEVT_RESTORE);
816 uiEvent evt = uiEvent(window, value ? UIEVT_MINIMIZE : UIEVT_RESTORE);
821 void uiApp::timerFunc(TimerHandle_t xTimer)
824 uiEvent evt = uiEvent(dest, UIEVT_TIMER);
825 evt.params.timerHandle = xTimer;
833 TimerHandle_t h = xTimerCreate(
"", pdMS_TO_TICKS(periodMS), pdTRUE, dest, &uiApp::timerFunc);
841 xTimerDelete(handle, portMAX_DELAY);
847 void uiApp::showCaret(
uiWindow * window)
849 if (m_caretWindow != window) {
850 if (window && window == m_focusedWindow) {
852 m_caretWindow = window;
854 m_caretInvertState = 0;
856 }
else if (m_caretTimer) {
860 m_caretTimer =
nullptr;
861 m_caretWindow = NULL;
867 void uiApp::suspendCaret(
bool value)
871 if (m_caretInvertState != -1) {
872 xTimerStop(m_caretTimer, 0);
874 m_caretInvertState = -1;
877 if (m_caretInvertState == -1) {
878 xTimerStart(m_caretTimer, 0);
879 m_caretInvertState = 0;
888 void uiApp::setCaret(
bool value)
894 void uiApp::setCaret(Point
const & pos)
896 setCaret(m_caretRect.move(pos));
900 void uiApp::setCaret(Rect
const & rect)
908 void uiApp::blinkCaret(
bool forceOFF)
910 if (m_caretWindow && m_caretInvertState != -1 && (forceOFF ==
false || m_caretInvertState == 1)) {
914 Rect aRect = m_caretWindow->
transformRect(m_caretRect, m_rootWindow);
916 m_caretInvertState = m_caretInvertState ? 0 : 1;
926 for (
auto child = window->
lastChild(); child; child = child->
prev())
929 if (m_caretWindow == window)
931 if (m_focusedWindow == window)
933 if (m_activeWindow == window)
938 uiEvent evt = uiEvent(window, UIEVT_DESTROY);
944 void uiApp::cleanWindowReferences(
uiWindow * window)
946 if (m_capturedMouseWindow == window)
947 m_capturedMouseWindow =
nullptr;
948 if (m_freeMouseWindow == window)
949 m_freeMouseWindow =
nullptr;
950 if (m_activeWindow == window)
951 m_activeWindow =
nullptr;
952 if (m_focusedWindow == window)
953 m_focusedWindow =
nullptr;
954 if (m_modalWindow == window)
955 m_modalWindow =
nullptr;
956 if (m_caretWindow == window)
957 m_caretWindow =
nullptr;
963 auto font = &FONT_std_14;
964 const int titleHeight = title && strlen(title) ? font->height : 0;
965 const int textExtent = m_canvas->
textExtent(font, text);
966 const int button1Extent = button1Text ? m_canvas->
textExtent(font, button1Text) + 10 : 0;
967 const int button2Extent = button2Text ? m_canvas->
textExtent(font, button2Text) + 10 : 0;
968 const int button3Extent = button3Text ? m_canvas->
textExtent(font, button3Text) + 10 : 0;
969 const int buttonsWidth = imax(imax(imax(button1Extent, button2Extent), button3Extent), 40);
977 const int buttonsHeight = font->height + 6;
982 const int bitmapWidth = bitmap ? bitmap->width : 0;
983 const int bitmapHeight = bitmap ? bitmap->height : 0;
984 constexpr
int buttonsSpace = 10;
985 const int bitmapSpace = bitmap ? 8 : 0;
986 const int textHeight = imax(font->height, bitmapHeight);
987 const int requiredWidth = imin(imax(bitmapWidth + bitmapSpace + textExtent + 10, buttonsWidth * totButtons + (2 + buttonsSpace) * totButtons), m_canvas->
getWidth());
988 const int requiredHeight = textHeight + buttonsHeight + titleHeight + font->height * 3;
989 const int frameX = (m_canvas->
getWidth() - requiredWidth) / 2;
990 const int frameY = (m_canvas->
getHeight() - requiredHeight) / 2;
992 auto mainFrame =
new uiFrame(m_rootWindow, title,
Point(frameX, frameY),
Size(requiredWidth, requiredHeight),
false);
993 mainFrame->frameProps().resizeable =
false;
994 mainFrame->frameProps().hasMaximizeButton =
false;
995 mainFrame->frameProps().hasMinimizeButton =
false;
997 int x = (requiredWidth - bitmapWidth - bitmapSpace - textExtent) / 2;
999 int y = font->height + titleHeight + (textHeight - bitmapHeight) / 2;
1001 x += bitmapWidth + bitmapSpace;
1004 int y = font->height + titleHeight + (textHeight - font->height) / 2;
1009 y += textHeight + titleHeight;
1010 auto panel =
new uiPanel(mainFrame,
Point(0, y),
Size(mainFrame->size().width, mainFrame->size().height - y));
1011 panel->windowStyle().borderColor =
RGB888(128, 128, 128);
1012 panel->panelStyle().backgroundColor = mainFrame->frameStyle().backgroundColor;
1016 y = (panel->size().height - buttonsHeight) / 2;
1017 x = mainFrame->windowStyle().borderSize + requiredWidth - buttonsWidth * totButtons - buttonsSpace * totButtons;
1019 auto button1 = button1Text ?
new uiButton(panel, button1Text,
Point(x, y),
Size(buttonsWidth, buttonsHeight)) :
nullptr;
1021 button1->onClick = [&]() { mainFrame->exitModal(1); };
1022 x += buttonsWidth + buttonsSpace;
1025 auto button2 = button2Text ?
new uiButton(panel, button2Text,
Point(x, y),
Size(buttonsWidth, buttonsHeight)) :
nullptr;
1027 button2->onClick = [&]() { mainFrame->exitModal(2); };
1028 x += buttonsWidth + buttonsSpace;
1031 auto button3 = button3Text ?
new uiButton(panel, button3Text,
Point(x, y),
Size(buttonsWidth, buttonsHeight)) :
nullptr;
1033 button3->onClick = [&]() { mainFrame->exitModal(3); };
1034 x += buttonsWidth + buttonsSpace;
1038 mainFrame->onShow = [&]() {
1047 switch (modalResult) {
1062 auto font = &FONT_std_14;
1063 const int titleHeight = title && strlen(title) ? font->height : 0;
1064 const int textExtent = m_canvas->
textExtent(font, text);
1065 const int editExtent = imin(maxLength * m_canvas->
textExtent(font,
"M"), m_rootWindow->
clientSize().
width / 2 - textExtent);
1066 const int button1Extent = button1Text ? m_canvas->
textExtent(font, button1Text) + 10 : 0;
1067 const int button2Extent = button2Text ? m_canvas->
textExtent(font, button2Text) + 10 : 0;
1068 const int buttonsWidth = imax(imax(button1Extent, button2Extent), 40);
1074 const int buttonsHeight = font->height + 6;
1075 const int textHeight = font->height;
1076 constexpr
int buttonsSpace = 10;
1077 const int requiredWidth = imin(imax(editExtent + textExtent + 10, buttonsWidth * totButtons + (2 + buttonsSpace) * totButtons), m_canvas->
getWidth());
1078 const int requiredHeight = textHeight + buttonsHeight + titleHeight + font->height * 3;
1079 const int frameX = (m_canvas->
getWidth() - requiredWidth) / 2;
1080 const int frameY = (m_canvas->
getHeight() - requiredHeight) / 2;
1082 auto mainFrame =
new uiFrame(m_rootWindow, title,
Point(frameX, frameY),
Size(requiredWidth, requiredHeight),
false);
1083 mainFrame->frameProps().resizeable =
false;
1084 mainFrame->frameProps().hasMaximizeButton =
false;
1085 mainFrame->frameProps().hasMinimizeButton =
false;
1088 mainFrame->exitModal(1);
1090 mainFrame->exitModal(0);
1094 int y = font->height + titleHeight + (textHeight - font->height) / 2;
1097 auto edit =
new uiTextEdit(mainFrame, inOutString,
Point(x + textExtent + 5, y - 4),
Size(editExtent - 15, textHeight + 6));
1101 y += textHeight + titleHeight;
1102 auto panel =
new uiPanel(mainFrame,
Point(0, y),
Size(mainFrame->size().width, mainFrame->size().height - y));
1103 panel->windowStyle().borderColor =
RGB888(128, 128, 128);
1104 panel->panelStyle().backgroundColor = mainFrame->frameStyle().backgroundColor;
1108 y = (panel->size().height - buttonsHeight) / 2;
1109 x = mainFrame->windowStyle().borderSize + requiredWidth - buttonsWidth * totButtons - buttonsSpace * totButtons;
1111 auto button1 = button1Text ?
new uiButton(panel, button1Text,
Point(x, y),
Size(buttonsWidth, buttonsHeight)) :
nullptr;
1113 button1->onClick = [&]() { mainFrame->exitModal(1); };
1114 x += buttonsWidth + buttonsSpace;
1117 auto button2 = button2Text ?
new uiButton(panel, button2Text,
Point(x, y),
Size(buttonsWidth, buttonsHeight)) :
nullptr;
1119 button2->onClick = [&]() { mainFrame->exitModal(2); };
1120 x += buttonsWidth + buttonsSpace;
1124 mainFrame->onShow = [&]() {
1133 switch (modalResult) {
1136 int len = imin(maxLength, strlen(edit->text()));
1137 memcpy(inOutString, edit->text(), len);
1138 inOutString[len] = 0;
1183 m_mouseDownPos(
Point(-1, -1)),
1184 m_isMouseOver(false),
1187 m_firstChild(nullptr),
1188 m_lastChild(nullptr),
1189 m_styleClassID(styleClassID),
1190 m_parentProcessKbdEvents(false)
1200 m_canvas =
app()->canvas();
1205 if (m_pos == UIWINDOW_PARENTCENTER) {
1209 m_pos =
Point(0, 0);
1216 if (visible &&
app())
1220 m_focusIndex = pframe ? ((
uiFrame*)pframe)->getNextFreeFocusIndex() : 0;
1223 uiEvent evt = uiEvent(
this, UIEVT_CREATE);
1229 uiWindow::~uiWindow()
1235 void uiWindow::freeChildren()
1241 m_firstChild = m_lastChild =
nullptr;
1245 void uiWindow::addChild(uiWindow * child)
1249 m_lastChild->m_next = child;
1250 child->m_prev = m_lastChild;
1251 m_lastChild = child;
1254 m_firstChild = m_lastChild = child;
1261 void uiWindow::insertAfter(uiWindow * child, uiWindow * underlyingChild)
1268 child->m_prev = underlyingChild;
1269 if (underlyingChild) {
1271 child->m_next = underlyingChild->m_next;
1273 child->m_next->m_prev = child;
1274 underlyingChild->m_next = child;
1275 if (m_lastChild == underlyingChild)
1276 m_lastChild = child;
1279 m_firstChild->m_prev = child;
1280 child->m_next = m_firstChild;
1281 m_firstChild = child;
1286 void uiWindow::removeChild(uiWindow * child,
bool freeChild)
1289 if (child == m_firstChild)
1290 m_firstChild = child->m_next;
1292 child->m_prev->m_next = child->m_next;
1294 if (child == m_lastChild)
1295 m_lastChild = child->m_prev;
1297 child->m_next->m_prev = child->m_prev;
1301 app()->cleanWindowReferences(child);
1303 child->m_prev = child->m_next =
nullptr;
1310 void uiWindow::moveChildOnTop(uiWindow * child)
1312 removeChild(child,
false);
1319 void uiWindow::moveAfter(uiWindow * child, uiWindow * underlyingChild)
1321 removeChild(child,
false);
1322 insertAfter(child, underlyingChild);
1328 parent()->moveChildOnTop(
this);
1334 parent()->moveAfter(
this, insertionPoint);
1339 bool uiWindow::isChild(
uiWindow * window)
1342 if (child == window || (child->hasChildren() && child->isChild(window)))
1352 for (
uiWindow * win =
this; win != baseWindow; win = win->m_parent)
1353 r = r.translate(win->m_pos);
1390 return rect(origin).shrink(bSize);
1406 void uiWindow::beginPaint(uiEvent * paintEvent,
Rect const & clippingRect)
1410 canvas()->
setClippingRect( clippingRect.intersection(paintEvent->params.rect) );
1416 void uiWindow::processEvent(uiEvent * event)
1418 uiEvtHandler::processEvent(event);
1420 switch (event->id) {
1423 m_parent->removeChild(
this);
1431 case UIEVT_ACTIVATE:
1436 for (
uiWindow * child =
this; child->parent() !=
nullptr; child = child->parent()) {
1437 if (child != child->parent()->lastChild()) {
1438 child->parent()->moveChildOnTop(child);
1439 winToRepaint = child;
1442 winToRepaint->repaint();
1446 case UIEVT_DEACTIVATE:
1451 case UIEVT_MOUSEBUTTONDOWN:
1452 if (event->params.mouse.changedButton == 1) {
1453 m_mouseDownPos = Point(event->params.mouse.status.X, event->params.mouse.status.Y);
1454 m_posAtMouseDown = m_pos;
1455 m_sizeAtMouseDown = m_size;
1462 app()->captureMouse(
this);
1466 case UIEVT_MOUSEBUTTONUP:
1468 if (event->params.mouse.changedButton == 1) {
1469 app()->captureMouse(
nullptr);
1471 if (
rect(
uiOrigin::Window).contains(event->params.mouse.status.X, event->params.mouse.status.Y)) {
1472 uiEvent evt = *event;
1473 evt.id = UIEVT_CLICK;
1483 case UIEVT_DBLCLICK:
1495 case UIEVT_MAXIMIZE:
1503 case UIEVT_MINIMIZE:
1517 case UIEVT_RESHAPEWINDOW:
1518 reshape(event->params.rect);
1521 case UIEVT_GENPAINTEVENTS:
1522 generatePaintEvents(event->params.rect);
1525 case UIEVT_MOUSEENTER:
1526 m_isMouseOver =
true;
1530 case UIEVT_MOUSELEAVE:
1531 m_isMouseOver =
false;
1535 if (m_parentProcessKbdEvents)
1536 m_parent->processEvent(event);
1540 if (m_parentProcessKbdEvents)
1541 m_parent->processEvent(event);
1549 case UIEVT_SETFOCUS:
1550 case UIEVT_KILLFOCUS:
1560 void uiWindow::paintWindow()
1566 for (
int i = 0; i < bSize; ++i)
1573 void uiWindow::generatePaintEvents(Rect
const & paintRect)
1575 app()->setCaret(
false);
1577 rects.push(paintRect);
1578 while (!rects.isEmpty()) {
1579 Rect thisRect = rects.pop();
1580 bool noIntesections =
true;
1583 if (win->state().visible && thisRect.intersects(winRect)) {
1584 noIntesections =
false;
1585 removeRectangle(rects, thisRect, winRect);
1586 Rect newRect = thisRect.intersection(winRect).translate(-win->pos().X, -win->pos().Y);
1587 win->generatePaintEvents(newRect);
1591 if (noIntesections) {
1592 uiEvent evt = uiEvent(
nullptr, UIEVT_PAINT);
1594 evt.params.rect = thisRect;
1605 void uiWindow::reshape(Rect
const & r)
1613 if (oldRect == newRect)
1617 m_pos = Point(r.X1, r.Y1);
1620 if (!oldRect.intersects(newRect)) {
1625 removeRectangle(rects, oldRect, newRect);
1626 while (!rects.isEmpty())
1631 uiEvent evt = uiEvent(
this, UIEVT_SETPOS);
1632 evt.params.pos =
pos();
1636 evt = uiEvent(
this, UIEVT_SETSIZE);
1637 evt.params.size =
size();
1641 int dx = newRect.width() - oldRect.width();
1642 int dy = newRect.height() - oldRect.height();
1643 if (dx != 0 || dy != 0) {
1646 Rect newChildRect = childRect;
1648 if (!child->m_anchors.left && !child->m_anchors.right) {
1650 int ofs = dx > 0 ? imax(1, dx / 2) : imin(-1, dx / 2);
1651 newChildRect.X1 += ofs;
1652 newChildRect.X2 += ofs;
1653 }
else if (!child->m_anchors.left)
1654 newChildRect.X1 += dx;
1655 if (child->m_anchors.right)
1656 newChildRect.X2 += dx;
1659 if (!child->m_anchors.top && !child->m_anchors.bottom) {
1661 int ofs = dy > 0 ? imax(1, dy / 2) : imin(-1, dy / 2);
1662 newChildRect.Y1 += ofs;
1663 newChildRect.Y2 += ofs;
1664 }
else if (!child->m_anchors.top)
1665 newChildRect.Y1 += dy;
1666 if (child->m_anchors.bottom)
1667 newChildRect.Y2 += dy;
1669 if (newChildRect != childRect) {
1671 child->m_pos.X = newChildRect.X1;
1672 child->m_pos.Y = newChildRect.Y1;
1673 child->m_size.width = newChildRect.width();
1674 child->m_size.height = newChildRect.height();
1676 uiEvent evt = uiEvent(child, UIEVT_SETPOS);
1677 evt.params.pos = child->pos();
1680 evt = uiEvent(child, UIEVT_SETSIZE);
1681 evt.params.size = child->size();
1693 uiEvent evt = uiEvent(
this, UIEVT_EXITMODAL);
1694 evt.params.modalResult = modalResult;
1705 bool uiWindow::isFocusable()
1712 uiWindow * uiWindow::findChildWithFocusIndex(
int focusIndex,
int * maxIndex)
1714 for (
auto child = m_firstChild; child; child = child->m_next) {
1715 if (child->isFocusable()) {
1716 *maxIndex = imax(*maxIndex, child->m_focusIndex);
1721 if (child->hasChildren()) {
1722 auto r = child->findChildWithFocusIndex(
focusIndex, maxIndex);
1735 while (ret && ret->
objectType().uiFrame == 0)
1751 :
uiWindow(parent, pos, size, visible, 0),
1754 m_mouseDownFrameItem(uiFrameItem::
None),
1755 m_mouseMoveFrameItem(uiFrameItem::
None),
1756 m_lastReshapingBox(
Rect(0, 0, 0, 0)),
1757 m_nextFreeFocusIndex(0)
1774 m_titleLength = strlen(value);
1775 m_title = (
char*) realloc(m_title, m_titleLength + 1);
1776 strcpy(m_title, value);
1783 va_start(ap, format);
1784 int size = vsnprintf(
nullptr, 0, format, ap) + 1;
1787 va_start(ap, format);
1789 vsnprintf(buf,
size, format, ap);
1796 int uiFrame::titleBarHeight()
1798 return m_frameStyle.
titleFont->height + 3;
1802 Rect uiFrame::titleBarRect()
1805 r.Y2 = r.Y1 + titleBarHeight() - 1;
1815 if (m_titleLength > 0)
1816 r.
Y1 += titleBarHeight();
1822 Size uiFrame::minWindowSize()
1825 if (m_frameProps.
resizeable && !
state().minimized && m_titleLength == 0) {
1826 r.
width += CORNERSENSE * 2;
1827 r.
height += CORNERSENSE * 2;
1831 if (m_titleLength > 0) {
1832 int barHeight = titleBarHeight();
1835 r.
width += barHeight * 3;
1836 r.
width += barHeight * 4;
1846 Rect uiFrame::getBtnRect(
int buttonIndex)
1848 int btnSize = titleBarHeight();
1849 Rect barRect = titleBarRect();
1850 Rect btnRect = Rect(barRect.X2 - btnSize - CORNERSENSE / 2, barRect.Y1,
1851 barRect.X2 - CORNERSENSE / 2, barRect.Y2);
1852 while (buttonIndex--)
1853 btnRect = btnRect.translate(-btnSize, 0);
1858 void uiFrame::paintFrame()
1862 if (m_titleLength > 0) {
1863 int barHeight = titleBarHeight();
1869 int btnX = paintButtons(bkgRect);
1875 bkgRect.Y1 += barHeight;
1878 if (m_frameProps.
fillBackground && !
state().minimized && bkgRect.width() > 0 && bkgRect.height() > 0) {
1886 int uiFrame::paintButtons(Rect
const & bkgRect)
1888 int buttonsX = bkgRect.X2;
1891 Rect r = getBtnRect(0);
1893 if (m_mouseMoveFrameItem == uiFrameItem::CloseButton) {
1900 canvas()->
drawLine(r.X1, r.Y1, r.X2, r.Y2);
1901 canvas()->
drawLine(r.X2, r.Y1, r.X1, r.Y2);
1905 Rect r = getBtnRect(1);
1907 if (m_mouseMoveFrameItem == uiFrameItem::MaximizeButton) {
1914 if (
state().maximized ||
state().minimized) {
1916 r = r.shrink(1).translate(-1, +1);
1918 r = r.translate(+2, -2);
1919 canvas()->
moveTo(r.X1, r.Y1 + 2);
1920 canvas()->
lineTo(r.X1, r.Y1);
1921 canvas()->
lineTo(r.X2, r.Y1);
1922 canvas()->
lineTo(r.X2, r.Y2);
1923 canvas()->
lineTo(r.X2 - 2, r.Y2);
1929 Rect r = getBtnRect(2);
1931 if (m_mouseMoveFrameItem == uiFrameItem::MinimizeButton) {
1938 int h = (r.Y2 - r.Y1 + 1) / 2;
1939 canvas()->
drawLine(r.X1, r.Y1 + h, r.X2, r.Y1 + h);
1945 void uiFrame::processEvent(uiEvent * event)
1947 uiWindow::processEvent(event);
1949 switch (event->id) {
1957 case UIEVT_MOUSEBUTTONDOWN:
1958 if (event->params.mouse.changedButton == 1) {
1959 m_mouseDownFrameItem = getFrameItemAt(event->params.mouse.status.X, event->params.mouse.status.Y);
1960 app()->combineMouseMoveEvents(
true);
1964 case UIEVT_MOUSEBUTTONUP:
1965 if (event->params.mouse.changedButton == 1) {
1966 int mouseX =
event->params.mouse.status.X;
1967 int mouseY =
event->params.mouse.status.Y;
1970 movingCapturedMouse(mouseX, mouseY,
false);
1973 movingFreeMouse(mouseX, mouseY);
1976 handleButtonsClick(mouseX, mouseY,
false);
1978 app()->combineMouseMoveEvents(
false);
1982 case UIEVT_MOUSEMOVE:
1983 if (
app()->capturedMouseWindow() ==
this)
1984 movingCapturedMouse(event->params.mouse.status.X, event->params.mouse.status.Y,
true);
1986 movingFreeMouse(event->params.mouse.status.X, event->params.mouse.status.Y);
1989 case UIEVT_MOUSELEAVE:
1990 if (m_mouseMoveFrameItem == uiFrameItem::CloseButton)
1992 if (m_mouseMoveFrameItem == uiFrameItem::MaximizeButton)
1994 if (m_mouseMoveFrameItem == uiFrameItem::MinimizeButton)
1999 case UIEVT_DBLCLICK:
2000 handleButtonsClick(event->params.mouse.status.X, event->params.mouse.status.Y,
true);
2016 onTimer(event->params.timerHandle);
2021 if (event->params.key.VK ==
VK_TAB) {
2022 if (event->params.key.SHIFT)
2040 uiFrameItem uiFrame::getFrameItemAt(
int x,
int y)
2042 Point p = Point(x, y);
2044 if (m_titleLength > 0) {
2046 return uiFrameItem::CloseButton;
2049 return uiFrameItem::MaximizeButton;
2052 return uiFrameItem::MinimizeButton;
2061 if (Rect(CORNERSENSE, 0, w - CORNERSENSE,
windowStyle().borderSize).contains(p))
2062 return uiFrameItem::TopCenterResize;
2065 if (Rect(0, CORNERSENSE,
windowStyle().borderSize, h - CORNERSENSE).contains(p))
2066 return uiFrameItem::CenterLeftResize;
2069 if (Rect(w -
windowStyle().borderSize, CORNERSENSE, w - 1, h - CORNERSENSE).contains(p))
2070 return uiFrameItem::CenterRightResize;
2073 if (Rect(CORNERSENSE, h -
windowStyle().borderSize, w - CORNERSENSE, h - 1).contains(p))
2074 return uiFrameItem::BottomCenterResize;
2077 if (Rect(0, 0, CORNERSENSE, CORNERSENSE).contains(p))
2078 return uiFrameItem::TopLeftResize;
2081 if (Rect(w - CORNERSENSE, 0, w - 1, CORNERSENSE).contains(p))
2082 return uiFrameItem::TopRightResize;
2085 if (Rect(0, h - CORNERSENSE, CORNERSENSE, h - 1).contains(p))
2086 return uiFrameItem::BottomLeftResize;
2089 if (Rect(w - CORNERSENSE, h - CORNERSENSE, w - 1, h - 1).contains(p))
2090 return uiFrameItem::BottomRightResize;
2095 if (m_titleLength > 0 && m_frameProps.
moveable && !
state().maximized && titleBarRect().contains(p))
2096 return uiFrameItem::MoveArea;
2102 void uiFrame::movingCapturedMouse(
int mouseX,
int mouseY,
bool mouseIsDown)
2107 Size minSize = minWindowSize();
2111 switch (m_mouseDownFrameItem) {
2113 case uiFrameItem::MoveArea:
2114 newRect = newRect.move(
pos().
X + dx,
pos().
Y + dy);
2117 case uiFrameItem::CenterRightResize:
2118 newRect = newRect.resize(imax(sizeAtMouseDown().
width + dx, minSize.width), newRect.height());
2121 case uiFrameItem::CenterLeftResize:
2124 r.X1 =
pos().
X + dx;
2125 newRect.X1 = r.X1 - imax(0, minSize.width - r.size().width);
2129 case uiFrameItem::TopLeftResize:
2132 r.X1 =
pos().
X + dx;
2133 newRect.X1 = r.X1 - imax(0, minSize.width - r.size().width);
2134 r.Y1 =
pos().
Y + dy;
2135 newRect.Y1 = r.Y1 - imax(0, minSize.height - r.size().height);
2139 case uiFrameItem::TopCenterResize:
2142 r.Y1 =
pos().
Y + dy;
2143 newRect.Y1 = r.Y1 - imax(0, minSize.height - r.size().height);
2147 case uiFrameItem::TopRightResize:
2150 r.X2 =
pos().
X + sizeAtMouseDown().
width + dx;
2151 newRect.X2 = r.X2 + imax(0, minSize.width - r.size().width);
2152 r.Y1 =
pos().
Y + dy;
2153 newRect.Y1 = r.Y1 - imax(0, minSize.height - r.size().height);
2157 case uiFrameItem::BottomLeftResize:
2160 r.X1 =
pos().
X + dx;
2161 newRect.X1 = r.X1 - imax(0, minSize.width - r.size().width);
2162 r.Y2 =
pos().
Y + sizeAtMouseDown().
height + dy;
2163 newRect.Y2 = r.Y2 + imax(0, minSize.height - r.size().height);
2167 case uiFrameItem::BottomCenterResize:
2168 newRect = newRect.resize(newRect.width(), imax(sizeAtMouseDown().
height + dy, minSize.height));
2171 case uiFrameItem::BottomRightResize:
2172 newRect = newRect.resize(imax(sizeAtMouseDown().
width + dx, minSize.width), imax(sizeAtMouseDown().
height + dy, minSize.height));
2180 if (mouseIsDown ==
false ||
app()->appProps().realtimeReshaping) {
2181 m_lastReshapingBox = Rect();
2184 drawReshapingBox(newRect);
2188 void uiFrame::drawReshapingBox(Rect boxRect)
2196 if (m_lastReshapingBox != Rect()) {
2198 if (m_titleLength > 0)
2199 canvas()->
drawLine(m_lastReshapingBox.
X1, m_lastReshapingBox.
Y1 + clientOffsetY, m_lastReshapingBox.
X2, m_lastReshapingBox.
Y1 + clientOffsetY);
2201 if (boxRect != Rect()) {
2203 if (m_titleLength > 0)
2204 canvas()->
drawLine(boxRect.X1, boxRect.Y1 + clientOffsetY, boxRect.X2, boxRect.Y1 + clientOffsetY);
2207 m_lastReshapingBox = boxRect;
2211 void uiFrame::movingFreeMouse(
int mouseX,
int mouseY)
2213 uiFrameItem prevSensPos = m_mouseMoveFrameItem;
2215 m_mouseMoveFrameItem = getFrameItemAt(mouseX, mouseY);
2217 if ((m_mouseMoveFrameItem == uiFrameItem::CloseButton || prevSensPos == uiFrameItem::CloseButton) && m_mouseMoveFrameItem != prevSensPos)
2220 if ((m_mouseMoveFrameItem == uiFrameItem::MaximizeButton || prevSensPos == uiFrameItem::MaximizeButton) && m_mouseMoveFrameItem != prevSensPos)
2223 if ((m_mouseMoveFrameItem == uiFrameItem::MinimizeButton || prevSensPos == uiFrameItem::MinimizeButton) && m_mouseMoveFrameItem != prevSensPos)
2228 switch (m_mouseMoveFrameItem) {
2230 case uiFrameItem::TopLeftResize:
2234 case uiFrameItem::TopCenterResize:
2238 case uiFrameItem::TopRightResize:
2242 case uiFrameItem::CenterLeftResize:
2246 case uiFrameItem::CenterRightResize:
2250 case uiFrameItem::BottomLeftResize:
2254 case uiFrameItem::BottomCenterResize:
2258 case uiFrameItem::BottomRightResize:
2270 void uiFrame::handleButtonsClick(
int x,
int y,
bool doubleClick)
2272 if (m_titleLength > 0) {
2275 uiEvent evt = uiEvent(
this, UIEVT_CLOSE);
2278 (doubleClick && titleBarRect().contains(x, y)))) {
2303 :
uiWindow(parent, pos, size, visible, 0)
2313 uiControl::~uiControl()
2318 void uiControl::processEvent(uiEvent * event)
2320 uiWindow::processEvent(event);
2335 :
uiControl(parent, pos, size, visible, 0),
2357 uiButton::~uiButton()
2365 int len = strlen(value);
2366 m_text = (
char*) realloc(m_text, len + 1);
2367 strcpy(m_text, value);
2373 void uiButton::paintButton()
2378 if (
app()->capturedMouseWindow() ==
this)
2385 paintContent(bkgRect);
2389 void uiButton::paintContent(Rect
const & rect)
2391 Bitmap
const * bitmap = m_down ? m_buttonStyle.
downBitmap : m_buttonStyle.
bitmap;
2392 int textHeight = m_buttonStyle.
textFont->height;
2393 int bitmapWidth = bitmap ? bitmap->width : 0;
2394 int bitmapHeight = bitmap ? bitmap->height : 0;
2397 int x =
rect.
X1 + (
rect.size().
width - m_textExtent - bitmapTextSpace - bitmapWidth) / 2;
2398 int y =
rect.
Y1 + (
rect.size().
height - imax(textHeight, bitmapHeight)) / 2;
2402 x += bitmapWidth + bitmapTextSpace;
2403 y += (imax(textHeight, bitmapHeight) - textHeight) / 2;
2411 void uiButton::processEvent(uiEvent * event)
2413 uiControl::processEvent(event);
2415 switch (event->id) {
2426 case UIEVT_MOUSEENTER:
2430 case UIEVT_MOUSEBUTTONDOWN:
2431 if (event->params.mouse.changedButton == 1)
2435 case UIEVT_MOUSELEAVE:
2453 void uiButton::trigger()
2465 if (value != m_down) {
2484 :
uiControl(parent, pos, size, visible, 0),
2507 uiTextEdit::~uiTextEdit()
2515 m_textLength = strlen(value);
2516 checkAllocatedSpace(m_textLength);
2517 strcpy(m_text, value);
2521 void uiTextEdit::processEvent(uiEvent * event)
2523 uiControl::processEvent(event);
2525 switch (event->id) {
2531 app()->setCaret(
true);
2534 case UIEVT_MOUSEBUTTONDOWN:
2535 if (event->params.mouse.changedButton == 1) {
2536 int col = getColFromMouseX(event->params.mouse.status.X);
2537 moveCursor(col, col);
2542 case UIEVT_MOUSEBUTTONUP:
2545 case UIEVT_MOUSEENTER:
2549 case UIEVT_MOUSELEAVE:
2553 case UIEVT_MOUSEMOVE:
2555 if (
app()->capturedMouseWindow() ==
this)
2556 moveCursor(getColFromMouseX(event->params.mouse.status.X), m_selCursorCol);
2559 case UIEVT_SETFOCUS:
2562 app()->showCaret(
this);
2567 case UIEVT_KILLFOCUS:
2569 app()->showCaret(NULL);
2575 handleKeyDown(event->params.key);
2578 case UIEVT_DBLCLICK:
2579 selectWordAt(event->params.mouse.status.X);
2588 void uiTextEdit::handleKeyDown(uiKeyEventInfo key)
2594 if (m_cursorCol != m_selCursorCol)
2596 else if (m_cursorCol > 0) {
2598 moveCursor(m_cursorCol - 1, m_cursorCol - 1);
2612 if (c >= 0x20 && c != 0x7F) {
2613 if (m_cursorCol != m_selCursorCol)
2631 int newCurCol = key.CTRL ? getWordPosAtLeft() : m_cursorCol - 1;
2632 moveCursor(newCurCol, (key.SHIFT ? m_selCursorCol : newCurCol));
2643 int newCurCol = key.CTRL ? getWordPosAtRight() : m_cursorCol + 1;
2644 moveCursor(newCurCol, (key.SHIFT ? m_selCursorCol : newCurCol));
2652 moveCursor(0, (key.SHIFT ? m_selCursorCol : 0));
2659 moveCursor(m_textLength, (key.SHIFT ? m_selCursorCol : m_textLength));
2669 moveCursor(m_textLength, 0);
2681 Rect uiTextEdit::getEditRect()
2687 void uiTextEdit::paintTextEdit()
2689 m_contentRect = getEditRect();
2701 uint8_t
const * uiTextEdit::getCharInfo(
char ch,
int *
width)
2703 uint8_t
const * chptr;
2704 if (m_textEditStyle.
textFont->chptr) {
2706 chptr = m_textEditStyle.
textFont->data + m_textEditStyle.
textFont->chptr[(int)(ch)];
2710 chptr = m_textEditStyle.
textFont->data + ch;
2717 void uiTextEdit::paintContent()
2719 m_contentRect = m_contentRect.shrink(2);
2720 canvas()->
setClippingRect(canvas()->getClippingRect().intersection(m_contentRect));
2723 GlyphOptions glyphOpt = GlyphOptions().FillBackground(
false).DoubleWidth(0).Bold(
false).Italic(
false).Underline(
false).Invert(0);
2724 if (m_selCursorCol != m_cursorCol)
2725 glyphOpt.FillBackground(
true);
2728 for (
int x = m_contentRect.
X1 + m_viewX, y = m_contentRect.
Y1, col = 0, fontWidth; m_text[col]; ++col, x += fontWidth) {
2729 uint8_t
const * chptr = getCharInfo(m_text[col], &fontWidth);
2730 if (m_selCursorCol != m_cursorCol && (col == m_selCursorCol || col == m_cursorCol)) {
2731 glyphOpt.invert = !glyphOpt.invert;
2734 if (x >= m_contentRect.
X1 && x <= m_contentRect.
X2)
2735 canvas()->
drawGlyph(x, y, fontWidth, m_textEditStyle.
textFont->height, chptr, 0);
2743 int uiTextEdit::charColumnToWindowX(
int col)
2745 int x = m_contentRect.
X1 + m_viewX;
2746 for (
int curcol = 0, fontWidth; m_text[curcol]; ++curcol, x += fontWidth) {
2747 getCharInfo(m_text[curcol], &fontWidth);
2756 void uiTextEdit::updateCaret()
2759 int x = charColumnToWindowX(m_cursorCol);
2760 app()->setCaret(Rect(x, m_contentRect.
Y1, x, m_contentRect.
Y1 + m_textEditStyle.
textFont->height));
2769 void uiTextEdit::moveCursor(
int col,
int selCol)
2771 col = iclamp(col, 0, m_textLength);
2772 selCol = iclamp(selCol, 0, m_textLength);
2774 if (col == m_cursorCol && selCol == m_selCursorCol)
2777 bool doRepaint =
false;
2780 if (m_cursorCol != m_selCursorCol && col == selCol)
2784 m_selCursorCol = selCol;
2786 if (m_cursorCol != m_selCursorCol)
2790 int x = charColumnToWindowX(m_cursorCol);
2792 int prevCharWidth = 0;
2794 getCharInfo(m_text[col - 1], &prevCharWidth);
2797 getCharInfo(m_text[col < m_textLength ? col : col - 1], &charWidth);
2799 if (x - prevCharWidth < m_contentRect.
X1) {
2801 m_viewX += m_contentRect.
X1 - (x - prevCharWidth);
2803 }
else if (x + charWidth > m_contentRect.
X2) {
2805 m_viewX -= (x + charWidth - m_contentRect.
X2);
2817 int uiTextEdit::getColFromMouseX(
int mouseX)
2820 for (
int x = m_contentRect.
X1 + m_viewX, fontWidth; m_text[col]; ++col, x += fontWidth) {
2821 getCharInfo(m_text[col], &fontWidth);
2822 if (mouseX < x || (mouseX >= x && mouseX < x + fontWidth))
2830 void uiTextEdit::checkAllocatedSpace(
int requiredLength)
2833 if (m_textSpace < requiredLength) {
2834 if (m_textSpace == 0) {
2836 m_textSpace = requiredLength;
2839 while (m_textSpace < requiredLength)
2842 m_text = (
char*) realloc(m_text, m_textSpace);
2848 void uiTextEdit::insert(
char c)
2851 checkAllocatedSpace(m_textLength);
2852 memmove(m_text + m_cursorCol + 1, m_text + m_cursorCol, m_textLength - m_cursorCol);
2853 m_text[m_cursorCol] = c;
2854 moveCursor(m_cursorCol + 1, m_cursorCol + 1);
2861 void uiTextEdit::removeSel()
2863 if (m_textLength > 0) {
2864 if (m_cursorCol > m_selCursorCol)
2865 iswap(m_cursorCol, m_selCursorCol);
2866 int count = imax(1, m_selCursorCol - m_cursorCol);
2867 if (m_cursorCol < m_textLength) {
2868 memmove(m_text + m_cursorCol, m_text + m_cursorCol + count, m_textLength - m_cursorCol - count + 1);
2869 m_textLength -= count;
2870 moveCursor(m_cursorCol, m_cursorCol);
2879 int uiTextEdit::getWordPosAtLeft()
2881 int col = m_cursorCol - 1;
2882 while (col > 0 && (!isspace(m_text[col - 1]) || isspace(m_text[col])))
2884 return imax(0, col);
2889 int uiTextEdit::getWordPosAtRight()
2891 int col = m_cursorCol + 1;
2892 while (col < m_textLength && (!isspace(m_text[col - 1]) || isspace(m_text[col])))
2894 return imin(m_textLength, col);
2900 void uiTextEdit::selectWordAt(
int mouseX)
2902 int col = getColFromMouseX(mouseX), left = col, right = col;
2903 bool lspc = isspace(m_text[col]);
2904 while (left > 0 && (
bool)isspace(m_text[left - 1]) == lspc)
2906 while (right < m_textLength && (
bool)isspace(m_text[right]) == lspc)
2908 moveCursor(left, right);
2924 :
uiControl(parent, pos, size, visible, 0),
2950 int len = strlen(value);
2951 m_text = (
char*) realloc(m_text, len + 1);
2952 strcpy(m_text, value);
2960 va_start(ap, format);
2961 int size = vsnprintf(
nullptr, 0, format, ap) + 1;
2964 va_start(ap, format);
2966 vsnprintf(buf,
size, format, ap);
2982 void uiLabel::paintLabel()
2990 int y = r.
Y1 + (r.height() - m_labelStyle.
textFont->height) / 2;
2995 void uiLabel::processEvent(uiEvent * event)
2997 uiControl::processEvent(event);
2999 switch (event->id) {
3024 :
uiControl(parent, pos, size, visible, 0),
3050 if (m_autoSize &&
bitmap)
3055 void uiImage::paintImage()
3061 int x = r.
X1 + (r.
X2 + 1 - m_bitmap->
width) / 2;
3062 int y = r.
Y1 + (r.
Y2 + 1 - m_bitmap->
height) / 2;
3068 void uiImage::processEvent(uiEvent * event)
3070 uiControl::processEvent(event);
3072 switch (event->id) {
3095 :
uiControl(parent, pos, size, visible, 0)
3113 void uiPanel::paintPanel()
3122 void uiPanel::processEvent(uiEvent * event)
3124 uiControl::processEvent(event);
3126 switch (event->id) {
3162 uiPaintBox::~uiPaintBox()
3167 void uiPaintBox::paintPaintBox()
3179 void uiPaintBox::processEvent(uiEvent * event)
3181 uiScrollableControl::processEvent(event);
3183 switch (event->id) {
3206 :
uiControl(parent, pos, size, visible, 0),
3220 uiColorBox::~uiColorBox()
3232 void uiColorBox::paintColorBox()
3241 void uiColorBox::processEvent(uiEvent * event)
3243 uiControl::processEvent(event);
3245 switch (event->id) {
3268 :
uiControl(parent, pos, size, visible, 0),
3269 m_HScrollBarPosition(0),
3270 m_HScrollBarVisible(0),
3271 m_HScrollBarRange(0),
3272 m_VScrollBarPosition(0),
3273 m_VScrollBarVisible(0),
3274 m_VScrollBarRange(0),
3275 m_mouseOverItem(uiScrollBarItem::
None),
3276 m_scrollTimer(nullptr)
3285 uiScrollableControl::~uiScrollableControl()
3297 position = iclamp(position, 0, range - visible);
3298 switch (orientation) {
3301 bool changedPos = (m_VScrollBarPosition != position);
3302 if (m_VScrollBarVisible != visible || m_VScrollBarRange != range || changedPos) {
3303 m_VScrollBarVisible = visible;
3304 m_VScrollBarRange = range;
3305 m_VScrollBarPosition = position;
3306 if (repaintScrollbar)
3307 repaintScrollBar(orientation);
3315 bool changedPos = (m_HScrollBarPosition != position);
3316 if (m_HScrollBarVisible != visible || m_HScrollBarRange != range || changedPos) {
3317 m_HScrollBarVisible = visible;
3318 m_HScrollBarRange = range;
3319 m_HScrollBarPosition = position;
3320 if (repaintScrollbar)
3321 repaintScrollBar(orientation);
3331 void uiScrollableControl::repaintScrollBar(
uiOrientation orientation)
3337 void uiScrollableControl::processEvent(uiEvent * event)
3339 uiControl::processEvent(event);
3341 switch (event->id) {
3345 paintScrollableControl();
3348 case UIEVT_MOUSEBUTTONDOWN:
3349 if (event->params.mouse.changedButton == 1) {
3350 m_mouseDownHScrollBarPosition = m_HScrollBarPosition;
3351 m_mouseDownVScrollBarPosition = m_VScrollBarPosition;
3352 if (m_mouseOverItem == uiScrollBarItem::LeftButton || m_mouseOverItem == uiScrollBarItem::RightButton ||
3353 m_mouseOverItem == uiScrollBarItem::TopButton || m_mouseOverItem == uiScrollBarItem::BottomButton) {
3356 handleButtonsScroll();
3360 app()->combineMouseMoveEvents(
true);
3364 case UIEVT_MOUSEBUTTONUP:
3365 if (event->params.mouse.changedButton == 1) {
3366 app()->combineMouseMoveEvents(
false);
3367 if (m_scrollTimer) {
3369 m_scrollTimer =
nullptr;
3374 case UIEVT_MOUSEMOVE:
3375 if (
app()->capturedMouseWindow() ==
this)
3376 handleCapturedMouseMove(event->params.mouse.status.X, event->params.mouse.status.Y);
3378 handleFreeMouseMove(event->params.mouse.status.X, event->params.mouse.status.Y);
3381 case UIEVT_MOUSEWHEEL:
3382 if (m_VScrollBarRange)
3387 if (event->params.timerHandle == m_scrollTimer)
3388 handleButtonsScroll();
3397 void uiScrollableControl::handleButtonsScroll()
3399 switch (m_mouseOverItem) {
3400 case uiScrollBarItem::LeftButton:
3403 case uiScrollBarItem::RightButton:
3406 case uiScrollBarItem::TopButton:
3409 case uiScrollBarItem::BottomButton:
3418 void uiScrollableControl::handlePageScroll()
3420 switch (m_mouseOverItem) {
3421 case uiScrollBarItem::PageLeft:
3424 case uiScrollBarItem::PageRight:
3427 case uiScrollBarItem::PageUp:
3430 case uiScrollBarItem::PageDown:
3439 void uiScrollableControl::handleFreeMouseMove(
int mouseX,
int mouseY)
3441 auto prev = m_mouseOverItem;
3442 m_mouseOverItem = getItemAt(mouseX, mouseY);
3443 if (m_mouseOverItem !=
prev) {
3444 if (m_VScrollBarRange)
3446 if (m_HScrollBarRange)
3452 void uiScrollableControl::handleCapturedMouseMove(
int mouseX,
int mouseY)
3454 if (m_mouseOverItem == uiScrollBarItem::HBar) {
3457 int newPos = m_mouseDownHScrollBarPosition + offset * m_HScrollBarRange / m_HBarArea;
3459 }
else if (m_mouseOverItem == uiScrollBarItem::VBar) {
3462 int newPos = m_mouseDownVScrollBarPosition + offset * m_VScrollBarRange / m_VBarArea;
3468 uiScrollBarItem uiScrollableControl::getItemAt(
int x,
int y)
3470 if (m_HScrollBarRange) {
3471 Rect lbtn, rbtn, bar;
3472 Rect box = getHScrollBarRects(&lbtn, &rbtn, &bar);
3473 if (lbtn.contains(x, y))
3474 return uiScrollBarItem::LeftButton;
3475 if (rbtn.contains(x, y))
3476 return uiScrollBarItem::RightButton;
3477 if (bar.contains(x, y))
3478 return uiScrollBarItem::HBar;
3479 if (box.contains(x, y))
3480 return x < bar.X1 ? uiScrollBarItem::PageLeft : uiScrollBarItem::PageRight;
3482 if (m_VScrollBarRange) {
3483 Rect tbtn, bbtn, bar;
3484 Rect box = getVScrollBarRects(&tbtn, &bbtn, &bar);
3485 if (tbtn.contains(x, y))
3486 return uiScrollBarItem::TopButton;
3487 if (bbtn.contains(x, y))
3488 return uiScrollBarItem::BottomButton;
3489 if (bar.contains(x, y))
3490 return uiScrollBarItem::VBar;
3491 if (box.contains(x, y))
3492 return y < bar.Y1 ? uiScrollBarItem::PageUp: uiScrollBarItem::PageDown;
3498 Rect uiScrollableControl::getVScrollBarRects(Rect * topButton, Rect * bottomButton, Rect * bar)
3502 Rect box = Rect(cArea.X2 + 1 - sbSize, cArea.Y1, cArea.X2, cArea.Y2 - (m_HScrollBarRange ? sbSize : 0));
3503 if (topButton && bottomButton && bar) {
3505 *topButton = Rect(box.X1 + 2, box.Y1 + 2, box.X2 - 2, box.Y1 + sbSize - 2);
3506 *bottomButton = Rect(box.X1 + 2, box.Y2 - sbSize + 2, box.X2 - 2, box.Y2 - 2);
3508 int barAreaY1 = topButton->Y2 + 2;
3509 int barAreaY2 = bottomButton->Y1 - 2;
3510 m_VBarArea = barAreaY2 - barAreaY1 + 1;
3511 int barOffsetY = m_VScrollBarPosition * m_VBarArea / m_VScrollBarRange;
3512 int barHeight = m_VScrollBarVisible * m_VBarArea / m_VScrollBarRange;
3513 *bar = Rect(box.X1 + 1, barAreaY1 + barOffsetY, box.X2 - 1, barAreaY1 + barOffsetY + barHeight);
3519 Rect uiScrollableControl::getHScrollBarRects(Rect * leftButton, Rect * rightButton, Rect * bar)
3523 Rect box = Rect(cArea.X1, cArea.Y2 + 1 - sbSize, cArea.X2 - (m_VScrollBarRange ? sbSize : 0), cArea.Y2);
3524 if (leftButton && rightButton && bar) {
3526 *leftButton = Rect(box.X1 + 2, box.Y1 + 2, box.X1 + sbSize - 2, box.Y2 - 2);
3527 *rightButton = Rect(box.X2 - sbSize + 2, box.Y1 + 2, box.X2 - 2, box.Y2 - 2);
3529 int barAreaX1 = leftButton->X2 + 2;
3530 int barAreaX2 = rightButton->X1 - 2;
3531 m_HBarArea = barAreaX2 - barAreaX1 + 1;
3532 int barOffsetX = m_HScrollBarPosition * m_HBarArea / m_HScrollBarRange;
3533 int barWidth = m_HScrollBarVisible * m_HBarArea / m_HScrollBarRange;
3534 *bar = Rect(barAreaX1 + barOffsetX, box.Y1 + 1, barAreaX1 + barOffsetX + barWidth, box.Y2 - 1);
3540 void uiScrollableControl::paintScrollableControl()
3544 if (m_HScrollBarRange) {
3546 Rect lbtn, rbtn, bar;
3547 Rect box = getHScrollBarRects(&lbtn, &rbtn, &bar);
3551 canvas()->
fillRectangle(Rect(box.X1, box.Y1, bar.X1 - 1, box.Y2));
3552 canvas()->
fillRectangle(Rect(bar.X2 + 1, box.Y1, box.X2, box.Y2));
3553 canvas()->
drawLine(bar.X1, box.Y1, bar.X2, box.Y1);
3554 canvas()->
drawLine(bar.X1, box.Y2, bar.X2, box.Y2);
3556 canvas()->
setPenColor(m_mouseOverItem == uiScrollBarItem::LeftButton ? mouseOverFColor : FColor);
3557 canvas()->
drawLine(lbtn.X2, lbtn.Y1, lbtn.X1, lbtn.Y1 + lbtn.height() / 2);
3558 canvas()->
drawLine(lbtn.X1, lbtn.Y1 + lbtn.height() / 2, lbtn.X2, lbtn.Y2);
3559 canvas()->
setPenColor(m_mouseOverItem == uiScrollBarItem::RightButton ? mouseOverFColor : FColor);
3560 canvas()->
drawLine(rbtn.X1, rbtn.Y1, rbtn.X2, rbtn.Y1 + lbtn.height() / 2);
3561 canvas()->
drawLine(rbtn.X2, rbtn.Y1 + lbtn.height() / 2, rbtn.X1, rbtn.Y2);
3563 canvas()->
setBrushColor(m_mouseOverItem == uiScrollBarItem::HBar ? mouseOverFColor : FColor);
3566 if (m_VScrollBarRange) {
3568 Rect ubtn, bbtn, bar;
3569 Rect box = getVScrollBarRects(&ubtn, &bbtn, &bar);
3573 canvas()->
fillRectangle(Rect(box.X1, box.Y1, box.X2, bar.Y1 - 1));
3574 canvas()->
fillRectangle(Rect(box.X1, bar.Y2 + 1, box.X2, box.Y2));
3575 canvas()->
drawLine(box.X1, bar.Y1, box.X1, bar.Y2);
3576 canvas()->
drawLine(box.X2, bar.Y1, box.X2, bar.Y2);
3578 if (m_HScrollBarRange)
3581 canvas()->
setPenColor(m_mouseOverItem == uiScrollBarItem::TopButton ? mouseOverFColor : FColor);
3582 canvas()->
drawLine(ubtn.X1, ubtn.Y2, ubtn.X1 + ubtn.width() / 2, ubtn.Y1);
3583 canvas()->
drawLine(ubtn.X1 + ubtn.width() / 2, ubtn.Y1, ubtn.X2, ubtn.Y2);
3584 canvas()->
setPenColor(m_mouseOverItem == uiScrollBarItem::BottomButton ? mouseOverFColor : FColor);
3585 canvas()->
drawLine(bbtn.X1, bbtn.Y1, bbtn.X1 + bbtn.width() / 2, bbtn.Y2);
3586 canvas()->
drawLine(bbtn.X1 + bbtn.width() / 2, bbtn.Y2, bbtn.X2, bbtn.Y1);
3588 canvas()->
setBrushColor(m_mouseOverItem == uiScrollBarItem::VBar ? mouseOverFColor : FColor);
3597 r.
X2 -= (m_VScrollBarRange ? m_scrollableControlStyle.
scrollBarSize : 0);
3598 r.
Y2 -= (m_HScrollBarRange ? m_scrollableControlStyle.
scrollBarSize : 0);
3615 m_firstVisibleItem(0)
3629 uiCustomListBox::~uiCustomListBox()
3634 void uiCustomListBox::processEvent(uiEvent * event)
3636 uiScrollableControl::processEvent(event);
3638 switch (event->id) {
3645 case UIEVT_MOUSEBUTTONDOWN:
3646 if (event->params.mouse.changedButton == 1)
3647 handleMouseDown(event->params.mouse.status.X, event->params.mouse.status.Y);
3651 handleKeyDown(event->params.key);
3658 case UIEVT_KILLFOCUS:
3672 void uiCustomListBox::handleKeyDown(uiKeyEventInfo key)
3674 bool shift = key.SHIFT;
3703 selectItem(items_getCount() - 1, shift, shift);
3714 if (items_getCount() > 0) {
3715 index = iclamp(index, 0, items_getCount() - 1);
3718 items_deselectAll();
3720 if (index <= first) {
3721 for (
int i = index; i <= first; ++i)
3722 items_select(i,
true);
3724 for (
int i = index; i >= first; --i)
3725 items_select(i,
true);
3728 items_select(index,
true);
3732 makeItemVisible(index);
3741 void uiCustomListBox::makeItemVisible(
int index)
3744 if (index < m_firstVisibleItem)
3745 m_firstVisibleItem = index;
3754 items_deselectAll();
3760 void uiCustomListBox::paintListBox()
3766 if (itmRect.height() * items_getCount() > cliRect.height()) {
3767 int visible = cliRect.height() / itmRect.height();
3768 int range = items_getCount();
3777 m_firstVisibleItem = 0;
3783 int index = m_firstVisibleItem;
3785 if (!itmRect.intersects(cliRect))
3790 if (index < items_getCount() && items_selected(index))
3795 if (index < items_getCount()) {
3798 items_draw(index, itmRect);
3802 itmRect = itmRect.translate(0, m_listBoxStyle.
itemHeight);
3812 for (
int i = 0; i < items_getCount(); ++i)
3813 if (items_selected(i))
3822 for (
int i = items_getCount() - 1; i >= 0; --i)
3823 if (items_selected(i))
3842 int uiCustomListBox::getItemAtMousePos(
int mouseX,
int mouseY)
3845 if (cliRect.contains(mouseX, mouseY)) {
3846 int idx = m_firstVisibleItem + (mouseY - cliRect.
Y1) / m_listBoxStyle.
itemHeight;
3847 return idx < items_getCount() ? idx : -1;
3853 void uiCustomListBox::handleMouseDown(
int mouseX,
int mouseY)
3855 int idx = getItemAtMousePos(mouseX, mouseY);
3859 items_select(idx, !items_selected(idx));
3862 items_deselectAll();
3863 items_select(idx,
true);
3865 }
else if (idx == -1)
3866 items_deselectAll();
3893 void uiListBox::items_draw(
int index,
const Rect & itemRect)
3895 int x = itemRect.
X1 + 1;
3912 m_selectedColor((
Color)0)
3923 void uiColorListBox::items_draw(
int index,
const Rect & itemRect)
3925 constexpr
int BORDER = 1;
3927 canvas()->
fillRectangle(itemRect.
X1 + BORDER, itemRect.
Y1 + BORDER, itemRect.
X2 - BORDER, itemRect.
Y2 - BORDER);
3951 void uiFileBrowser::items_draw(
int index,
const Rect & itemRect)
3953 int x = itemRect.
X1 + 1;
3957 static const char * DIRTXT =
"[dir]";
3964 void uiFileBrowser::items_select(
int index,
bool select)
3968 else if (index == m_selected || index == -1)
3976 m_selected = m_dir.
count() > 0 ? 0 : -1;
3984 m_selected = m_dir.
count() > 0 ? 0 : -1;
3991 return m_selected >= 0 ? m_dir.
get(m_selected)->
name :
nullptr;
3997 return m_selected >= 0 ? m_dir.
get(m_selected)->
isDir :
false;
4001 void uiFileBrowser::enterSubDir()
4003 if (m_selected >= 0) {
4004 auto selItem = m_dir.
get(m_selected);
4005 if (selItem->isDir) {
4018 m_selected = imin(m_dir.
count() - 1, m_selected);
4024 void uiFileBrowser::processEvent(uiEvent * event)
4026 uiCustomListBox::processEvent(event);
4028 switch (event->id) {
4043 case UIEVT_DBLCLICK:
4063 :
uiControl(parent, pos, size, visible, 0),
4064 m_listHeight(listHeight)
4077 uiCustomComboBox::~uiCustomComboBox()
4089 updateEditControl();
4093 void uiCustomComboBox::processEvent(uiEvent * event)
4095 uiControl::processEvent(event);
4097 switch (event->id) {
4104 updateEditControl();
4107 listbox()->
onKeyUp = [&](uiKeyEventInfo key) {
4121 case UIEVT_MOUSEBUTTONDOWN:
4122 if (event->params.mouse.changedButton == 1 && getButtonRect().contains(event->params.mouse.status.X, event->params.mouse.status.Y))
4126 case UIEVT_CHILDSETFOCUS:
4127 if (m_comboBoxProps.
openOnFocus && event->params.focusInfo.newFocused == editcontrol()
4128 && event->params.focusInfo.oldFocused != listbox()
4129 && event->params.focusInfo.oldFocused !=
this) {
4134 case UIEVT_SETFOCUS:
4135 if (event->params.focusInfo.oldFocused != listbox() && event->params.focusInfo.oldFocused != editcontrol()) {
4141 }
else if (event->params.focusInfo.oldFocused == listbox()) {
4146 case UIEVT_KILLFOCUS:
4147 if (event->params.focusInfo.newFocused != listbox()) {
4153 listbox()->processEvent(event);
4158 if (((event->params.key.RALT || event->params.key.LALT) && (event->params.key.VK ==
VK_DOWN || event->params.key.VK ==
VK_UP)) || (event->params.key.VK ==
VK_RETURN))
4168 void uiCustomComboBox::openListBox()
4172 r.Y2 = r.Y1 + m_listHeight;
4180 void uiCustomComboBox::closeListBox()
4186 void uiCustomComboBox::switchListBox()
4188 if (listbox()->
state().visible) {
4197 Size uiCustomComboBox::getEditControlSize()
4200 return Size(clientArea.width() - buttonWidth(), clientArea.height());
4204 int uiCustomComboBox::buttonWidth()
4207 return clientArea.height() / 2;
4211 Rect uiCustomComboBox::getButtonRect()
4214 btnRect.X1 = btnRect.X2 - buttonWidth() + 1;
4219 void uiCustomComboBox::paintComboBox()
4221 Rect btnRect = getButtonRect();
4229 Rect arrowRect = btnRect.hShrink(1).vShrink(2);
4230 int hHeight = arrowRect.height() / 2;
4231 int hWidth = arrowRect.width() / 2;
4232 constexpr
int vDist = 2;
4233 canvas()->
drawLine(arrowRect.X1, arrowRect.Y1 + hHeight - vDist, arrowRect.X1 + hWidth, arrowRect.Y1);
4234 canvas()->
drawLine(arrowRect.X1 + hWidth, arrowRect.Y1, arrowRect.X2, arrowRect.Y1 + hHeight - vDist);
4235 canvas()->
drawLine(arrowRect.X1, arrowRect.Y1 + hHeight + vDist, arrowRect.X1 + hWidth, arrowRect.Y2);
4236 canvas()->
drawLine(arrowRect.X1 + hWidth, arrowRect.Y2, arrowRect.X2, arrowRect.Y1 + hHeight + vDist);
4251 m_textEdit(nullptr),
4267 uiComboBox::~uiComboBox()
4273 void uiComboBox::updateEditControl()
4292 m_colorBox(nullptr),
4293 m_colorListBox(nullptr)
4305 uiColorComboBox::~uiColorComboBox()
4311 void uiColorComboBox::updateEditControl()
4327 :
uiControl(parent, pos, size, visible, 0),
4346 uiCheckBox::~uiCheckBox()
4351 void uiCheckBox::paintCheckBox()
4366 canvas()->
drawLine(r.X1, r.Y2 - r.height() / 3, r.X1 + r.width() / 3, r.Y2);
4367 canvas()->
drawLine(r.X1 + r.width() / 3, r.Y2, r.X2, r.Y1);
4371 canvas()->
fillEllipse(r.X1 + r.width() / 2 - 1, r.Y1 + r.height() / 2 - 1, r.width(), r.height());
4378 void uiCheckBox::processEvent(uiEvent * event)
4380 uiControl::processEvent(event);
4382 switch (event->id) {
4393 case UIEVT_MOUSEENTER:
4397 case UIEVT_MOUSEBUTTONDOWN:
4398 if (event->params.mouse.changedButton == 1)
4402 case UIEVT_MOUSELEAVE:
4420 void uiCheckBox::trigger()
4424 m_checked = !m_checked;
4438 if (value != m_checked) {
4448 void uiCheckBox::unCheckGroup()
4450 if (m_groupIndex == -1)
4453 if (sibling !=
this &&
objectType().uiCheckBox) {
4455 if (chk->m_groupIndex == m_groupIndex)
4473 :
uiControl(parent, pos, size, visible, 0),
4474 m_orientation(orientation),
4478 m_ticksFrequency(25)
4493 uiSlider::~uiSlider()
4500 if (value != m_position) {
4501 m_position = iclamp(value, m_min, m_max);
4512 m_ticksFrequency = ticksFrequency;
4513 m_position = iclamp(m_position, m_min, m_max);
4517 void uiSlider::paintSlider()
4520 Rect slideRect = cRect.shrink(4);
4521 Rect gripRect = getGripRect();
4527 switch (m_orientation) {
4540 if (m_ticksFrequency > 0) {
4542 int range = m_max - m_min + 0;
4543 for (
int p = m_min; p <= m_max; p += m_ticksFrequency) {
4544 switch (m_orientation) {
4547 int x = slideRect.
X1 + slideRect.width() * (p - m_min) / range;
4553 int y = slideRect.
Y2 - slideRect.height() * (p - m_min) / range;
4566 Rect uiSlider::getGripRect()
4569 Rect slideRect = cRect.shrink(4);
4570 int range = m_max - m_min + 0;
4571 switch (m_orientation) {
4574 int x = slideRect.X1 + slideRect.width() * (m_position - m_min) / range;
4575 return Rect(x - 4, cRect.Y1, x + 4, cRect.Y2);
4579 int y = slideRect.Y2 - slideRect.height() * (m_position - m_min) / range;
4580 return Rect(cRect.X1, y - 4, cRect.X2, y + 4);
4588 void uiSlider::moveGripTo(
int x,
int y)
4591 Rect slideRect = cRect.shrink(4);
4592 int range = m_max - m_min + 1;
4593 switch (m_orientation) {
4595 setPosition(m_min + (x - slideRect.X1) * range / slideRect.width());
4598 setPosition(m_min + (slideRect.Y2 - y) * range / slideRect.height());
4604 void uiSlider::processEvent(uiEvent * event)
4606 uiControl::processEvent(event);
4608 switch (event->id) {
4615 case UIEVT_MOUSEBUTTONDOWN:
4616 moveGripTo(event->params.mouse.status.X, event->params.mouse.status.Y);
4619 case UIEVT_MOUSEMOVE:
4620 if (
app()->capturedMouseWindow() ==
this)
4621 moveGripTo(event->params.mouse.status.X, event->params.mouse.status.Y);
4625 handleKeyDown(event->params.key);
4634 void uiSlider::handleKeyDown(uiKeyEventInfo key)
int textExtent(FontInfo const *fontInfo, char const *text)
Calculates text extension in pixels.
Represents a 24 bit RGB color.
uiWindow * setActiveWindow(uiWindow *value)
Sets the active window.
uiWindowStyle & windowStyle()
Sets or gets window style.
void selectItem(int index, bool add=false, bool range=false)
Selects a listbox item.
GlyphOptions & Bold(bool value)
Helper method to set or reset bold.
Delegate onChange
Change event delegate.
int selectedItem()
Represents currently selected item.
A class with a set of drawing methods.
Delegate onDblClick
Mouse double click event delegate.
Shows a list of 16 colors, one selectable.
A frame is a window with a title bar, maximize/minimize/close buttons and that is resizeable or movea...
int lastSelectedItem()
Gets the last selected item.
Contains details about the key event.
Rect rect(uiOrigin origin)
Determines the window bounding box.
ModalWindowState * initModalWindow(uiWindow *window)
Begins modal window processing.
uiTextEdit(uiWindow *parent, char const *text, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
uiOrientation
Item direction/orientation.
void setScrollBar(uiOrientation orientation, int position, int visible, int range, bool repaintScrollbar)
Sets scrollbar position, visible portion and range.
int firstSelectedItem()
Gets the first selected item.
Represents the whole application base class.
uiMessageBoxResult messageBox(char const *title, char const *text, char const *button1Text, char const *button2Text=nullptr, char const *button3Text=nullptr, uiMessageBoxIcon icon=uiMessageBoxIcon::Question)
Displays a modal dialog box with an icon, text and some buttons.
bool insertEvent(uiEvent const *event)
Inserts (first position) an event in the event queue and returns without waiting for the receiver to ...
This file contains all classes related to FabGL Graphical User Interface.
This is a combination of a listbox and another component, base of all combobox components.
uiStyle * style()
Gets current application controls style.
void setText(char const *value)
Sets label text.
char const * text()
Gets current content of the text edit.
void selectItem(int index)
Selects an item.
Base class for all visible UI elements (Frames and Controls)
void update()
Reloads current directory content and repaints.
int getHeight()
Determines the canvas height in pixels.
int run(BitmappedDisplayController *displayController, Keyboard *keyboard=nullptr, Mouse *mouse=nullptr)
Initializes application and executes the main event loop.
Keyboard * keyboard()
Returns the instance of Keyboard object automatically created by PS2Controller.
void setup(int min, int max, int ticksFrequency)
Sets minimum, maximum position and ticks frequency.
A color box is a control that shows a single color.
int virtualKeyToASCII(VirtualKey virtualKey)
Converts virtual key to ASCII.
void setParentProcessKbdEvents(bool value)
Enables a child window to send keyboard events to its parent.
GlyphOptions & Italic(bool value)
Helper method to set or reset italic.
void setUIApp(uiApp *app)
Sets current UI app.
uiColorBox(uiWindow *parent, const Point &pos, const Size &size, Color color=Color::BrightWhite, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
DirItem const * get(int index)
Gets file/directory at index.
uiColorComboBox(uiWindow *parent, const Point &pos, const Size &size, int listHeight, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
FontInfo const * textFont
Shows a list of selectable string items.
This file contains fabgl::Keyboard definition.
Bitmap const * bitmap()
Gets image bitmap.
void bringAfter(uiWindow *insertionPoint)
Brings this window after another one.
Size size()
Determines the window size.
RGB888 mouseOverBackgroundButtonColor
virtual void init()
Method to inherit to implement an application.
uiWindow * parent()
Determines the parent window.
void resetGlyphOptions()
Resets glyph options.
uiImage(uiWindow *parent, Bitmap const *bitmap, const Point &pos, const Size &size=Size(0, 0), bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
Base class of all UI elements that can receive events.
void quit(int exitCode)
Terminates application and free resources.
Color
This enum defines named colors.
uiLabel(uiWindow *parent, char const *text, const Point &pos, const Size &size=Size(0, 0), bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
uiColorListBox(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
bool setDirectory(const char *path)
Sets absolute directory path.
int showModalWindow(uiWindow *window)
Makes a window visible and handles it has a modal window.
The PS2 Keyboard controller class.
Represents the base abstract class for bitmapped display controllers.
Delegate onClick
Mouse click event delegate.
This file contains fabgl::Canvas definition.
Size clientSize()
Determines the client area size.
uiWindow * lastChild()
Gets last child.
A panel is used to contain and to group some controls.
int getWidth()
Determines the canvas width in pixels.
Represents a checkbox or a radiobutton.
void setPaintOptions(PaintOptions options)
Sets paint options.
This file contains fabgl::Mouse definition.
void moveWindow(uiWindow *window, int x, int y)
Moves a window.
void destroyWindow(uiWindow *window)
Destroys a window.
uint16_t caretBlinkingTime
Delegate onResize
Resize window event delegate.
uiCheckBoxKind
Specifies the combobox behaviour.
void setTitleFmt(const char *format,...)
Sets window title as formatted text.
void fillEllipse(int X, int Y, int width, int height)
Fills an ellipse specifying center and size, using current brush color.
void update()
Updates the label content.
void setColor(Color value)
Sets current colorbox color.
uiWindowProps & windowProps()
Sets or gets window properties.
void setTextFmt(const char *format,...)
Sets label formatted text.
uiCustomComboBox(uiWindow *parent, const Point &pos, const Size &size, int listHeight, bool visible, uint32_t styleClassID)
Creates an instance of the object.
Point mouseDownPos()
Determines mouse position when left button was down.
void setBrushColor(uint8_t red, uint8_t green, uint8_t blue)
Sets brush (background) color specifying color components.
void setClippingRect(Rect const &rect)
Sets clipping rectangle relative to the origin.
bool processModalWindowEvents(ModalWindowState *state, int timeout)
Processes all messages from modal window.
RGB888 focusedSelectedBackgroundColor
uiButtonKind
Specifies the button kind.
Delegate< Rect > onPaint
Paint event delegate.
uiWindow * parentFrame()
Determines the parent frame.
uiMessageBoxResult inputBox(char const *title, char const *text, char *inOutString, int maxLength, char const *button1Text, char const *button2Text=nullptr)
Displays a modal dialog box with a text, a text edit and up to two buttons.
void deselectAll()
Deselects all selected items.
uiFrameProps & frameProps()
Sets or gets frame properties.
Delegate onChange
Change event delegate.
uiCustomListBox(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
RGB888 buttonBackgroundColor
uiFrameStyle & frameStyle()
Sets or gets frame style.
Represents the coordinate of a point.
void setPosition(int value)
Sets the slider position.
This file contains some utility classes and functions.
static PS2Controller * instance()
Returns the singleton instance of PS2Controller class.
Delegate< uiTimerHandle > onTimer
Timer event delegate.
RGB888 mouseOverBackgroundColor
uiSlider(uiWindow *parent, const Point &pos, const Size &size, uiOrientation orientation, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
void fillRectangle(int X1, int Y1, int X2, int Y2)
Fills a rectangle using the current brush color.
uiFrame(uiWindow *parent, char const *title, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
uiControl(uiWindow *parent, const Point &pos, const Size &size, bool visible, uint32_t styleClassID=0)
Creates an instance of the object.
uiOrigin
Specifies window rectangle origin.
Rect transformRect(Rect const &rect, uiWindow *baseWindow)
Transforms rectangle origins from current window to another one.
GlyphOptions & Underline(bool value)
Helper method to set or reset underlined.
uiPaintBox(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
void drawGlyph(int X, int Y, int width, int height, uint8_t const *data, int index=0)
Draws a glyph at specified position.
char const * filename()
Currently selected filename.
bool isMouseAvailable()
Checks if mouse has been detected and correctly initialized.
uiMessageBoxResult
Return values from uiApp.messageBox() method.
Specifies various glyph painting options.
uiWindow * screenToWindow(Point &point)
Determines which window a point belongs to.
uint8_t focusedBorderSize
void maximizeWindow(uiWindow *window, bool value)
Maximizes or restores a window.
Delegate< uiTimerHandle > onTimer
Timer event delegate.
void terminateAbsolutePositioner()
Terminates absolute position handler.
void drawTextWithEllipsis(FontInfo const *fontInfo, int X, int Y, char const *text, int maxX)
Draws a string at specified position. Add ellipses before truncation.
Represents a text edit control.
void minimizeWindow(uiWindow *window, bool value)
Minimizes or restores a window.
uiWindow * prev()
Gets previous sibling.
void repaintWindow(uiWindow *window)
Repaints a window.
uiTextEditProps & textEditProps()
Sets or gets text edit properties.
RGB888 mouseOverButtonColor
CursorName
This enum defines a set of predefined mouse cursors.
int focusIndex()
Determines the focus index (aka tab-index)
RGB888 mouseOverBackgroundColor
FontInfo const * textFont
uiWindow * firstChild()
Gets first child.
void setMouseCursor(Cursor *cursor)
Sets mouse cursor and make it visible.
uint8_t hasMaximizeButton
GlyphOptions & DoubleWidth(uint8_t value)
Helper method to set or reset doubleWidth.
void reshapeWindow(uiWindow *window, Rect const &rect)
Reshapes a window.
FontInfo const * titleFont
StringList & items()
A list of strings representing items of the combobox.
RGB888 activeTitleBackgroundColor
uiWindow * setFocusedWindow(uiWindow *value)
Sets the focused window (control)
void setBitmap(Bitmap const *bitmap)
Sets image bitmap.
Point pos()
Determines the window position relative to parent window.
virtual Rect clientRect(uiOrigin origin)
Determines the client area bounding box.
void setChecked(bool value)
Sets current checkbox or radiobutton checked status.
Represents a bidimensional size.
uiCheckBox(uiWindow *parent, const Point &pos, const Size &size, uiCheckBoxKind kind=uiCheckBoxKind::CheckBox, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
Delegate onKillFocus
Kill focus event delegate.
uiObjectType & objectType()
Determines the object type.
bool hasChildren()
Determines whether this window has children.
Delegate< uiKeyEventInfo > onKeyUp
Key-up event delegate.
RGB888 focusedBorderColor
Delegate onShow
Show window event delegate.
bool isDirectory()
Determines whether currently selected item is a directory.
uiTimerHandle setTimer(uiEvtHandler *dest, int periodMS)
Setups a timer.
int max()
Gets maximum position.
void clear()
Fills the entire canvas with the brush color.
void setUIApp(uiApp *app)
Sets current UI app.
uiApp * app()
Determines the app that owns this object.
FontInfo const * textFont
void setGlyphOptions(GlyphOptions options)
Sets drawing options for the next glyphs.
void resizeWindow(uiWindow *window, int width, int height)
Resizes a window.
int endModalWindow(ModalWindowState *state)
Ends modal window processing.
bool postEvent(uiEvent const *event)
Places an event in the event queue and returns without waiting for the receiver to process the event...
uint32_t styleClassID()
Determines current style class for this UI element.
void drawLine(int X1, int Y1, int X2, int Y2)
Draws a line specifying initial and ending coordinates.
A label is a static text UI element.
void processEvents()
Processes all events in queue.
uiComboBox(uiWindow *parent, const Point &pos, const Size &size, int listHeight, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
uiListBox(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
void bringOnTop()
Brings this window on top.
uiWindowState state()
Determines the window state.
uiPanel(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
Rect clientRect(uiOrigin origin)
Determines the client area bounding box.
uiWindow * moveFocus(int delta)
Move focus to a control with current focus index plus a delta.
RGB888 checkedBackgroundColor
void repaintRect(Rect const &rect)
Repaints a screen area.
This is the base class for all controls. A control can have focus and is not activable.
RGB888 titleBackgroundColor
bool hasFocus()
Determines whether this window or control has focus.
void setPenColor(uint8_t red, uint8_t green, uint8_t blue)
Sets pen (foreground) color specifying color components.
void repaint()
Repaints this window.
uiFileBrowser(uiWindow *parent, const Point &pos, const Size &size, bool visible=true, uint32_t styleClassID=0)
Creates an instance of the object.
void repaint(Rect const &rect)
Repaints a rectangle of this window.
char const * title()
Determines the window title.
GlyphOptions & FillBackground(bool value)
Helper method to set or reset fillBackground.
RGB888 selectedBackgroundColor
Delegate onPaint
Paint event delegate.
RGB888 focusedBackgroundColor
Shows generic a list of selectable items.
uiWindow * next()
Gets next sibling.
void drawText(int X, int Y, char const *text, bool wrap=false)
Draws a string at specified position.
Delegate onHide
Hide window event delegate.
void setDirectory(char const *path)
Sets current directory as absolute path.
uiListBoxStyle & listBoxStyle()
Sets or gets listbox style.
void invertRectangle(int X1, int Y1, int X2, int Y2)
Inverts a rectangle.
Delegate onChange
Change event delegate.
void changeDirectory(const char *subdir)
Sets relative directory path.
Delegate< uiKeyEventInfo > onKeyUp
Key-up event delegate.
void setText(char const *value)
Replaces current text.
Delegate< uiKeyEventInfo > onKeyDown
Key-down event delegate.
Point clientPos()
Determines position of the client area.
uiWindow(uiWindow *parent, const Point &pos, const Size &size, bool visible, uint32_t styleClassID=0)
Creates an instance of the object.
GlyphOptions & Invert(uint8_t value)
Helper method to set or reset foreground and background swapping.
uiFrame * rootWindow()
Gets a pointer to the root window.
void runAsync(BitmappedDisplayController *displayController, int taskStack=3000, Keyboard *keyboard=nullptr, Mouse *mouse=nullptr)
Initializes application and executes asynchronously the main event loop.
The PS2 Mouse controller class.
void setupAbsolutePositioner(int width, int height, bool createAbsolutePositionsQueue, BitmappedDisplayController *updateDisplayController=nullptr, uiApp *app=nullptr)
Initializes absolute position handler.
void setOrigin(int X, int Y)
Sets the axes origin.
void moveTo(int X, int Y)
Moves current pen position to the spcified coordinates.
Mouse * mouse()
Returns the instance of Mouse object automatically created by PS2Controller.
int count()
Determines number of files in current directory.
bool reload()
Reloads directory content.
Delegate onChange
Text edit event delegate.
void enableBackgroundPrimitiveTimeout(bool value)
Enables or disables execution time limitation inside vertical retracing interrupt.
void resetPaintOptions()
Resets paint options.
bool isMouseOver()
Determines whether the mouse is over this window.
void showWindow(uiWindow *window, bool value)
Makes a window visible or invisible.
uint8_t hasMinimizeButton
RGB888 focusedBackgroundColor
void exitModal(int modalResult)
Exits from a modal window.
uiWindow * focusedWindow()
Gets the focused window (control)
void changeDirectory(char const *path)
Changes current directory as relative path.
void drawRectangle(int X1, int Y1, int X2, int Y2)
Draws a rectangle using the current pen color.
char const * text()
Determines label text.
void lineTo(int X, int Y)
Draws a line starting from current pen position.
void setTitle(char const *value)
Sets window title.
uiMessageBoxIcon
Icon displayed by the uiApp.messageBox() method.
void enableKeyboardAndMouseEvents(bool value)
Enables or disables mouse and keyboard events.
int min()
Gets minimum position.
Image control to display a static bitmap.
void killTimer(uiTimerHandle handle)
Kills a timer.
void drawBitmap(int X, int Y, Bitmap const *bitmap)
Draws a bitmap at specified position.
Delegate onChange
Slider changed event delegate.