Download
jcs
/wallops
/focusable.c
(View History)
jcs *: Cleanup panic messages | Latest amendment: 121 on 2024-09-18 |
1 | /* |
2 | * Copyright (c) 2021-2022 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <string.h> |
18 | |
19 | #include "focusable.h" |
20 | #include "util.h" |
21 | |
22 | struct focusable **focusables = NULL; |
23 | short nfocusables = 0; |
24 | |
25 | struct focusable * |
26 | focusable_find(GrafPtr win) |
27 | { |
28 | short n; |
29 | |
30 | for (n = 0; n < nfocusables; n++) { |
31 | if (focusables[n]->win == win) |
32 | return focusables[n]; |
33 | } |
34 | |
35 | return NULL; |
36 | } |
37 | |
38 | struct focusable * |
39 | focusable_focused(void) |
40 | { |
41 | if (nfocusables && focusables[0]->visible) |
42 | return focusables[0]; |
43 | |
44 | return NULL; |
45 | } |
46 | |
47 | void |
48 | focusable_add(struct focusable *focusable) |
49 | { |
50 | short n, id; |
51 | bool found; |
52 | |
53 | nfocusables++; |
54 | focusables = xreallocarray(focusables, sizeof(struct focusable *), |
55 | nfocusables); |
56 | |
57 | if (nfocusables > 1) |
58 | for (n = nfocusables - 1; n > 0; n--) |
59 | focusables[n] = focusables[n - 1]; |
60 | |
61 | focusables[0] = focusable; |
62 | |
63 | focusable->id = -1; |
64 | for (id = 0; id < nfocusables; id++) { |
65 | found = false; |
66 | for (n = 0; n < nfocusables; n++) { |
67 | if (focusables[n]->id == id) { |
68 | found = true; |
69 | break; |
70 | } |
71 | } |
72 | if (!found) { |
73 | focusable->id = id; |
74 | break; |
75 | } |
76 | } |
77 | if (focusable->id == -1) |
78 | panic("No focusable id"); |
79 | |
80 | focusable_show(focusable); |
81 | } |
82 | |
83 | bool |
84 | focusable_show(struct focusable *focusable) |
85 | { |
86 | struct focusable *last, *tmp; |
87 | short n; |
88 | |
89 | if (nfocusables > 1 && focusables[0] != focusable) { |
90 | last = focusables[0]; |
91 | |
92 | if (last->modal) |
93 | /* other focusables cannot steal focus from modals */ |
94 | return false; |
95 | |
96 | focusables[0] = focusable; |
97 | for (n = 1; n < nfocusables; n++) { |
98 | tmp = focusables[n]; |
99 | focusables[n] = last; |
100 | last = tmp; |
101 | if (last == focusable) |
102 | break; |
103 | } |
104 | } |
105 | |
106 | focusable->visible = true; |
107 | ShowWindow(focusable->win); |
108 | SelectWindow(focusable->win); |
109 | SetPort(focusable->win); |
110 | |
111 | return true; |
112 | } |
113 | |
114 | bool |
115 | focusable_close(struct focusable *focusable) |
116 | { |
117 | short n; |
118 | |
119 | if (focusable->close) { |
120 | if (!focusable->close(focusable)) |
121 | return false; |
122 | } else |
123 | DisposeWindow(focusable->win); |
124 | |
125 | for (n = 0; n < nfocusables; n++) { |
126 | if (focusables[n] == focusable) { |
127 | for (; n < nfocusables - 1; n++) |
128 | focusables[n] = focusables[n + 1]; |
129 | break; |
130 | } |
131 | } |
132 | |
133 | nfocusables--; |
134 | if (nfocusables) |
135 | focusables = xreallocarray(focusables, sizeof(Ptr), nfocusables); |
136 | else |
137 | xfree(&focusables); |
138 | |
139 | if (nfocusables && focusables[0]->visible) |
140 | focusable_show(focusables[0]); |
141 | |
142 | return true; |
143 | } |
144 | |
145 | void |
146 | focusable_hide(struct focusable *focusable) |
147 | { |
148 | short n; |
149 | |
150 | HideWindow(focusable->win); |
151 | focusable->visible = false; |
152 | |
153 | for (n = 0; n < nfocusables; n++) { |
154 | if (focusables[n] == focusable) { |
155 | for (; n < nfocusables - 1; n++) |
156 | focusables[n] = focusables[n + 1]; |
157 | break; |
158 | } |
159 | } |
160 | focusables[nfocusables - 1] = focusable; |
161 | } |
162 | |
163 | bool |
164 | focusables_quit(void) |
165 | { |
166 | short tnfocusables = nfocusables; |
167 | short n; |
168 | struct focusable **tfocusables; |
169 | bool quit = true; |
170 | |
171 | if (nfocusables) { |
172 | /* |
173 | * nfocusables and focusables array will probably be |
174 | * modified as each focusable quits |
175 | */ |
176 | tfocusables = xcalloc(sizeof(Ptr), tnfocusables); |
177 | memcpy(tfocusables, focusables, sizeof(Ptr) * tnfocusables); |
178 | |
179 | for (n = 0; n < tnfocusables; n++) { |
180 | if (tfocusables[n] && tfocusables[n]->quit && |
181 | !tfocusables[n]->quit(tfocusables[n])) { |
182 | quit = false; |
183 | break; |
184 | } |
185 | } |
186 | |
187 | xfree(&tfocusables); |
188 | } |
189 | |
190 | return quit; |
191 | } |