[qwaq] Implement focus handling

Sort of works (when not segfaulting due to problem fixed in next
commit).
This commit is contained in:
Bill Currie 2020-03-24 13:33:28 +09:00
parent 47b8f8dd6a
commit 77651dbcba
8 changed files with 216 additions and 16 deletions

View file

@ -58,14 +58,15 @@ arp_end (void)
r.extent.width /= 2;
r.extent.height /= 2;
Window *w;
[objects insert: w = [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]];
[objects insertSelected: w = [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]];
r = {{1, 1}, {r.extent.width - 2, r.extent.height - 2}};
[w addView: [[Editor alloc] initWithRect: r file: "Makefile"]];
[w insertSelected: [[Editor alloc] initWithRect: r file: "Makefile"]];
return self;
}
-run
{
[objects takeFocus];
[self draw];
do {
arp_start ();

View file

@ -12,6 +12,7 @@
line_count = [buffer countLines: {0, [buffer textSize]}];
linebuffer = [DrawBuffer buffer: { xlen, 1 }];
growMode = gfGrowHi;
options = ofCanFocus;
return self;
}

View file

@ -19,6 +19,8 @@
}
-initWithContext: (id<TextContext>) context owner: (View *) owner;
-insert: (View *) view;
-insertDrawn: (View *) view;
-insertSelected: (View *) view;
-remove: (View *) view;
-(Rect) rect;
-(Point) origin;
@ -27,6 +29,11 @@
-redraw;
-resize: (Extent) delta;
-handleEvent: (qwaq_event_t *) event;
-takeFocus;
-loseFocus;
-selectNext;
-selectPrev;
-selectView: (View *) view;
-(void) grabMouse;
-(void) releaseMouse;
@end

View file

@ -32,16 +32,129 @@
return self;
}
-insertDrawn: (View *) view
{
[self insert: view];
[view draw];
return self;
}
-insertSelected: (View *) view
{
[self insertDrawn: view];
[self selectView: view];
return self;
}
-remove: (View *) view
{
int index = [views indexOfObject: view];
if (index != NotFound) {
if (focused == index) {
focused = -1;
[self selectPrev];
if (focused == index) {
focused = -1;
}
} else if (focused > index) {
focused--;
}
[views removeObjectAtIndex: index];
if (mouse_within == view) {
mouse_within = nil;
}
if (mouse_grabbed == view) {
[self releaseMouse];
}
}
return self;
}
static int
makeFirst (Group *self, int viewIndex)
{
View *view = [self.views objectAtIndex: viewIndex];
[self.views addObject: view];
[self.views removeObjectAtIndex: viewIndex];
return [self.views count] - 1;
}
static int
trySetFocus (Group *self, int viewIndex)
{
View *view = [self.views objectAtIndex:viewIndex];
if (([view state] & (sfDrawn | sfDisabled)) == sfDrawn
&& [view options] & ofCanFocus) {
if (!self.owner || [self.owner state] & sfInFocus) {
if (self.focused >= 0) {
[[self.views objectAtIndex: self.focused] loseFocus];
}
self.focused = viewIndex;
if ([view options] & ofMakeFirst) {
self.focused = makeFirst (self, viewIndex);
}
[view takeFocus];
}
return 1;
}
return 0;
}
-takeFocus
{
if (focused >= 0) {
[[views objectAtIndex:focused] takeFocus];
}
return self;
}
-loseFocus
{
if (focused >= 0) {
[[views objectAtIndex:focused] loseFocus];
}
return self;
}
-selectNext
{
for (int i = focused + 1; i < [views count]; i++) {
if (trySetFocus (self, i)) {
return self;
}
}
// hit end, start again at the beginning
for (int i = 0; i < focused; i++) {
if (trySetFocus (self, i)) {
return self;
}
}
// did not find another view that can be focused
return self;
}
-selectPrev
{
for (int i = focused - 1; i >= 0; i--) {
if (trySetFocus (self, i)) {
return self;
}
}
// hit end, start again at the beginning
for (int i = [views count] - 1; i > focused; i++) {
if (trySetFocus (self, i)) {
return self;
}
}
// did not find another view that can be focused
return self;
}
-selectView:(View *)view
{
int index = [views indexOfObject: view];
if (index != NotFound) {
trySetFocus (self, index);
}
return self;
}

View file

@ -9,6 +9,7 @@
#include "qwaq-textcontext.h"
@class Group;
@class ListenerGroup;
enum {
ofCanFocus = 0x0001,
@ -68,6 +69,8 @@ enum {
int growMode;
int cursorState;
Point cursor;
ListenerGroup *onReceiveFocus;
ListenerGroup *onReleaseFocus;
}
-initWithRect: (Rect) rect;
- (void) dealloc;
@ -84,6 +87,7 @@ enum {
-(void) releaseMouse;
-(int) options;
-(int) state;
-setContext: (id<TextContext>) context;
-draw;
@ -92,11 +96,14 @@ enum {
-resize: (Extent) delta;
-grow: (Extent) delta;
-handleEvent: (qwaq_event_t *) event;
-takeFocus;
-loseFocus;
-(ListenerGroup *) onReceiveFocus;
-(ListenerGroup *) onReleaseFocus;
- (void) onMouseEnter: (Point) pos;
- (void) onMouseLeave: (Point) pos;
- (void) refresh;
- (void) mvprintf: (Point) pos, string fmt, ...;
- (void) mvvprintf: (Point) pos, string fmt, @va_list args;

View file

@ -1,4 +1,5 @@
#include "qwaq-curses.h"
#include "qwaq-listener.h"
#include "qwaq-view.h"
#include "qwaq-group.h"
@ -6,7 +7,12 @@
-init
{
return [super init];
if (!(self = [super init])) {
return nil;
}
onReceiveFocus = [[ListenerGroup alloc] init];
onReleaseFocus = [[ListenerGroup alloc] init];
return self;
}
-initWithRect: (Rect) rect
@ -16,6 +22,8 @@
}
self.rect = rect;
self.absRect = rect;
onReceiveFocus = [[ListenerGroup alloc] init];
onReleaseFocus = [[ListenerGroup alloc] init];
return self;
}
@ -38,6 +46,11 @@
return options;
}
- (int) state
{
return state;
}
static void
updateScreenCursor (View *view)
{
@ -236,9 +249,38 @@ updateScreenCursor (View *view)
-handleEvent: (qwaq_event_t *) event
{
if (event.what & (qe_mousedown | qe_mouseclick)
&& options & ofCanFocus && !(state & (sfDisabled | sfInFocus))) {
[owner selectView: self];
if (!(options & ofFirstClick)) {
event.what = qe_none;
}
}
return self;
}
-takeFocus
{
state |= sfInFocus;
return self;
}
-loseFocus
{
state &= ~sfInFocus;
return self;
}
-(ListenerGroup *) onReceiveFocus
{
return onReceiveFocus;
}
-(ListenerGroup *) onReleaseFocus
{
return onReleaseFocus;
}
- (void) onMouseEnter: (Point) pos
{
}

View file

@ -28,7 +28,9 @@
}
+windowWithRect: (Rect) rect;
-setBackground: (int) ch;
-addView: (View *) view;
-insert: (View *) view;
-insertDrawn: (View *) view;
-insertSelected: (View *) view;
@end
#endif//__qwaq_window_h

View file

@ -28,7 +28,7 @@
objects = [[Group alloc] initWithContext: textContext owner: self];
[self addView: [[TitleBar alloc] initWithTitle:"drag me"]];
[self insert: [[TitleBar alloc] initWithTitle:"drag me"]];
topDrag = [[Button alloc] initWithRect: {{2, 0},
{xlen - 4, 1}}];
@ -46,14 +46,14 @@
{2, 2}}];
bottomDrag = [[Button alloc] initWithRect: {{2, ylen - 1},
{xlen - 4, 1}}];
[self addView: [topDrag setGrowMode: gfGrowHiX]];
[self addView: [topLeftDrag setGrowMode: gfGrowNone]];
[self addView: [topRightDrag setGrowMode: gfGrowX]];
[self addView: [leftDrag setGrowMode: gfGrowHiY]];
[self addView: [rightDrag setGrowMode: gfGrowX | gfGrowHiY]];
[self addView: [bottomLeftDrag setGrowMode: gfGrowY]];
[self addView: [bottomRightDrag setGrowMode: gfGrowAll]];
[self addView: [bottomDrag setGrowMode: gfGrowHiX | gfGrowY]];
[self insert: [topDrag setGrowMode: gfGrowHiX]];
[self insert: [topLeftDrag setGrowMode: gfGrowNone]];
[self insert: [topRightDrag setGrowMode: gfGrowX]];
[self insert: [leftDrag setGrowMode: gfGrowHiY]];
[self insert: [rightDrag setGrowMode: gfGrowX | gfGrowHiY]];
[self insert: [bottomLeftDrag setGrowMode: gfGrowY]];
[self insert: [bottomRightDrag setGrowMode: gfGrowAll]];
[self insert: [bottomDrag setGrowMode: gfGrowHiX | gfGrowY]];
[[topDrag onDrag] addListener: self : @selector(dragWindow:)];
[[topLeftDrag onDrag] addListener: self : @selector(dragWindow:)];
@ -70,6 +70,7 @@
[buf mvaddstr: {0, 2}, "XOX"];
growMode = gfGrowHi;
options = ofCanFocus | ofMakeFirst;
return self;
}
@ -162,12 +163,38 @@
return self;
}
-addView: (View *) view
-takeFocus
{
[super takeFocus];
[objects takeFocus];
return self;
}
-loseFocus
{
[super loseFocus];
[objects loseFocus];
return self;
}
-insert: (View *) view
{
[objects insert: view];
return self;
}
-insertDrawn: (View *) view
{
[objects insertDrawn: view];
return self;
}
-insertSelected: (View *) view
{
[objects insertSelected: view];
return self;
}
-setBackground: (int) ch
{
[(id)textContext bkgd: ch];