this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

vxfw: simplify focus management

+22 -196
+22 -196
src/vxfw/App.zig
··· 86 86 var mouse_handler = MouseHandler.init(widget); 87 87 defer mouse_handler.deinit(self.allocator); 88 88 var focus_handler = FocusHandler.init(self.allocator, widget); 89 - focus_handler.intrusiveInit(); 90 89 try focus_handler.path_to_focused.append(widget); 91 90 defer focus_handler.deinit(); 92 91 ··· 484 483 /// Maintains a tree of focusable nodes. Delivers events to the currently focused node, walking up 485 484 /// the tree until the event is handled 486 485 const FocusHandler = struct { 487 - arena: std.heap.ArenaAllocator, 488 - 489 - root: Node, 490 - focused: *Node, 486 + root: Widget, 491 487 focused_widget: vxfw.Widget, 492 488 path_to_focused: std.ArrayList(Widget), 493 489 494 - const Node = struct { 495 - widget: Widget, 496 - parent: ?*Node, 497 - children: []*Node, 498 - 499 - fn nextSibling(self: Node) ?*Node { 500 - const parent = self.parent orelse return null; 501 - const idx = for (0..parent.children.len) |i| { 502 - const node = parent.children[i]; 503 - if (self.widget.eql(node.widget)) 504 - break i; 505 - } else unreachable; 506 - 507 - // Return null if last child 508 - if (idx == parent.children.len - 1) 509 - return null 510 - else 511 - return parent.children[idx + 1]; 512 - } 513 - 514 - fn prevSibling(self: Node) ?*Node { 515 - const parent = self.parent orelse return null; 516 - const idx = for (0..parent.children.len) |i| { 517 - const node = parent.children[i]; 518 - if (self.widget.eql(node.widget)) 519 - break i; 520 - } else unreachable; 521 - 522 - // Return null if first child 523 - if (idx == 0) 524 - return null 525 - else 526 - return parent.children[idx - 1]; 527 - } 528 - 529 - fn lastChild(self: Node) ?*Node { 530 - if (self.children.len > 0) 531 - return self.children[self.children.len - 1] 532 - else 533 - return null; 534 - } 535 - 536 - fn firstChild(self: Node) ?*Node { 537 - if (self.children.len > 0) 538 - return self.children[0] 539 - else 540 - return null; 541 - } 542 - 543 - /// returns the next logical node in the tree 544 - fn nextNode(self: *Node) *Node { 545 - // If we have a sibling, we return it's first descendant line 546 - if (self.nextSibling()) |sibling| { 547 - var node = sibling; 548 - while (node.firstChild()) |child| { 549 - node = child; 550 - } 551 - return node; 552 - } 553 - 554 - // If we don't have a sibling, we return our parent 555 - if (self.parent) |parent| return parent; 556 - 557 - // If we don't have a parent, we are the root and we return or first descendant 558 - var node = self; 559 - while (node.firstChild()) |child| { 560 - node = child; 561 - } 562 - return node; 563 - } 564 - 565 - fn prevNode(self: *Node) *Node { 566 - // If we have children, we return the last child descendant 567 - if (self.children.len > 0) { 568 - var node = self; 569 - while (node.lastChild()) |child| { 570 - node = child; 571 - } 572 - return node; 573 - } 574 - 575 - // If we have siblings, we return the last descendant line of the sibling 576 - if (self.prevSibling()) |sibling| { 577 - var node = sibling; 578 - while (node.lastChild()) |child| { 579 - node = child; 580 - } 581 - return node; 582 - } 583 - 584 - // If we don't have a sibling, we return our parent 585 - if (self.parent) |parent| return parent; 586 - 587 - // If we don't have a parent, we are the root and we return our last descendant 588 - var node = self; 589 - while (node.lastChild()) |child| { 590 - node = child; 591 - } 592 - return node; 593 - } 594 - }; 595 - 596 490 fn init(allocator: Allocator, root: Widget) FocusHandler { 597 - const node: Node = .{ 598 - .widget = root, 599 - .parent = null, 600 - .children = &.{}, 601 - }; 602 491 return .{ 603 - .root = node, 604 - .focused = undefined, 492 + .root = root, 605 493 .focused_widget = root, 606 - .arena = std.heap.ArenaAllocator.init(allocator), 607 494 .path_to_focused = std.ArrayList(Widget).init(allocator), 608 495 }; 609 496 } 610 497 611 - fn intrusiveInit(self: *FocusHandler) void { 612 - self.focused = &self.root; 613 - } 614 - 615 498 fn deinit(self: *FocusHandler) void { 616 499 self.path_to_focused.deinit(); 617 - self.arena.deinit(); 618 500 } 619 501 620 502 /// Update the focus list 621 - fn update(self: *FocusHandler, root: vxfw.Surface) Allocator.Error!void { 622 - _ = self.arena.reset(.free_all); 503 + fn update(self: *FocusHandler, surface: vxfw.Surface) Allocator.Error!void { 504 + // clear path 505 + self.path_to_focused.clearAndFree(); 623 506 624 - var list = std.ArrayList(*Node).init(self.arena.allocator()); 625 - for (root.children) |child| { 626 - try self.findFocusableChildren(&self.root, &list, child.surface); 627 - } 628 - 629 - // Update children 630 - self.root.children = list.items; 507 + // Find the path to the focused widget. This builds a list that has the first element as the 508 + // focused widget, and walks backward to the root. It's possible our focused widget is *not* 509 + // in this tree. If this is the case, we refocus to the root widget 510 + const has_focus = try self.childHasFocus(surface); 631 511 632 - // Update path 633 - self.path_to_focused.clearAndFree(); 634 - if (!self.root.widget.eql(root.widget)) { 635 - // Always make sure the root widget (the one we started with) is the first item, even if 636 - // it isn't focusable or in the path 637 - try self.path_to_focused.append(self.root.widget); 512 + // We assert that the focused widget *must* be in the widget tree. There is certianly a 513 + // logic bug in the code somewhere if this is not the case 514 + assert(has_focus); 515 + if (!self.root.eql(surface.widget)) { 516 + // If the root of surface is not the initial widget, we append the initial widget 517 + try self.path_to_focused.append(self.root); 638 518 } 639 - _ = try childHasFocus(root, &self.path_to_focused, self.focused.widget); 640 519 641 520 // reverse path_to_focused so that it is root first 642 521 std.mem.reverse(Widget, self.path_to_focused.items); ··· 644 523 645 524 /// Returns true if a child of surface is the focused widget 646 525 fn childHasFocus( 526 + self: *FocusHandler, 647 527 surface: vxfw.Surface, 648 - list: *std.ArrayList(Widget), 649 - focused: Widget, 650 528 ) Allocator.Error!bool { 651 529 // Check if we are the focused widget 652 - if (focused.eql(surface.widget)) { 653 - try list.append(surface.widget); 530 + if (self.focused_widget.eql(surface.widget)) { 531 + try self.path_to_focused.append(surface.widget); 654 532 return true; 655 533 } 656 534 for (surface.children) |child| { 657 535 // Add child to list if it is the focused widget or one of it's own children is 658 - if (try childHasFocus(child.surface, list, focused)) { 659 - try list.append(surface.widget); 536 + if (try self.childHasFocus(child.surface)) { 537 + try self.path_to_focused.append(surface.widget); 660 538 return true; 661 539 } 662 540 } 663 541 return false; 664 542 } 665 543 666 - /// Walks the surface tree, adding all focusable nodes to list 667 - fn findFocusableChildren( 668 - self: *FocusHandler, 669 - parent: *Node, 670 - list: *std.ArrayList(*Node), 671 - surface: vxfw.Surface, 672 - ) Allocator.Error!void { 673 - if (self.root.widget.eql(surface.widget)) { 674 - // Never add the root_widget. We will always have this as the root 675 - for (surface.children) |child| { 676 - try self.findFocusableChildren(parent, list, child.surface); 677 - } 678 - } else if (surface.focusable) { 679 - // We are a focusable child of parent. Create a new node, and find our own focusable 680 - // children 681 - const node = try self.arena.allocator().create(Node); 682 - var child_list = std.ArrayList(*Node).init(self.arena.allocator()); 683 - for (surface.children) |child| { 684 - try self.findFocusableChildren(node, &child_list, child.surface); 685 - } 686 - node.* = .{ 687 - .widget = surface.widget, 688 - .parent = parent, 689 - .children = child_list.items, 690 - }; 691 - if (self.focused_widget.eql(surface.widget)) { 692 - self.focused = node; 693 - } 694 - try list.append(node); 695 - } else { 696 - for (surface.children) |child| { 697 - try self.findFocusableChildren(parent, list, child.surface); 698 - } 699 - } 700 - } 701 - 702 544 fn focusWidget(self: *FocusHandler, ctx: *vxfw.EventContext, widget: vxfw.Widget) anyerror!void { 545 + // Focusing a widget requires it to have an event handler 546 + assert(widget.eventHandler != null); 703 547 if (self.focused_widget.eql(widget)) return; 704 548 705 549 ctx.phase = .at_target; 706 550 try self.focused_widget.handleEvent(ctx, .focus_out); 707 551 self.focused_widget = widget; 708 552 try self.focused_widget.handleEvent(ctx, .focus_in); 709 - } 710 - 711 - fn focusNode(self: *FocusHandler, ctx: *vxfw.EventContext, node: *Node) anyerror!void { 712 - if (self.focused.widget.eql(node.widget)) return; 713 - 714 - try self.focused.widget.handleEvent(ctx, .focus_out); 715 - self.focused = node; 716 - try self.focused.widget.handleEvent(ctx, .focus_in); 717 - } 718 - 719 - /// Focuses the next focusable widget 720 - fn focusNext(self: *FocusHandler, ctx: *vxfw.EventContext) anyerror!void { 721 - return self.focusNode(ctx, self.focused.nextNode()); 722 - } 723 - 724 - /// Focuses the previous focusable widget 725 - fn focusPrev(self: *FocusHandler, ctx: *vxfw.EventContext) anyerror!void { 726 - return self.focusNode(ctx, self.focused.prevNode()); 727 553 } 728 554 729 555 fn handleEvent(self: *FocusHandler, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {