ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
CollectionView.c File Reference
#include <assert.h>
#include <math.h>
#include "CollectionView.h"

Go to the source code of this file.

Macros

#define _Class   _CollectionView
 

Functions

Class * _CollectionView (void)
 
static void applyStyle (View *self, const Style *style)
 
static bool captureEvent (Control *self, const SDL_Event *event)
 
static void dealloc (Object *self)
 
static void deselectAll (CollectionView *self)
 
static void deselectAll_enumerate (const Array *array, ident obj, ident data)
 ArrayEnumerator for all item deselection.
 
static void deselectItemAtIndexPath (CollectionView *self, const IndexPath *indexPath)
 
static void deselectItemsAtIndexPaths (CollectionView *self, const Array *indexPaths)
 
static void deselectItemsAtIndexPaths_enumerate (const Array *array, ident obj, ident data)
 ArrayEnumerator for item deselection.
 
static IndexPath * indexPathForItem (const CollectionView *self, const CollectionItemView *item)
 
static IndexPath * indexPathForItemAtPoint (const CollectionView *self, const SDL_Point *point)
 
static Viewinit (View *self)
 
static void initialize (Class *clazz)
 
static CollectionViewinitWithFrame (CollectionView *self, const SDL_Rect *frame)
 
static CollectionItemViewitemAtIndexPath (const CollectionView *self, const IndexPath *indexPath)
 
static void layoutSubviews (View *self)
 
static SDL_Size naturalSize (const CollectionView *self)
 
static void reloadData (CollectionView *self)
 
static void reloadData_removeItems (const Array *array, ident obj, ident data)
 ArrayEnumerator to remove CollectionItemViews from the collection's contentView.
 
static void selectAll (CollectionView *self)
 
static void selectAll_enumerate (const Array *array, ident obj, ident data)
 ArrayEnumerator for all item selection.
 
static Array * selectionIndexPaths (const CollectionView *self)
 
static void selectItemAtIndexPath (CollectionView *self, const IndexPath *indexPath)
 
static void selectItemsAtIndexPaths (CollectionView *self, const Array *indexPaths)
 
static void selectItemsAtIndexPaths_enumerate (const Array *array, ident obj, ident data)
 ArrayEnumerator for item selection.
 

Variables

const EnumName CollectionViewAxisNames []
 

Macro Definition Documentation

◆ _Class

#define _Class   _CollectionView

Definition at line 34 of file CollectionView.c.

Function Documentation

◆ _CollectionView()

Class * _CollectionView ( void  )

Definition at line 542 of file CollectionView.c.

542 {
543 static Class *clazz;
544 static Once once;
545
546 do_once(&once, {
547 clazz = _initialize(&(const ClassDef) {
548 .name = "CollectionView",
549 .superclass = _Control(),
550 .instanceSize = sizeof(CollectionView),
551 .interfaceOffset = offsetof(CollectionView, interface),
552 .interfaceSize = sizeof(CollectionViewInterface),
554 });
555 });
556
557 return clazz;
558}
static void initialize(Class *clazz)
Class * _Control(void)
Definition Control.c:391
CollectionViews display items in a grid.

◆ applyStyle()

static void applyStyle ( View self,
const Style style 
)
static
See also
View::applyStyle(View *, const Style *)

Definition at line 59 of file CollectionView.c.

59 {
60
61 super(View, self, applyStyle, style);
62
63 CollectionView *this = (CollectionView *) self;
64
65 const Inlet inlets[] = MakeInlets(
66 MakeInlet("axis", InletTypeEnum, &this->axis, (ident) CollectionViewAxisNames),
67 MakeInlet("item-size", InletTypeSize, &this->itemSize, NULL),
68 MakeInlet("item-spacing", InletTypeSize, &this->itemSpacing, NULL)
69 );
70
71 $(self, bind, inlets, (Dictionary *) style->attributes);
72}
static void applyStyle(View *self, const Style *style)
const EnumName CollectionViewAxisNames[]
@ InletTypeEnum
Definition View+JSON.h:75
@ InletTypeSize
Definition View+JSON.h:110
#define MakeInlets(...)
Creates a null-termianted array of Inlets.
Definition View+JSON.h:221
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Definition View+JSON.h:216
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:155
Dictionary * attributes
Definition Style.h:59
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134

◆ captureEvent()

static bool captureEvent ( Control self,
const SDL_Event *  event 
)
static
See also
Control::captureEvent(Control *, const SDL_Event *)

Definition at line 129 of file CollectionView.c.

129 {
130
131 if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
132
133 CollectionView *this = (CollectionView *) self;
134
135 if ($((Control *) this->scrollView, isHighlighted) == false) {
136 if ($((View *) this->contentView, didReceiveEvent, event)) {
137
138 const SDL_Point point = {
139 .x = event->button.x,
140 .y = event->button.y
141 };
142
143 IndexPath *indexPath = $(this, indexPathForItemAtPoint, &point);
144
145 const CollectionItemView *item = $(this, itemAtIndexPath, indexPath);
146 if (item) {
147
148 switch (self->selection) {
150 break;
152 if (item->isSelected == false) {
153 $(this, deselectAll);
154 $(this, selectItemAtIndexPath, indexPath);
155 }
156 break;
158 if (SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_GUI)) {
159 if (item->isSelected) {
160 $(this, deselectItemAtIndexPath, indexPath);
161 } else {
162 $(this, selectItemAtIndexPath, indexPath);
163 }
164 } else {
165 $(this, deselectAll);
166 $(this, selectItemAtIndexPath, indexPath);
167 }
168 break;
169 }
170
171 if (this->delegate.didModifySelection) {
173
174 this->delegate.didModifySelection(this, selectionIndexPaths);
175
176 release(selectionIndexPaths);
177 }
178 }
179
180 release(indexPath);
181 return true;
182 }
183 }
184 }
185
186 return super(Control, self, captureEvent, event);
187}
static void deselectItemAtIndexPath(CollectionView *self, const IndexPath *indexPath)
static CollectionItemView * itemAtIndexPath(const CollectionView *self, const IndexPath *indexPath)
static bool captureEvent(Control *self, const SDL_Event *event)
static Array * selectionIndexPaths(const CollectionView *self)
static IndexPath * indexPathForItemAtPoint(const CollectionView *self, const SDL_Point *point)
static void selectItemAtIndexPath(CollectionView *self, const IndexPath *indexPath)
static void deselectAll(CollectionView *self)
static bool isHighlighted(const Control *self)
Definition Control.c:327
@ ControlSelectionMultiple
Definition Control.h:57
@ ControlSelectionSingle
Definition Control.h:56
@ ControlSelectionNone
Definition Control.h:55
static bool didReceiveEvent(const View *self, const SDL_Event *event)
Definition View.c:668
CollectionViewItems are a visual representation of an item within a CollectionView.
bool isSelected
True when this item is selected, false otherwise.
Controls are Views which capture and respond to events.
Definition Control.h:83
ControlSelection selection
The ControlSelection.
Definition Control.h:109

◆ dealloc()

static void dealloc ( Object *  self)
static
See also
Object::dealloc(Object *)

Definition at line 41 of file CollectionView.c.

41 {
42
43 CollectionView *this = (CollectionView *) self;
44
45 memset(&this->delegate, 0, sizeof(this->delegate));
46
47 release(this->contentView);
48 release(this->items);
49 release(this->scrollView);
50
51 super(Object, self, dealloc);
52}
static void dealloc(Object *self)

◆ deselectAll()

static void deselectAll ( CollectionView self)
static

Definition at line 202 of file CollectionView.c.

202 {
203 $((Array *) self->items, enumerate, deselectAll_enumerate, NULL);
204}
static void deselectAll_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for all item deselection.
static void enumerate(View *self, ViewEnumerator enumerator, ident data)
Definition View.c:749
Array * items
The items.

◆ deselectAll_enumerate()

static void deselectAll_enumerate ( const Array *  array,
ident  obj,
ident  data 
)
static

ArrayEnumerator for all item deselection.

Definition at line 194 of file CollectionView.c.

194 {
195 $((CollectionItemView *) obj, setSelected, false);
196}
static void setSelected(CollectionItemView *self, bool isSelected)

◆ deselectItemAtIndexPath()

static void deselectItemAtIndexPath ( CollectionView self,
const IndexPath *  indexPath 
)
static

Definition at line 210 of file CollectionView.c.

210 {
211
212 if (indexPath) {
213 CollectionItemView *item = $(self, itemAtIndexPath, indexPath);
214 if (item) {
215 $(item, setSelected, false);
217 }
218 }
219}
static void invalidateStyle(View *self)
Definition View.c:1033
View * contentView
The content view.

◆ deselectItemsAtIndexPaths()

static void deselectItemsAtIndexPaths ( CollectionView self,
const Array *  indexPaths 
)
static

Definition at line 232 of file CollectionView.c.

232 {
233
234 if (indexPaths) {
236 }
237}
static void deselectItemsAtIndexPaths_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for item deselection.

◆ deselectItemsAtIndexPaths_enumerate()

static void deselectItemsAtIndexPaths_enumerate ( const Array *  array,
ident  obj,
ident  data 
)
static

ArrayEnumerator for item deselection.

Definition at line 224 of file CollectionView.c.

224 {
225 $((CollectionItemView *) obj, setSelected, false);
226}

◆ indexPathForItem()

static IndexPath * indexPathForItem ( const CollectionView self,
const CollectionItemView item 
)
static

Definition at line 283 of file CollectionView.c.

283 {
284
285 const ssize_t index = $((Array *) self->items, indexOfObject, (ident) item);
286 if (index > -1) {
287 return $(alloc(IndexPath), initWithIndex, index);
288 }
289
290 return NULL;
291}

◆ indexPathForItemAtPoint()

static IndexPath * indexPathForItemAtPoint ( const CollectionView self,
const SDL_Point *  point 
)
static

Definition at line 243 of file CollectionView.c.

243 {
244
245 if (self->itemSize.w && self->itemSize.h) {
246
247 const SDL_Rect frame = $(self->contentView, renderFrame);
248
249 const int itemWidth = self->itemSize.w + self->itemSpacing.w;
250 const int itemHeight = self->itemSize.h + self->itemSpacing.h;
251
252 const int rows = max(1, frame.h / itemHeight);
253 const int cols = max(1, frame.w / itemWidth);
254
255 const int x = point->x - frame.x;
256 const int y = point->y - frame.y;
257
258 const int row = y / itemHeight;
259 const int col = x / itemWidth;
260
261 int index;
262 switch (self->axis) {
264 index = row * cols + col;
265 break;
267 index = col * rows + row;
268 break;
269 }
270
271 if (index < (int) self->items->count) {
272 return $(alloc(IndexPath), initWithIndex, index);
273 }
274 }
275
276 return NULL;
277}
static SDL_Rect renderFrame(const View *self)
Definition View.c:1455
@ CollectionViewAxisHorizontal
@ CollectionViewAxisVertical
SDL_Size itemSize
The item size.
CollectionViewAxis axis
The layout axis.
SDL_Size itemSpacing
The item spacing.

◆ init()

static View * init ( View self)
static
See also
View::init(View *)

Definition at line 77 of file CollectionView.c.

77 {
78 return (View *) $((CollectionView *) self, initWithFrame, NULL);
79}
static CollectionView * initWithFrame(CollectionView *self, const SDL_Rect *frame)

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 513 of file CollectionView.c.

513 {
514
515 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
516
517 ((ViewInterface *) clazz->interface)->applyStyle = applyStyle;
518 ((ViewInterface *) clazz->interface)->init = init;
519 ((ViewInterface *) clazz->interface)->layoutSubviews = layoutSubviews;
520
521 ((ControlInterface *) clazz->interface)->captureEvent = captureEvent;
522
523 ((CollectionViewInterface *) clazz->interface)->deselectAll = deselectAll;
524 ((CollectionViewInterface *) clazz->interface)->deselectItemAtIndexPath = deselectItemAtIndexPath;
525 ((CollectionViewInterface *) clazz->interface)->deselectItemsAtIndexPaths = deselectItemsAtIndexPaths;
526 ((CollectionViewInterface *) clazz->interface)->indexPathForItem = indexPathForItem;
527 ((CollectionViewInterface *) clazz->interface)->indexPathForItemAtPoint = indexPathForItemAtPoint;
528 ((CollectionViewInterface *) clazz->interface)->initWithFrame = initWithFrame;
529 ((CollectionViewInterface *) clazz->interface)->itemAtIndexPath = itemAtIndexPath;
530 ((CollectionViewInterface *) clazz->interface)->naturalSize = naturalSize;
531 ((CollectionViewInterface *) clazz->interface)->reloadData = reloadData;
532 ((CollectionViewInterface *) clazz->interface)->selectAll = selectAll;
533 ((CollectionViewInterface *) clazz->interface)->selectionIndexPaths = selectionIndexPaths;
534 ((CollectionViewInterface *) clazz->interface)->selectItemAtIndexPath = selectItemAtIndexPath;
535 ((CollectionViewInterface *) clazz->interface)->selectItemsAtIndexPaths = selectItemsAtIndexPaths;
536}
static void selectAll(CollectionView *self)
static IndexPath * indexPathForItem(const CollectionView *self, const CollectionItemView *item)
static View * init(View *self)
static void deselectItemsAtIndexPaths(CollectionView *self, const Array *indexPaths)
static void selectItemsAtIndexPaths(CollectionView *self, const Array *indexPaths)
static SDL_Size naturalSize(const CollectionView *self)
static void layoutSubviews(View *self)
static void reloadData(CollectionView *self)
CollectionItemView * itemAtIndexPath(const CollectionView *self, const IndexPath *indexPath)
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
Definition Box.c:74

◆ initWithFrame()

static CollectionView * initWithFrame ( CollectionView self,
const SDL_Rect *  frame 
)
static

Definition at line 297 of file CollectionView.c.

297 {
298
299 self = (CollectionView *) super(Control, self, initWithFrame, frame);
300 if (self) {
301 self->items = $$(Array, array);
302 assert(self->items);
303
304 self->contentView = $(alloc(View), initWithFrame, NULL);
305 assert(self->contentView);
306
307 $(self->contentView, addClassName, "contentView");
308 $(self->contentView, addClassName, "container");
309
310 self->scrollView = $(alloc(ScrollView), initWithFrame, NULL);
311 assert(self->scrollView);
312
313 $(self->scrollView, setContentView, self->contentView);
314 $((View *) self, addSubview, (View *) self->scrollView);
315 }
316
317 return self;
318}
static void addSubview(View *self, View *subview)
Definition PageView.c:49
static void setContentView(ScrollView *self, View *contentView)
Definition ScrollView.c:148
static void addClassName(View *self, const char *className)
Definition View.c:159
ScrollView * scrollView
The scroll view.
ScrollViews allow users to pan their internal contents.
Definition ScrollView.h:62

◆ itemAtIndexPath()

static CollectionItemView * itemAtIndexPath ( const CollectionView self,
const IndexPath *  indexPath 
)
static

Definition at line 324 of file CollectionView.c.

324 {
325
326 if (indexPath) {
327 const Array *items = (Array *) self->items;
328 const size_t index = $(indexPath, indexAtPosition, 0);
329
330 if (index < items->count) {
331 return $(items, objectAtIndex, index);
332 }
333 }
334
335 return NULL;
336}

◆ layoutSubviews()

static void layoutSubviews ( View self)
static
See also
View::layoutSubviews(View *)

Definition at line 84 of file CollectionView.c.

84 {
85
86 CollectionView *this = (CollectionView *) self;
87
88 super(View, self, layoutSubviews);
89
90 const SDL_Rect bounds = $((View *) this->scrollView, bounds);
91
92 int x = bounds.x, y = bounds.y;
93
94 const Array *items = (Array *) this->items;
95 for (size_t i = 0; i < items->count; i++) {
96
97 CollectionItemView *item = (CollectionItemView *) $(items, objectAtIndex, i);
98
99 $((View *) item, resize, &this->itemSize);
100 $((View *) item, layoutIfNeeded);
101
102 item->view.frame.x = x;
103 item->view.frame.y = y;
104
105 switch (this->axis) {
107 x += this->itemSize.w + this->itemSpacing.w;
108 if (x + this->itemSize.w > bounds.w) {
109 y += this->itemSize.h + this->itemSpacing.h;
110 x = bounds.x;
111 }
112 break;
114 y += this->itemSize.h + this->itemSpacing.h;
115 if (y + this->itemSize.h > bounds.h) {
116 x += this->itemSize.w + this->itemSpacing.w;
117 y = bounds.y;
118 }
119 break;
120 }
121 }
122}
static void resize(View *self, const SDL_Size *size)
Definition View.c:1527
static void layoutIfNeeded(View *self)
Definition View.c:1115
static SDL_Rect bounds(const View *self)
Definition View.c:492
View view
The superclass.
SDL_Rect frame
The frame, relative to the superview.
Definition View.h:191

◆ naturalSize()

static SDL_Size naturalSize ( const CollectionView self)
static

Definition at line 342 of file CollectionView.c.

342 {
343
344 ViewPadding padding = MakePadding(0, 0, 0, 0);
345 padding = AddPadding(padding, ((View *) self)->padding);
346 padding = AddPadding(padding, ((View *) self->scrollView)->padding);
347 padding = AddPadding(padding, ((View *) self->contentView)->padding);
348
349 SDL_Size size = MakeSize(padding.left + padding.right, padding.top + padding.bottom);
350
351 View *scrollView = (View *) self->scrollView;
352 SDL_Size scrollViewSize;
353 if (scrollView->autoresizingMask & ViewAutoresizingContain) {
354 scrollViewSize = $(scrollView, sizeThatContains);
355 } else if (scrollView->autoresizingMask & ViewAutoresizingFit) {
356 scrollViewSize = $(scrollView, sizeThatFits);
357 } else {
358 scrollViewSize = $(scrollView, size);
359 }
360
361 switch (self->axis) {
363 int itemsPerRow = 1;
364 int w = scrollViewSize.w;
365 while (w > 0) {
366 w -= self->itemSize.w;
367 itemsPerRow++;
368 if (w - self->itemSpacing.w < 0) {
369 break;
370 }
371 w -= self->itemSpacing.w;
372 }
373 const int rows = ceilf(self->items->count / (float) itemsPerRow);
374 size.w += max(self->itemSize.w, scrollViewSize.w);
375 size.h += rows * (self->itemSize.h + self->itemSpacing.h);
376 }
377 break;
379 int itemsPerCol = 1;
380 int h = scrollViewSize.h;
381 while (h > 0) {
382 h -= self->itemSize.h;
383 itemsPerCol++;
384 if (h - self->itemSpacing.h < 0) {
385 break;
386 }
387 h -= self->itemSpacing.h;
388 }
389 const int cols = ceilf(self->items->count / (float) itemsPerCol);
390 size.w += cols * (self->itemSize.w + self->itemSpacing.w);
391 size.h += max(self->itemSize.h, scrollViewSize.h);
392 }
393 break;
394 }
395
396 return size;
397}
static SDL_Size size(const Image *self)
Definition Image.c:181
static SDL_Size sizeThatFits(const View *self)
Definition Select.c:92
static SDL_Size sizeThatContains(const View *self)
Definition View.c:1659
#define MakePadding(top, right, bottom, left)
Creates a ViewPadding with the given dimensions.
Definition View.h:107
#define AddPadding(a, b)
Definition View.h:113
@ ViewAutoresizingContain
Definition View.h:92
@ ViewAutoresizingFit
Definition View.h:91
Spacing applied to the inside of a View's frame.
Definition View.h:100
int top
Definition View.h:101
int bottom
Definition View.h:101
int right
Definition View.h:101
int left
Definition View.h:101

◆ reloadData()

static void reloadData ( CollectionView self)
static

Definition at line 410 of file CollectionView.c.

410 {
411
412 assert(self->dataSource.numberOfItems);
414
415 $((Array *) self->items, enumerate, reloadData_removeItems, self->contentView);
416 $(self->items, removeAllObjects);
417
418 const size_t numberOfItems = self->dataSource.numberOfItems(self);
419 for (size_t i = 0; i < numberOfItems; i++) {
420
421 IndexPath *indexPath = $(alloc(IndexPath), initWithIndex, i);
422
423 CollectionItemView *item = self->delegate.itemForObjectAtIndexPath(self, indexPath);
424 assert(item);
425
426 $(self->items, addObject, item);
427 $(self->contentView, addSubview, (View *) item);
428
429 release(item);
430 release(indexPath);
431 }
432
433 ((View *) self)->needsLayout = true;
434}
static void reloadData_removeItems(const Array *array, ident obj, ident data)
ArrayEnumerator to remove CollectionItemViews from the collection's contentView.
size_t(* numberOfItems)(const CollectionView *collectionView)
CollectionItemView *(* itemForObjectAtIndexPath)(const CollectionView *collectionView, const IndexPath *indexPath)
Called by the CollectionView to instantiate items.
CollectionViewDelegate delegate
The delegate.
CollectionViewDataSource dataSource
The data source.

◆ reloadData_removeItems()

static void reloadData_removeItems ( const Array *  array,
ident  obj,
ident  data 
)
static

ArrayEnumerator to remove CollectionItemViews from the collection's contentView.

Definition at line 402 of file CollectionView.c.

402 {
403 $((View *) data, removeSubview, (View *) obj);
404}
static void removeSubview(View *self, View *subview)
Definition PageView.c:72

◆ selectAll()

static void selectAll ( CollectionView self)
static

Definition at line 447 of file CollectionView.c.

447 {
448 $((Array *) self->items, enumerate, selectAll_enumerate, NULL);
449}
static void selectAll_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for all item selection.

◆ selectAll_enumerate()

static void selectAll_enumerate ( const Array *  array,
ident  obj,
ident  data 
)
static

ArrayEnumerator for all item selection.

Definition at line 439 of file CollectionView.c.

439 {
440 $((CollectionItemView *) obj, setSelected, true);
441}

◆ selectionIndexPaths()

static Array * selectionIndexPaths ( const CollectionView self)
static

Definition at line 455 of file CollectionView.c.

455 {
456
457 Array *array = $$(Array, array);
458
459 const Array *items = (Array *) self->items;
460 for (size_t i = 0; i < items->count; i++) {
461
462 const CollectionItemView *item = $(items, objectAtIndex, i);
463 if (item->isSelected) {
464
465 IndexPath *indexPath = $(self, indexPathForItem, item);
466 $(array, addObject, indexPath);
467
468 release(indexPath);
469 }
470 }
471
472 return (Array *) array;
473}

◆ selectItemAtIndexPath()

static void selectItemAtIndexPath ( CollectionView self,
const IndexPath *  indexPath 
)
static

Definition at line 479 of file CollectionView.c.

479 {
480
481 if (indexPath) {
482 CollectionItemView *item = $(self, itemAtIndexPath, indexPath);
483 if (item) {
484 $(item, setSelected, true);
486 }
487 }
488}

◆ selectItemsAtIndexPaths()

static void selectItemsAtIndexPaths ( CollectionView self,
const Array *  indexPaths 
)
static

Definition at line 501 of file CollectionView.c.

501 {
502
503 if (indexPaths) {
504 $(indexPaths, enumerate, selectItemsAtIndexPaths_enumerate, self);
505 }
506}
static void selectItemsAtIndexPaths_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for item selection.

◆ selectItemsAtIndexPaths_enumerate()

static void selectItemsAtIndexPaths_enumerate ( const Array *  array,
ident  obj,
ident  data 
)
static

ArrayEnumerator for item selection.

Definition at line 493 of file CollectionView.c.

493 {
494 $((CollectionView *) data, selectItemAtIndexPath, (IndexPath *) obj);
495}

Variable Documentation

◆ CollectionViewAxisNames

const EnumName CollectionViewAxisNames[]
Initial value:
= MakeEnumNames(
MakeEnumAlias(CollectionViewAxisHorizontal, horizontal),
MakeEnumAlias(CollectionViewAxisVertical, vertical)
)

Definition at line 29 of file CollectionView.c.