1 #include <hikari/layout.h>
2 
3 #include <assert.h>
4 
5 #include <hikari/split.h>
6 #include <hikari/tile.h>
7 #include <hikari/view.h>
8 
9 void
hikari_layout_init(struct hikari_layout * layout,struct hikari_split * split,struct hikari_sheet * sheet)10 hikari_layout_init(struct hikari_layout *layout,
11     struct hikari_split *split,
12     struct hikari_sheet *sheet)
13 {
14   layout->split = hikari_split_copy(split);
15   layout->sheet = sheet;
16   wl_list_init(&layout->tiles);
17 }
18 
19 void
hikari_layout_fini(struct hikari_layout * layout)20 hikari_layout_fini(struct hikari_layout *layout)
21 {
22   hikari_split_free(layout->split);
23 }
24 
25 #define CYCLE_LAYOUT(name, link)                                               \
26   struct hikari_view *hikari_layout_##name##_view(                             \
27       struct hikari_layout *layout)                                            \
28   {                                                                            \
29     struct wl_list *link = layout->tiles.link;                                 \
30     struct hikari_tile *link##_tile;                                           \
31                                                                                \
32     do {                                                                       \
33       if (link == &layout->tiles) {                                            \
34         return NULL;                                                           \
35       } else {                                                                 \
36         link##_tile = wl_container_of(link, link##_tile, layout_tiles);        \
37       }                                                                        \
38       link = link->link;                                                       \
39     } while (hikari_view_is_hidden(link##_tile->view));                        \
40                                                                                \
41     assert(link##_tile != NULL);                                               \
42     assert(link##_tile->view != NULL);                                         \
43     assert(!hikari_view_is_hidden(link##_tile->view));                         \
44                                                                                \
45     return link##_tile->view;                                                  \
46   }
47 
CYCLE_LAYOUT(first,next)48 CYCLE_LAYOUT(first, next)
49 CYCLE_LAYOUT(last, prev)
50 #undef CYCLE_LAYOUT
51 
52 void
53 hikari_layout_reset(struct hikari_layout *layout)
54 {
55   assert(layout != NULL);
56 
57   struct hikari_sheet *sheet = layout->sheet;
58 
59   struct hikari_view *view;
60   wl_list_for_each (view, &sheet->views, sheet_views) {
61     if (hikari_view_is_tiled(view)) {
62       hikari_view_reset_geometry(view);
63     }
64   }
65 }
66 
67 static void
restack(struct hikari_layout * layout)68 restack(struct hikari_layout *layout)
69 {
70   assert(layout != NULL);
71 
72   struct hikari_tile *tile;
73   wl_list_for_each_reverse (tile, &layout->tiles, layout_tiles) {
74     struct hikari_view *view = tile->view;
75 
76     if (hikari_view_is_hidden(view)) {
77       hikari_view_show(view);
78     } else {
79       hikari_view_raise(view);
80     }
81   }
82 }
83 
84 void
hikari_layout_restack_append(struct hikari_layout * layout)85 hikari_layout_restack_append(struct hikari_layout *layout)
86 {
87   assert(layout != NULL);
88 
89   restack(layout);
90 
91   hikari_sheet_apply_split(layout->sheet, layout->split);
92 }
93 
94 static bool
view_is_prependable(struct hikari_view * view)95 view_is_prependable(struct hikari_view *view)
96 {
97   return !hikari_view_is_tiled(view) && hikari_view_is_tileable(view);
98 }
99 
100 static void
raise_prependable(struct hikari_sheet * sheet)101 raise_prependable(struct hikari_sheet *sheet)
102 {
103   struct hikari_view *view, *view_temp, *first = NULL;
104   wl_list_for_each_reverse_safe (view, view_temp, &sheet->views, sheet_views) {
105     if (view_is_prependable(view)) {
106       if (view == first) {
107         break;
108       } else if (first == NULL) {
109         first = view;
110       }
111 
112       hikari_view_raise(view);
113     }
114   }
115 }
116 
117 void
hikari_layout_restack_prepend(struct hikari_layout * layout)118 hikari_layout_restack_prepend(struct hikari_layout *layout)
119 {
120   assert(layout != NULL);
121 
122   restack(layout);
123   raise_prependable(layout->sheet);
124 
125   hikari_sheet_apply_split(layout->sheet, layout->split);
126 }
127