Design Pattern Examples
Overview of object-oriented design patterns
HandlerChain_MessageWindow.c
Go to the documentation of this file.
1
8
9
10#include <stdlib.h>
11#include <stdio.h>
12
13#include "helpers/formatstring.h"
14
18
19
20const int CLOSE_WIDTH = 2;
21const int CLOSE_HEIGHT = 2;
22
30struct _Window
31{
32 // Note: We must specify struct _Window so we can add pointer references for
33 // next and prev in the structure. These cannot be specified with the
34 // typedef alias of MessageWindow.
35
39 struct _Window* prev;
40
44 struct _Window* next;
45
50
54 const char* _title;
55
60
67
73};
74
82typedef struct _Window MessageWindow;
83
84
89
93static int _nextWindowId = 1;
94
101{
102 if (_windowList == NULL)
103 {
104 _windowList = window;
105 }
106 else
107 {
108 MessageWindow* nextWindow = _windowList;
109 while (nextWindow->next != NULL)
110 {
111 nextWindow = nextWindow->next;
112 }
113 nextWindow->next = window;
114 window->prev = nextWindow;
115 }
116}
117
124{
125 if (window != NULL)
126 {
127 if (window->prev != NULL)
128 {
129 window->prev->next = window->next;
130
131 }
132 else
133 {
134 _windowList = window->next;
135 }
136
137 if (window->next != NULL)
138 {
139 window->next->prev = window->prev;
140 }
141
142 window->next = NULL;
143 window->prev = NULL;
144 }
145}
146
153static MessageWindow* _FindWindow(int windowId)
154{
155 MessageWindow* foundWindow = NULL;
156
157 if (_windowList != NULL)
158 {
159 MessageWindow* window = _windowList;
160 while (window != NULL)
161 {
162 if (window->_windowId == windowId)
163 {
164 foundWindow = window;
165 break;
166 }
167 window = window->next;
168 }
169 }
170 return foundWindow;
171}
172
173//-----------------------------------------------------------------------------
174//-----------------------------------------------------------------------------
175
183static bool _HandleButtonDownMessage(MessageWindow* window, Message* message)
184{
185 // Note: we are not saying we handled the message here since
186 // we want other windows to get the button down message as
187 // well so they can select or deselect themselves.
188 bool messageProcessed = false;
189
190 if (window != NULL && message != NULL)
191 {
192 if (WindowRectangle_PointInside(&window->_windowBox, &message->Position))
193 {
194 if (!window->_selected)
195 {
196 window->_selected = true;
197 printf(" --> Button Down in \"%s\", window selected\n", window->_title);
198 }
199 }
200 else
201 {
202 if (window->_selected)
203 {
204 window->_selected = false;
205 printf(" --> Button Down not in \"%s\", window deselected\n", window->_title);
206 }
207 }
208 }
209
210 return messageProcessed;
211}
212
213
221static bool _HandleButtonUpMessage(MessageWindow* window, Message* message)
222{
223 bool messageProcessed = false;
224
225 if (window != NULL && message != NULL)
226 {
227 if (window->_selected)
228 {
229 if (WindowRectangle_PointInside(&window->_windowBox, &message->Position))
230 {
231 // The Button Up is in the same window as Button Down so
232 // we will handle this message and let no other window see
233 // it.
234 messageProcessed = true;
235 if (WindowRectangle_PointInside(&window->_closeBox, &message->Position))
236 {
237 printf(" --> Button Up in \"%s\" close box, sending Close message\n", window->_title);
238 Message closeMessage;
239 Message_Initialize(&closeMessage, Close, message->Position.X, message->Position.Y);
240 HandlerChain_SendMessage(window->_windowId, &closeMessage);
241 }
242 else
243 {
244 printf(" --> Button Up in \"%s\", no further action taken\n", window->_title);
245 }
246 }
247 }
248 }
249
250 return messageProcessed;
251}
252
253
261static bool _HandleCloseMessage(MessageWindow* window, Message* message)
262{
263 bool messageProcessed = false;
264
265 if (window != NULL && message != NULL)
266 {
267 if (window->_selected)
268 {
269 printf(" --> Close in \"%s\", sending Destroy message\n", window->_title);
270
271 // This window is being closed. We are handling the message
272 // so no other window needs to see it.
273 messageProcessed = true;
274 Message destroyMessage;
275 Message_Initialize(&destroyMessage, Destroy, 0, 0);
276 HandlerChain_SendMessage(window->_windowId, &destroyMessage);
277 }
278 else
279 {
280 printf(" --> Close seen in \"%s\" but this window is not selected, ignoring\n", window->_title);
281 }
282
283 }
284
285 return messageProcessed;
286}
287
299static bool _HandleDestroyMessage(MessageWindow* window, Message* message)
300{
301 bool messageProcessed = false;
302
303 if (window != NULL && message != NULL)
304 {
305 printf(" --> Destroy in \"%s\", removing window from handler chain and destroying window\n", window->_title);
307 window->_selected = false;
309 messageProcessed = true;
310 }
311
312 return messageProcessed;
313}
314
316// MessageWindow_Create()
318int MessageWindow_Create(const char* title, int x, int y, int w, int h)
319{
320 int windowId = -1;
321
322 if (title != NULL)
323 {
324 MessageWindow* window = calloc(1, sizeof(MessageWindow));
325 if (window != NULL)
326 {
327 windowId = _nextWindowId++;
328 window->_windowId = windowId;
329 bool success = HandlerChain_AddWindow(window->_windowId);
330 if (success)
331 {
332 window->_title = title;
333 WindowRectangle_Initialize(&window->_windowBox, x, y, w, h);
335 _AppendWindowToList(window);
336 }
337 else
338 {
339 printf(" Error! Out of memory condition adding a window to the handler chain in MessageWindow_Create()!\n");
340 free(window);
341 window = NULL;
342 windowId = -1;
343 }
344 }
345 }
346
347 return windowId;
348}
349
350
352// MessageWindow_Destroy()
354void MessageWindow_Destroy(int windowId)
355{
356 MessageWindow* window = _FindWindow(windowId);
357 if (window != NULL)
358 {
359 _RemoveWindowFromList(window);
360 free(window);
361 }
362}
363
365// MessageWindow_ProcessMessage()
367bool MessageWindow_ProcessMessage(int windowId, Message* message)
368{
369 bool processed = false;
370
371 if (message != NULL)
372 {
373 MessageWindow* window = _FindWindow(windowId);
374 if (window != NULL)
375 {
376 switch (message->MessageType)
377 {
378 case Close:
379 processed = _HandleCloseMessage(window, message);
380 break;
381
382 case ButtonDown:
383 processed = _HandleButtonDownMessage(window, message);
384 break;
385
386 case ButtonUp:
387 processed = _HandleButtonUpMessage(window, message);
388 break;
389
390 case Destroy:
391 processed = _HandleDestroyMessage(window, message);
392 break;
393
394 default:
395 printf("Error! Cannot process unrecognized message type: %d!\n", message->MessageType);
396 processed = true;
397 break;
398 }
399 }
400 }
401
402 return processed;
403}
404
405
407// MessageWindow_ProcessMessage()
409bool MessageWindow_ToString(int windowId, DynamicString* output)
410{
411 bool success = false;
412
413 if (output != NULL)
414 {
415 MessageWindow* window = _FindWindow(windowId);
416 if (window != NULL)
417 {
418 DynamicString boxOutput = { 0 };
419 success = WindowRectangle_ToString(&window->_windowBox, &boxOutput);
420 if (success)
421 {
422 char* buffer = formatstring("[id=%2d] \"%s\" (%s), selected=%s",
423 window->_windowId, window->_title, boxOutput.string,
424 (window->_selected) ? "true" : "false");
425 if (buffer != NULL)
426 {
427 success = DynamicString_Append(output, buffer);
428 if (!success)
429 {
430 printf(" Error! Out of memory condition formatting a MessageWindow as a string!\n");
431 }
432 free(buffer);
433 }
434 else
435 {
436 printf(" Error! Out of memory formatting message window in MessageWindow_ToString()!\n");
437 }
438 }
439 DynamicString_Clear(&boxOutput);
440 }
441 }
442
443 return success;
444}
bool HandlerChain_AddWindow(int windowId)
Add an instance of a MessageWindow to end of the list of windows, protected by a multi-threading lock...
void HandlerChain_RemoveWindow(int windowId)
Remove an instance of a MessageWindow from the list, protected by a multi-threading lock.
void HandlerChain_SendMessage(int windowId, Message *message)
Send a message to each of the handlers in the list, protected by a multi-threading lock.
Declaration of the Handler Chain functions, HandlerChain_SendMessage(), HandlerChain_AddWindow(),...
void Message_Initialize(Message *message, MessageType type, int x, int y)
Initialize a Message structure.
@ ButtonUp
Take an action on the currently selected window.
@ ButtonDown
Selects a window based on position.
@ Destroy
Window is being told to destroy itself. This is sent in response to seeing the Close message.
@ Close
Window is asked to close itself, generally sent by the window itself in response to a button up in a ...
const int CLOSE_HEIGHT
Height of the close region in the window.
static int _nextWindowId
The next ID to use for a new window.
static MessageWindow * _FindWindow(int windowId)
Helper function to find a MessageWindow given the window's ID.
static bool _HandleButtonUpMessage(MessageWindow *window, Message *message)
Helper function to handle the ButtonUp message.
bool MessageWindow_ProcessMessage(int windowId, Message *message)
Pass a Message object to a window for processing.
int MessageWindow_Create(const char *title, int x, int y, int w, int h)
Create a MessageWindow object with the given properties and return the ID of the object.
static void _RemoveWindowFromList(MessageWindow *window)
Helper function to remove the given MessageWindow object from the linked list of MessageWindow object...
static bool _HandleButtonDownMessage(MessageWindow *window, Message *message)
Helper function to handle the ButtonDown message.
const int CLOSE_WIDTH
Width of the close region in the window.
void MessageWindow_Destroy(int windowId)
Destroy the MessageWindow object with the given ID. Removes the window from any message handling as w...
static void _AppendWindowToList(MessageWindow *window)
Helper function to append the given MessageWindow to the list of MessageWindow objects.
static bool _HandleCloseMessage(MessageWindow *window, Message *message)
Helper function to handle the Close message.
bool MessageWindow_ToString(int windowId, DynamicString *output)
Convert the specified window to a string representation.
static MessageWindow * _windowList
List of all created MessageWindow objects, in a double-linked list.
static bool _HandleDestroyMessage(MessageWindow *window, Message *message)
Helper function to trigger the destruction of the window. The window is destroyed and can no longer r...
Declaration of the MessageWindow support functions, MessageWindow_Create(), MessageWindow_Destroy(),...
bool WindowRectangle_ToString(WindowRectangle *rectangle, DynamicString *output)
Convert the given WindowRectangle to a string representation.
void WindowRectangle_Initialize(WindowRectangle *rectangle, int x, int y, int width, int height)
Initialize the specified WindowRectangle based on the given position and size in some arbitrary space...
bool WindowRectangle_PointInside(WindowRectangle *rectangle, MessagePosition *point)
Determine if the given WindowRectangle object contains the given MessagePosition.
Declaration of the WindowRectangle structure and its support functions, WindowRectangle_Initialize(),...
void DynamicString_Clear(DynamicString *string)
Clear a DynamicString object, releasing any allocated memory. Resets to an empty string.
Definition: dynamicstring.c:27
bool DynamicString_Append(DynamicString *string, const char *s)
Append the specified string to the DynamicString object.
Definition: dynamicstring.c:39
char * formatstring(const char *format,...)
Use the given string and arguments to return a buffer containing the formatted string....
Definition: formatstring.c:15
Represents a window in an arbitrary space. It has an ID, title, and position. A close box is within t...
WindowRectangle _closeBox
Position of the close window within the window box, although the coordinates are also global coordina...
struct _Window * prev
Previous window in a linked list. NULL if this window is the head of the list.
bool _selected
Whether this window has been selected (a button click occurred within the window).
int _windowId
Unique ID of this window.
WindowRectangle _windowBox
Position of this window in global coordinates.
struct _Window * next
Next window in a linked list. NULL if this windows is the last in the list.
const char * _title
Title/Name of this window.
Represents a string that can be grown dynamically.
Definition: dynamicstring.h:16
char * string
The string that can grow.
Definition: dynamicstring.h:17
Represents a message sent to the windows. A message contains a type and a position.
MessagePosition Position
Position of message when the message was sent. In a real system, this would generally represent the p...
MessageType MessageType
Value from the MessageType enumeration indicating the type of this message.
Represents a rectangular region, with upper left and lower right coordinates.