Usermode/Build - Updates to build system for crtbegin/crtend
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderer_widget.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  *
5  * render_widget.c
6  * - AxWin2 Widget port
7  */
8 #include <common.h>
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
11 #include <string.h>
12 #include <wm_messages.h>
13 #include <stdlib.h>
14 #include "include/image.h"
15
16 #define DEFAULT_ELETABLE_SIZE   64
17
18 // === PROTOTYPES ===
19  int    Renderer_Widget_Init(void);
20 tWindow *Renderer_Widget_Create(int Flags);
21 void    Renderer_Widget_Redraw(tWindow *Window);
22
23 void    Widget_RenderWidget(tWindow *Window, tElement *Element);
24 void    Widget_UpdateDimensions(tElement *Element);
25 void    Widget_UpdatePosition(tElement *Element);
26 // --- Messages
27 tElement        *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
28 void    Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg);
29 void    Widget_SetFlags(tWidgetWin *Info, int Len, tWidgetMsg_SetFlags *Msg);
30 void    Widget_SetSize(tWidgetWin *Info, int Len, tWidgetMsg_SetSize *Msg);
31 void    Widget_SetText(tWidgetWin *Info, int Len, tWidgetMsg_SetText *Msg);
32  int    Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
33 // --- Type helpers
34 void    Widget_DispText_UpdateText(tElement *Element, const char *Text);
35 void    Widget_Image_UpdateText(tElement *Element, const char *Text);
36  int    Widget_Button_MouseButton(tElement *Element, int X, int Y, int Button, int bPress);
37 void    Widget_TextInput_Init(tElement *Element);
38
39 // === GLOBALS ===
40 tWMRenderer     gRenderer_Widget = {
41         .Name = "Widget",
42         .CreateWindow = Renderer_Widget_Create,
43         .Redraw = Renderer_Widget_Redraw,
44         .HandleMessage = Renderer_Widget_HandleMessage
45 };
46         
47 // --- Element callbacks
48 struct {
49         void    (*Init)(tElement *Ele);
50         void    (*Delete)(tElement *Ele);
51         
52         void    (*UpdateFlags)(tElement *Ele);
53         void    (*UpdateSize)(tElement *Ele);
54         void    (*UpdateText)(tElement *Ele, const char *Text); // This should update Ele->Text
55
56         /**
57          * \name Input handlers
58          * \note Returns boolean unhandled
59          * \{
60          */     
61          int    (*MouseButton)(tElement *Ele, int X, int Y, int Button, int bPressed);
62          int    (*MouseMove)(tElement *Ele, int X, int Y);
63          int    (*KeyDown)(tElement *Ele, int KeySym, int Character);
64          int    (*KeyUp)(tElement *Ele, int KeySym);
65          int    (*KeyFire)(tElement *Ele, int KeySym, int Character);
66         /**
67          * \}
68          */
69 }       gaWM_WidgetTypes[NUM_ELETYPES] = {
70         {0},    // NULL
71         {0},    // Box
72         {.UpdateText = Widget_DispText_UpdateText},     // Text
73         {.UpdateText = Widget_Image_UpdateText},        // Image
74         {.MouseButton = Widget_Button_MouseButton},     // Button
75         {0},    // Spacer
76         {.Init = Widget_TextInput_Init},        // Text Box (Single Line)
77 };
78 const int       ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
79
80 // === CODE ===
81 int Renderer_Widget_Init(void)
82 {
83         WM_RegisterRenderer(&gRenderer_Widget); 
84
85         return 0;
86 }
87
88 tWindow *Renderer_Widget_Create(int Flags)
89 {
90         tWindow *ret;
91         tWidgetWin      *info;
92          int    eletable_size = DEFAULT_ELETABLE_SIZE;
93
94         _SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
95
96         // TODO: Use `Flags` as default element count?
97         // - Actaully, it's taken by the root ele flags
98         // - Use the upper bits?
99
100         ret = WM_CreateWindowStruct( sizeof(tWidgetWin) + sizeof(tElement*)*eletable_size );
101         info = ret->RendererInfo;
102         
103         info->TableSize = eletable_size;
104         info->RootElement.Window = ret;
105         info->RootElement.ID = -1;
106         info->RootElement.BackgroundColour = 0xCCCCCC;
107         info->RootElement.Flags = Flags;
108         
109         return ret;
110 }
111
112 void Renderer_Widget_Redraw(tWindow *Window)
113 {
114         tWidgetWin      *info = Window->RendererInfo;
115         WM_Render_FillRect(Window, 0, 0, 0xFFF, 0xFFF, info->RootElement.BackgroundColour);
116
117         Widget_UpdateDimensions(&info->RootElement);
118         Widget_UpdatePosition(&info->RootElement);
119
120         Widget_RenderWidget(Window, &info->RootElement);
121 }
122
123 // --- Render / Resize ---
124 void Widget_RenderWidget(tWindow *Window, tElement *Element)
125 {
126         tElement        *child;
127         
128         if( Element->Flags & ELEFLAG_NORENDER ) return ;
129         if( Element->Flags & ELEFLAG_INVISIBLE )        return ;
130         
131         Widget_Decorator_RenderWidget(Window, Element);
132         
133         for(child = Element->FirstChild; child; child = child->NextSibling)
134         {
135                 Widget_RenderWidget(Window, child);
136         }
137 }
138
139 void Widget_UpdateDimensions(tElement *Element)
140 {
141         tElement        *child;
142          int    nChildren = 0;
143          int    nFixed = 0;
144          int    maxCross = 0;
145          int    fixedSize = 0;
146          int    fullCross, dynWith;
147         
148         // Pass 1
149         // - Get the fixed and minimum sizes of the element
150         for( child = Element->FirstChild; child; child = child->NextSibling )
151         {
152                 // Ignore elements that will not be rendered
153                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
154                 
155                 // Absolutely positioned elements don't affect dimensions
156                 if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue ;
157         
158                 // Fixed width elements 
159                 if( child->FixedWith )
160                 {
161                         nFixed ++;
162                         fixedSize += child->FixedWith;
163                 }
164                 else if( child->Flags & ELEFLAG_NOSTRETCH )
165                 {
166                         nFixed ++;
167                         fixedSize += child->MinWith;
168                 }
169                 
170                 if( child->FixedCross && maxCross < child->FixedCross )
171                         maxCross = child->FixedCross;
172                 if( child->MinCross && maxCross < child->MinCross )
173                         maxCross = child->MinCross;
174                 nChildren ++;
175         }
176
177         // Get the dynamic with size from the unused space in the element
178         if( nChildren > nFixed ) {
179                 if( Element->Flags & ELEFLAG_VERTICAL )
180                         dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
181                 else
182                         dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
183                 dynWith -= fixedSize;
184                 if( dynWith < 0 )       return ;
185                 dynWith /= nChildren - nFixed;
186         }
187         
188 //      _SysDebug("%i - nChildren = %i, nFixed = %i, dynWith = %i, fixedSize = %i",
189 //              Element->ID, nChildren, nFixed, dynWith, fixedSize);
190
191         // Get the cross size
192         if( Element->Flags & ELEFLAG_VERTICAL )
193                 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
194         else
195                 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
196         
197         // Pass 2 - Set sizes and recurse
198         for( child = Element->FirstChild; child; child = child->NextSibling )
199         {
200                  int    cross, with;
201
202                 // Ignore elements that will not be rendered
203                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
204                 
205                 // --- Cross Size ---
206                 // TODO: Expand to fill?
207                 // TODO: Extra flag so options are (Expand, Equal, Wrap)
208                 if( child->FixedCross )
209                         cross = child->FixedCross;
210                 else if( child->Flags & ELEFLAG_NOEXPAND )
211                         cross = child->MinCross;
212                 else
213                         cross = fullCross;
214                 
215                 // --- With Size ---
216                 if( child->FixedWith )
217                         with = child->FixedWith;
218                 else if( child->Flags & ELEFLAG_NOSTRETCH )
219                         with = child->MinWith;
220                 else
221                         with = dynWith;
222         
223
224                 if(with < child->MinWith)       with = child->MinWith;
225                 if(cross < child->MinCross)     cross = child->MinCross;
226                 
227                 // Update the dimensions if they have changed
228                 if( Element->Flags & ELEFLAG_VERTICAL ) {
229                         // If no change, don't recurse
230                         if( child->CachedW == cross && child->CachedH == with )
231                                 continue ;
232                         child->CachedW = cross;
233                         child->CachedH = with;
234                 }
235                 else {
236                         // If no change, don't recurse
237                         if( child->CachedW == with && child->CachedH == cross )
238                                 continue ;
239                         child->CachedW = with;
240                         child->CachedH = cross;
241                 }
242                 
243                 // Force the positions of child elements to be recalculated
244                 child->CachedX = -1;
245         
246                 // Recurse down so the child elements can be updated    
247                 Widget_UpdateDimensions(child);
248         }
249         
250 }
251
252 /**
253  * \brief Update the position of child elements
254  */
255 void Widget_UpdatePosition(tElement *Element)
256 {
257         tElement        *child;
258          int    x, y;
259         
260         if( Element->Flags & ELEFLAG_NORENDER ) return ;
261
262 //      _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))",
263 //              Element, Element->ID, Element->Type, Element->Flags);
264         
265         // Initialise
266         x = Element->CachedX + Element->PaddingL;
267         y = Element->CachedY + Element->PaddingT;
268         
269         // Update each child
270         for(child = Element->FirstChild; child; child = child->NextSibling)
271         {
272                  int    newX, newY;
273                 // Ignore elements that will not be rendered
274                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
275
276                 newX = x; newY = y;
277                 
278                 // Handle alignment
279                 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
280                         if(Element->Flags & ELEFLAG_VERTICAL)
281                                 newX += Element->CachedW/2 - child->CachedW/2;
282                         else
283                                 newY += Element->CachedH/2 - child->CachedH/2;
284                 }
285                 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
286                         if(Element->Flags & ELEFLAG_VERTICAL )
287                                 newX += Element->CachedW - child->CachedW
288                                         - Element->PaddingL - Element->PaddingR;
289                         else
290                                 newY += Element->CachedH - child->CachedH
291                                         - Element->PaddingT - Element->PaddingB;
292                 }
293
294 //              _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY);
295
296                 // Check for changes, and don't update if there was no change
297                 if( newX != child->CachedX || newY != child->CachedY )
298                 {
299                         child->CachedX = newX;
300                         child->CachedY = newY;
301                         // Update child's children positions
302                         Widget_UpdatePosition(child);
303                 }
304                 
305                 // Increment
306                 if(Element->Flags & ELEFLAG_VERTICAL ) {
307                         y += child->CachedH + Element->GapSize;
308                 }
309                 else {
310                         x += child->CachedW + Element->GapSize;
311                 }
312         }
313 }
314
315 /**
316  * \brief Update the minimum dimensions of the element
317  * \note Called after a child's minimum dimensions have changed
318  */
319 void Widget_UpdateMinDims(tElement *Element)
320 {
321         tElement        *child;
322         
323         if(!Element)    return;
324         
325         Element->MinCross = 0;
326         Element->MinWith = 0;
327         
328         for(child = Element->FirstChild; child; child = child->NextSibling)
329         {
330                 if( Element->Parent &&
331                         (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL)
332                         )
333                 {
334                         if(child->FixedCross)
335                                 Element->MinCross += child->FixedCross;
336                         else
337                                 Element->MinCross += child->MinCross;
338                         if(child->FixedWith)
339                                 Element->MinWith += child->FixedWith;
340                         else
341                                 Element->MinWith += child->MinWith;
342                 }
343                 else
344                 {
345                         if(child->FixedCross)
346                                 Element->MinWith += child->FixedCross;
347                         else
348                                 Element->MinWith += child->MinCross;
349                         if(child->FixedWith)
350                                 Element->MinCross += child->FixedWith;
351                         else
352                                 Element->MinCross += child->MinWith;
353                 }
354         }
355         
356         // Recurse upwards
357         Widget_UpdateMinDims(Element->Parent);
358 }
359
360 tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
361 {
362         tElement        *ret, *next, *ele;
363         
364         next = &Info->RootElement;
365         while(next)
366         {
367                 ret = next;
368                 next = NULL;
369                 for(ele = ret->FirstChild; ele; ele = ele->NextSibling)
370                 {
371                         if(ele->Flags & ELEFLAG_NORENDER)       continue;
372                         if(X < ele->CachedX)    continue;
373                         if(Y < ele->CachedY)    continue;
374                         if(X >= ele->CachedX + ele->CachedW)    continue;
375                         if(Y >= ele->CachedY + ele->CachedH)    continue;
376                         next = ele;
377                 }
378         }
379         return ret;
380 }
381
382 // --- Helpers ---
383 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
384 {
385         tElement        *ele;
386
387         if( ID == -1 )  return &Info->RootElement;
388         
389         if( ID < Info->TableSize )      return Info->ElementTable[ID];
390
391         ele = Info->ElementTable[ID % Info->TableSize];
392         while(ele && ele->ID != ID)     ele = ele->ListNext;
393         return ele;
394 }
395
396 // --- Message Handlers ---
397 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
398 {
399         const int       max_debugname_len = Len - sizeof(tWidgetMsg_Create);
400         tElement        *parent, *new;
401
402         // Sanity check
403         if( Len < sizeof(tWidgetMsg_Create) )
404                 return ;
405         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
406                 return ;
407         
408         _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)",
409                 Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags);
410         
411         // Create
412         parent = Widget_GetElementById(Info, Msg->Parent);
413         if(!parent)
414         {
415                 _SysDebug("Widget_NewWidget - Bad parent ID %i", Msg->Parent);
416                 return ;
417         }
418
419         // Check if the ID is already in use
420         if( Widget_GetElementById(Info, Msg->NewID) )
421                 return ;
422
423         // Create new element
424         new = calloc(sizeof(tElement), 1);
425         new->Window = parent->Window;
426         new->ID = Msg->NewID;
427         new->Type = Msg->Type;
428         new->Parent = parent;
429         new->Flags = Msg->Flags;
430         new->PaddingT = 2;
431         new->PaddingB = 2;
432         new->PaddingL = 2;
433         new->PaddingR = 2;
434         new->CachedX = -1;
435         
436         if( new->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[new->Type].Init )
437                 gaWM_WidgetTypes[new->Type].Init(new);
438         
439         // Add to parent's list
440         if(parent->LastChild)
441                 parent->LastChild->NextSibling = new;
442         else
443                 parent->FirstChild = new;
444         parent->LastChild = new;
445
446         // Add to info
447         {
448                 tElement        *ele, *prev = NULL;
449                 for(ele = Info->ElementTable[new->ID % Info->TableSize]; ele; prev = ele, ele = ele->ListNext);
450                 if(prev)
451                         prev->ListNext = new;
452                 else
453                         Info->ElementTable[new->ID % Info->TableSize] = new;
454         }
455
456         Widget_UpdateMinDims(parent);
457 }
458
459 void Widget_SetFlags(tWidgetWin *Info, int Len, tWidgetMsg_SetFlags *Msg)
460 {
461         tElement        *ele;
462         
463         if( Len < sizeof(tWidgetMsg_SetFlags) )
464                 return ;
465
466         _SysDebug("Widget_SetFlags: (%i 0x%x 0x%x)", Msg->WidgetID, Msg->Value, Msg->Mask);
467         
468         ele = Widget_GetElementById(Info, Msg->WidgetID);
469         if(!ele)        return;
470
471         Msg->Value &= Msg->Mask;
472         
473         ele->Flags &= ~Msg->Mask;
474         ele->Flags |= Msg->Value;
475 }
476
477 void Widget_SetSize(tWidgetWin *Info, int Len, tWidgetMsg_SetSize *Msg)
478 {
479         tElement        *ele;
480         
481         if( Len < sizeof(tWidgetMsg_SetSize) )
482                 return ;
483         
484         ele = Widget_GetElementById(Info, Msg->WidgetID);
485         if(!ele)        return ;
486         
487         ele->FixedWith = Msg->Value;
488 }
489
490 void Widget_SetText(tWidgetWin *Info, int Len, tWidgetMsg_SetText *Msg)
491 {
492         tElement        *ele;
493         
494         if( Len < sizeof(tWidgetMsg_SetText) + 1 )
495                 return ;
496         if( Msg->Text[Len - sizeof(tWidgetMsg_SetText) - 1] != '\0' )
497                 return ;
498
499         ele = Widget_GetElementById(Info, Msg->WidgetID);
500         if(!ele)        return ;
501
502
503         if( ele->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[ele->Type].UpdateText )
504         {
505                 gaWM_WidgetTypes[ele->Type].UpdateText( ele, Msg->Text );
506         }
507 //      else
508 //      {
509 //              if(ele->Text)   free(ele->Text);
510 //              ele->Text = strdup(Msg->Text);
511 //      }
512 }
513
514 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
515 {
516         tWidgetWin      *info = Target->RendererInfo;
517         switch(Msg)
518         {
519         case WNDMSG_RESIZE: {
520                 struct sWndMsg_Resize   *msg = Data;
521                 if(Len < sizeof(*msg))  return -1;              
522
523                 info->RootElement.CachedW = msg->W;             
524                 info->RootElement.CachedH = msg->H;
525                 
526                 // TODO: Update dimensions of all child elements?
527                 
528                 return 0; }
529
530         case WNDMSG_MOUSEMOVE: {
531                 _SysDebug("TODO: Support widget mouse move events");
532                 return 0; }
533
534         case WNDMSG_MOUSEBTN: {
535                 struct sWndMsg_MouseButton      *msg = Data;
536                 tWidgetMsg_MouseBtn     client_msg;
537                 tElement        *ele;
538                  int    x, y;
539                  int    rv;
540                 
541                 if(Len < sizeof(*msg))  return -1;
542
543                 x = msg->X; y = msg->Y;
544                 client_msg.Button = msg->Button;
545                 client_msg.bPressed = msg->bPressed;
546
547                 ele = Widget_GetElementByPos(info, x, y);
548                 // Send event to all elements from `ele` upwards
549                 for( ; ele; ele = ele->Parent )
550                 {
551                         if(ele->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[ele->Type].MouseButton)
552                         {
553                                 rv = gaWM_WidgetTypes[ele->Type].MouseButton(
554                                         ele,
555                                         x - ele->CachedX, y - ele->CachedY,
556                                         msg->Button, msg->bPressed
557                                         );
558                                 // Allow a type to trap the input from going any higher
559                                 if(rv == 0)     break;
560                         }
561                         else
562                         {
563                                 // Pass to user
564                                 client_msg.X = x - ele->CachedX;
565                                 client_msg.Y = y - ele->CachedY;
566                                 client_msg.WidgetID = ele->ID;
567                                 WM_SendMessage(Target, Target, MSG_WIDGET_MOUSEBTN, sizeof(client_msg), &client_msg);
568                         }
569                 }
570                 return 0; }
571
572         // New Widget
573         case MSG_WIDGET_CREATE:
574                 Widget_NewWidget(info, Len, Data);
575                 return 0;
576
577         case MSG_WIDGET_DELETE:
578                 _SysDebug("TODO: Implement MSG_WIDGET_DELETE");
579                 return 0;
580
581         // Set Flags
582         case MSG_WIDGET_SETFLAGS:
583                 Widget_SetFlags(info, Len, Data);
584                 return 0;
585         
586         // Set length
587         case MSG_WIDGET_SETSIZE:
588                 Widget_SetSize(info, Len, Data);
589                 return 0;
590         
591         // Set text
592         case MSG_WIDGET_SETTEXT:
593                 Widget_SetText(info, Len, Data);
594                 return 0;
595         
596         // 
597         default:
598                 return 1;       // Unhandled, pass to user
599         }
600 }
601
602 void Widget_Fire(tElement *Element)
603 {
604         tWidgetMsg_Fire msg;
605         msg.WidgetID = Element->ID;
606         WM_SendMessage(Element->Window, Element->Window, MSG_WIDGET_FIRE, sizeof(msg), &msg);
607 }
608
609 // --- Type Helpers
610 void Widget_DispText_UpdateText(tElement *Element, const char *Text)
611 {
612          int    w=0, h=0;
613
614         if(Element->Text)       free(Element->Text);
615         Element->Text = strdup(Text);
616
617         WM_Render_GetTextDims(NULL, Element->Text, &w, &h);
618         if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL)) {
619                 Element->MinCross = w;
620                 Element->MinWith = h;
621         }
622         else {
623                 Element->MinWith = w;
624                 Element->MinCross = h;
625         }
626
627         Widget_UpdateMinDims(Element->Parent);
628 }
629
630 void Widget_Image_UpdateText(tElement *Element, const char *Text)
631 {
632         if(Element->Data)       free(Element->Data);
633         Element->Data = Image_Load( Text );
634         if(!Element->Data) {
635 //              Element->Flags &= ~ELEFLAG_FIXEDSIZE;
636                 return ;
637         }
638         
639         Element->CachedW = ((tImage*)Element->Data)->Width;
640         Element->CachedH = ((tImage*)Element->Data)->Height;
641         
642         if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) ) {
643                 Element->MinCross = ((tImage*)Element->Data)->Width;
644                 Element->MinWith = ((tImage*)Element->Data)->Height;
645         }
646         else {
647                 Element->MinWith = ((tImage*)Element->Data)->Width;
648                 Element->MinCross = ((tImage*)Element->Data)->Height;
649         }
650
651         Widget_UpdateMinDims(Element->Parent);
652         
653         // NOTE: Doesn't update Element->Text because it's useless
654 }
655
656 int Widget_Button_MouseButton(tElement *Element, int X, int Y, int Button, int bPress)
657 {
658         _SysDebug("Ele %i - Button %i %s",
659                 Element->ID, Button,
660                 (bPress ? "pressed" : "released")
661                 );
662         if(!bPress)     Widget_Fire(Element);
663         return 0;       // Handled
664 }
665
666 void Widget_TextInput_Init(tElement *Element)
667 {
668          int    h;
669
670         // TODO: Select font correctly  
671         WM_Render_GetTextDims(NULL, "jJ", NULL, &h);
672         
673         if( Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) )
674                 Element->MinWith = h;
675         else
676                 Element->MinCross = h;
677
678         // No need to explicitly update parent min dims, as the AddElement routine does that    
679 }
680

UCC git Repository :: git.ucc.asn.au