Several widget fixes after optimizing repainting.
This commit is contained in:
parent
5f305dd14c
commit
094b263c36
10 changed files with 89 additions and 21 deletions
|
|
@ -593,4 +593,5 @@ int32_t appMain(DxeAppContextT *ctx) {
|
||||||
|
|
||||||
void appShutdown(void) {
|
void appShutdown(void) {
|
||||||
shellUnregisterDesktopUpdate(desktopUpdate);
|
shellUnregisterDesktopUpdate(desktopUpdate);
|
||||||
|
dvxQuit(sAc);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1858,15 +1858,9 @@ static void handleMouseButton(AppContextT *ctx, int32_t mx, int32_t my, int32_t
|
||||||
} else {
|
} else {
|
||||||
ctx->lastTitleClickTime = now;
|
ctx->lastTitleClickTime = now;
|
||||||
ctx->lastTitleClickId = win->id;
|
ctx->lastTitleClickId = win->id;
|
||||||
|
|
||||||
// Don't start a drag on a maximized window --
|
|
||||||
// dragging clears the maximized flag, which
|
|
||||||
// prevents the double-click restore from working.
|
|
||||||
if (!win->maximized) {
|
|
||||||
wmDragBegin(&ctx->stack, hitIdx, mx, my);
|
wmDragBegin(&ctx->stack, hitIdx, mx, my);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIT_CLOSE:
|
case HIT_CLOSE:
|
||||||
|
|
@ -2889,7 +2883,7 @@ static void pollKeyboard(AppContextT *ctx) {
|
||||||
|
|
||||||
wclsClosePopup(closing);
|
wclsClosePopup(closing);
|
||||||
|
|
||||||
wgtInvalidatePaint(closing);
|
wgtInvalidate(closing);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3011,6 +3005,7 @@ static void pollKeyboard(AppContextT *ctx) {
|
||||||
if (p->wclass && (p->wclass->flags & WCLASS_SCROLL_CONTAINER) &&
|
if (p->wclass && (p->wclass->flags & WCLASS_SCROLL_CONTAINER) &&
|
||||||
wclsHas(p, WGT_METHOD_SCROLL_CHILD_INTO_VIEW)) {
|
wclsHas(p, WGT_METHOD_SCROLL_CHILD_INTO_VIEW)) {
|
||||||
wclsScrollChildIntoView(p, next);
|
wclsScrollChildIntoView(p, next);
|
||||||
|
wgtInvalidate(p);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -588,6 +588,9 @@ typedef struct {
|
||||||
int32_t dragWindow;
|
int32_t dragWindow;
|
||||||
int32_t dragOffX;
|
int32_t dragOffX;
|
||||||
int32_t dragOffY;
|
int32_t dragOffY;
|
||||||
|
int32_t dragStartX; // mouse position at drag begin (for deadzone)
|
||||||
|
int32_t dragStartY;
|
||||||
|
bool dragActive; // true once mouse moved past deadzone
|
||||||
int32_t resizeWindow;
|
int32_t resizeWindow;
|
||||||
int32_t resizeEdge;
|
int32_t resizeEdge;
|
||||||
int32_t scrollWindow; // window being scroll-dragged (HIT_NONE = none)
|
int32_t scrollWindow; // window being scroll-dragged (HIT_NONE = none)
|
||||||
|
|
|
||||||
20
core/dvxWm.c
20
core/dvxWm.c
|
|
@ -1407,6 +1407,9 @@ void wmDragBegin(WindowStackT *stack, int32_t idx, int32_t mouseX, int32_t mouse
|
||||||
stack->dragWindow = idx;
|
stack->dragWindow = idx;
|
||||||
stack->dragOffX = mouseX - stack->windows[idx]->x;
|
stack->dragOffX = mouseX - stack->windows[idx]->x;
|
||||||
stack->dragOffY = mouseY - stack->windows[idx]->y;
|
stack->dragOffY = mouseY - stack->windows[idx]->y;
|
||||||
|
stack->dragStartX = mouseX;
|
||||||
|
stack->dragStartY = mouseY;
|
||||||
|
stack->dragActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1435,11 +1438,28 @@ void wmDragEnd(WindowStackT *stack) {
|
||||||
// we don't need to ask the app to repaint during the drag, just blit from
|
// we don't need to ask the app to repaint during the drag, just blit from
|
||||||
// its buffer at the new position.
|
// its buffer at the new position.
|
||||||
|
|
||||||
|
#define DRAG_DEADZONE 4
|
||||||
|
|
||||||
void wmDragMove(WindowStackT *stack, DirtyListT *dl, int32_t mouseX, int32_t mouseY, int32_t screenW, int32_t screenH) {
|
void wmDragMove(WindowStackT *stack, DirtyListT *dl, int32_t mouseX, int32_t mouseY, int32_t screenW, int32_t screenH) {
|
||||||
if (stack->dragWindow < 0 || stack->dragWindow >= stack->count) {
|
if (stack->dragWindow < 0 || stack->dragWindow >= stack->count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't move until the mouse has moved past the deadzone from the
|
||||||
|
// initial click point. This allows double-clicks on the title bar
|
||||||
|
// without accidentally starting a drag.
|
||||||
|
if (!stack->dragActive) {
|
||||||
|
int32_t dx = mouseX - stack->dragStartX;
|
||||||
|
int32_t dy = mouseY - stack->dragStartY;
|
||||||
|
|
||||||
|
if (dx < -DRAG_DEADZONE || dx > DRAG_DEADZONE ||
|
||||||
|
dy < -DRAG_DEADZONE || dy > DRAG_DEADZONE) {
|
||||||
|
stack->dragActive = true;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WindowT *win = stack->windows[stack->dragWindow];
|
WindowT *win = stack->windows[stack->dragWindow];
|
||||||
int32_t minVisible = 50;
|
int32_t minVisible = 50;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,8 +338,17 @@ static void widgetOnMouseInner(WindowT *win, WidgetT *root, int32_t x, int32_t y
|
||||||
// Click on popup area -- dispatch to widget's onMouse.
|
// Click on popup area -- dispatch to widget's onMouse.
|
||||||
// The widget may keep the popup open (e.g. scrollbar click)
|
// The widget may keep the popup open (e.g. scrollbar click)
|
||||||
// or close it (item selection sets sOpenPopup = NULL).
|
// or close it (item selection sets sOpenPopup = NULL).
|
||||||
wclsOnMouse(sOpenPopup, root, x, y);
|
WidgetT *popupWidget = sOpenPopup;
|
||||||
|
wclsOnMouse(popupWidget, root, x, y);
|
||||||
|
|
||||||
|
// If the popup closed, need a full repaint to erase the
|
||||||
|
// overlay (it's painted outside widget bounds).
|
||||||
|
if (!sOpenPopup) {
|
||||||
|
wgtInvalidate(root);
|
||||||
|
} else {
|
||||||
wgtInvalidatePaint(root);
|
wgtInvalidatePaint(root);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,7 +357,7 @@ static void widgetOnMouseInner(WindowT *win, WidgetT *root, int32_t x, int32_t y
|
||||||
|
|
||||||
wclsClosePopup(sOpenPopup);
|
wclsClosePopup(sOpenPopup);
|
||||||
sOpenPopup = NULL;
|
sOpenPopup = NULL;
|
||||||
wgtInvalidatePaint(root);
|
wgtInvalidate(root);
|
||||||
// Fall through to normal click handling
|
// Fall through to normal click handling
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,15 @@ void shellForceKillApp(AppContextT *ctx, ShellAppT *app) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call shutdown hook so the app can unregister callbacks, close
|
||||||
|
// handles, etc. Without this, dangling function pointers (e.g.
|
||||||
|
// shellDesktopUpdate callbacks) cause crashes after dlclose.
|
||||||
|
if (app->shutdownFn) {
|
||||||
|
ctx->currentAppId = app->appId;
|
||||||
|
app->shutdownFn();
|
||||||
|
ctx->currentAppId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Destroy all windows belonging to this app. Walk backwards because
|
// Destroy all windows belonging to this app. Walk backwards because
|
||||||
// dvxDestroyWindow removes the window from the stack, shifting indices.
|
// dvxDestroyWindow removes the window from the stack, shifting indices.
|
||||||
for (int32_t i = ctx->stack.count - 1; i >= 0; i--) {
|
for (int32_t i = ctx->stack.count - 1; i >= 0; i--) {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ void widgetComboBoxOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
wgtInvalidatePaint(w);
|
wgtInvalidate(w);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,8 @@ void widgetDropdownOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (w->onChange) {
|
if (w->onChange) {
|
||||||
w->onChange(w);
|
w->onChange(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wgtInvalidate(w);
|
||||||
} else if (key >= 0x20 && key < 0x7F) {
|
} else if (key >= 0x20 && key < 0x7F) {
|
||||||
int32_t found = widgetTypeAheadSearch((char)key, d->items, d->itemCount, d->hoverIdx);
|
int32_t found = widgetTypeAheadSearch((char)key, d->items, d->itemCount, d->hoverIdx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ typedef struct {
|
||||||
// Prototypes
|
// Prototypes
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
static void invalidateOldSelection(WidgetT *group, int32_t oldIdx);
|
||||||
static void widgetRadioDestroy(WidgetT *w);
|
static void widgetRadioDestroy(WidgetT *w);
|
||||||
static void widgetRadioGroupDestroy(WidgetT *w);
|
static void widgetRadioGroupDestroy(WidgetT *w);
|
||||||
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy);
|
||||||
|
|
@ -150,6 +151,7 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (next) {
|
if (next) {
|
||||||
RadioDataT *nd = (RadioDataT *)next->data;
|
RadioDataT *nd = (RadioDataT *)next->data;
|
||||||
RadioGroupDataT *gd = (RadioGroupDataT *)next->parent->data;
|
RadioGroupDataT *gd = (RadioGroupDataT *)next->parent->data;
|
||||||
|
invalidateOldSelection(w->parent, gd->selectedIdx);
|
||||||
sFocusedWidget = next;
|
sFocusedWidget = next;
|
||||||
gd->selectedIdx = nd->index;
|
gd->selectedIdx = nd->index;
|
||||||
|
|
||||||
|
|
@ -174,6 +176,7 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
RadioDataT *pd = (RadioDataT *)prev->data;
|
RadioDataT *pd = (RadioDataT *)prev->data;
|
||||||
RadioGroupDataT *gd = (RadioGroupDataT *)prev->parent->data;
|
RadioGroupDataT *gd = (RadioGroupDataT *)prev->parent->data;
|
||||||
|
invalidateOldSelection(w->parent, gd->selectedIdx);
|
||||||
sFocusedWidget = prev;
|
sFocusedWidget = prev;
|
||||||
gd->selectedIdx = pd->index;
|
gd->selectedIdx = pd->index;
|
||||||
|
|
||||||
|
|
@ -192,6 +195,21 @@ void widgetRadioOnKey(WidgetT *w, int32_t key, int32_t mod) {
|
||||||
// widgetRadioOnMouse
|
// widgetRadioOnMouse
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
// Find the currently selected radio in the group and invalidate it
|
||||||
|
static void invalidateOldSelection(WidgetT *group, int32_t oldIdx) {
|
||||||
|
for (WidgetT *c = group->firstChild; c; c = c->nextSibling) {
|
||||||
|
if (c->type == sRadioTypeId) {
|
||||||
|
RadioDataT *rd = (RadioDataT *)c->data;
|
||||||
|
|
||||||
|
if (rd->index == oldIdx) {
|
||||||
|
wgtInvalidatePaint(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) {
|
void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) {
|
||||||
(void)root;
|
(void)root;
|
||||||
(void)vx;
|
(void)vx;
|
||||||
|
|
@ -201,6 +219,11 @@ void widgetRadioOnMouse(WidgetT *w, WidgetT *root, int32_t vx, int32_t vy) {
|
||||||
if (w->parent && w->parent->type == sRadioGroupTypeId) {
|
if (w->parent && w->parent->type == sRadioGroupTypeId) {
|
||||||
RadioDataT *rd = (RadioDataT *)w->data;
|
RadioDataT *rd = (RadioDataT *)w->data;
|
||||||
RadioGroupDataT *gd = (RadioGroupDataT *)w->parent->data;
|
RadioGroupDataT *gd = (RadioGroupDataT *)w->parent->data;
|
||||||
|
|
||||||
|
if (gd->selectedIdx != rd->index) {
|
||||||
|
invalidateOldSelection(w->parent, gd->selectedIdx);
|
||||||
|
}
|
||||||
|
|
||||||
gd->selectedIdx = rd->index;
|
gd->selectedIdx = rd->index;
|
||||||
|
|
||||||
if (w->parent->onChange) {
|
if (w->parent->onChange) {
|
||||||
|
|
|
||||||
|
|
@ -414,17 +414,19 @@ void widgetTabControlPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const B
|
||||||
|
|
||||||
td->scrollOffset = clampInt(td->scrollOffset, 0, maxOff);
|
td->scrollOffset = clampInt(td->scrollOffset, 0, maxOff);
|
||||||
|
|
||||||
uint32_t fg = colors->contentFg;
|
bool canScrollLeft = (td->scrollOffset > 0);
|
||||||
|
bool canScrollRight = (td->scrollOffset < maxOff);
|
||||||
BevelStyleT btnBevel = BEVEL_RAISED(colors, 1);
|
BevelStyleT btnBevel = BEVEL_RAISED(colors, 1);
|
||||||
|
|
||||||
// Left arrow button
|
// Left arrow button
|
||||||
drawBevel(d, ops, w->x, w->y, TAB_ARROW_W, tabH, &btnBevel);
|
drawBevel(d, ops, w->x, w->y, TAB_ARROW_W, tabH, &btnBevel);
|
||||||
{
|
{
|
||||||
|
uint32_t arrowFg = canScrollLeft ? colors->contentFg : colors->windowShadow;
|
||||||
int32_t cx = w->x + TAB_ARROW_W / 2;
|
int32_t cx = w->x + TAB_ARROW_W / 2;
|
||||||
int32_t cy = w->y + tabH / 2;
|
int32_t cy = w->y + tabH / 2;
|
||||||
|
|
||||||
for (int32_t i = 0; i < 4; i++) {
|
for (int32_t i = 0; i < 4; i++) {
|
||||||
drawVLine(d, ops, cx - 2 + i, cy - i, 1 + i * 2, fg);
|
drawVLine(d, ops, cx - 2 + i, cy - i, 1 + i * 2, arrowFg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,11 +434,12 @@ void widgetTabControlPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const B
|
||||||
int32_t rx = w->x + w->w - TAB_ARROW_W;
|
int32_t rx = w->x + w->w - TAB_ARROW_W;
|
||||||
drawBevel(d, ops, rx, w->y, TAB_ARROW_W, tabH, &btnBevel);
|
drawBevel(d, ops, rx, w->y, TAB_ARROW_W, tabH, &btnBevel);
|
||||||
{
|
{
|
||||||
|
uint32_t arrowFg = canScrollRight ? colors->contentFg : colors->windowShadow;
|
||||||
int32_t cx = rx + TAB_ARROW_W / 2;
|
int32_t cx = rx + TAB_ARROW_W / 2;
|
||||||
int32_t cy = w->y + tabH / 2;
|
int32_t cy = w->y + tabH / 2;
|
||||||
|
|
||||||
for (int32_t i = 0; i < 4; i++) {
|
for (int32_t i = 0; i < 4; i++) {
|
||||||
drawVLine(d, ops, cx + 2 - i, cy - i, 1 + i * 2, fg);
|
drawVLine(d, ops, cx + 2 - i, cy - i, 1 + i * 2, arrowFg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -451,6 +454,9 @@ void widgetTabControlPaint(WidgetT *w, DisplayT *d, const BlitOpsT *ops, const B
|
||||||
int32_t oldClipH = d->clipH;
|
int32_t oldClipH = d->clipH;
|
||||||
setClipRect(d, headerLeft, w->y, headerRight - headerLeft, tabH + 2);
|
setClipRect(d, headerLeft, w->y, headerRight - headerLeft, tabH + 2);
|
||||||
|
|
||||||
|
// Clear the header strip so scrolled-away tab pixels are erased
|
||||||
|
rectFill(d, ops, headerLeft, w->y, headerRight - headerLeft, tabH + 2, colors->contentBg);
|
||||||
|
|
||||||
int32_t tabX = headerLeft - td->scrollOffset;
|
int32_t tabX = headerLeft - td->scrollOffset;
|
||||||
int32_t tabIdx = 0;
|
int32_t tabIdx = 0;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue