summaryrefslogtreecommitdiff
path: root/src/ui/sidebarwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-11 16:10:42 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-11 16:10:42 +0300
commit1e8b17b775715edfc68157d9be6743109f65a71b (patch)
tree9680b21fed26866c1717bcf89f8ce38ec6047d52 /src/ui/sidebarwidget.c
parenta0ddbf089bacfe8b9852e77a3bfcfb452d288053 (diff)
Document outline; jumping to clicked heading
Diffstat (limited to 'src/ui/sidebarwidget.c')
-rw-r--r--src/ui/sidebarwidget.c227
1 files changed, 202 insertions, 25 deletions
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 8f1273bf..46b36434 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -1,57 +1,234 @@
1#include "sidebarwidget.h" 1#include "sidebarwidget.h"
2#include "labelwidget.h" 2#include "labelwidget.h"
3#include "scrollwidget.h" 3#include "scrollwidget.h"
4#include "documentwidget.h"
4#include "paint.h" 5#include "paint.h"
5#include "util.h" 6#include "util.h"
7#include "command.h"
8#include "../gmdocument.h"
9#include "app.h"
10
11#include <the_Foundation/array.h>
12
13iDeclareType(SidebarItem)
14
15struct Impl_SidebarItem {
16 int indent;
17 iChar icon;
18 iString label;
19 iString meta;
20 iString url;
21 size_t index;
22};
23
24void init_SidebarItem(iSidebarItem *d) {
25 d->indent = 0;
26 d->icon = 0;
27 d->index = 0;
28 init_String(&d->label);
29 init_String(&d->meta);
30 init_String(&d->url);
31}
32
33void deinit_SidebarItem(iSidebarItem *d) {
34 deinit_String(&d->url);
35 deinit_String(&d->meta);
36 deinit_String(&d->label);
37}
38
39iDefineTypeConstruction(SidebarItem)
40
41/*----------------------------------------------------------------------------------------------*/
6 42
7struct Impl_SidebarWidget { 43struct Impl_SidebarWidget {
8 iWidget widget; 44 iWidget widget;
9 enum iSidebarMode mode; 45 enum iSidebarMode mode;
10 iScrollWidget *scroll; 46 iScrollWidget *scroll;
47 int scrollY;
48 iLabelWidget *modeButtons[max_SidebarMode];
49 int itemHeight;
50 iArray items;
51 size_t hoverItem;
52 iClick click;
11}; 53};
12 54
13iDefineObjectConstruction(SidebarWidget) 55iDefineObjectConstruction(SidebarWidget)
14 56
57static void clearItems_SidebarWidget_(iSidebarWidget *d) {
58 iForEach(Array, i, &d->items) {
59 deinit_SidebarItem(i.value);
60 }
61 clear_Array(&d->items);
62}
63
64static void updateItems_SidebarWidget_(iSidebarWidget *d) {
65 clearItems_SidebarWidget_(d);
66 switch (d->mode) {
67 case documentOutline_SidebarMode: {
68 const iGmDocument *doc = document_DocumentWidget(document_App());
69 iConstForEach(Array, i, headings_GmDocument(doc)) {
70 const iGmHeading *head = i.value;
71 iSidebarItem item;
72 init_SidebarItem(&item);
73 item.index = index_ArrayConstIterator(&i);
74 setRange_String(&item.label, head->text);
75 item.indent = head->level * 4 * gap_UI;
76 pushBack_Array(&d->items, &item);
77 }
78 break;
79 }
80 case bookmarks_SidebarMode:
81 break;
82 case history_SidebarMode:
83 break;
84 default:
85 break;
86 }
87 refresh_Widget(as_Widget(d));
88}
89
90void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
91 if (d->mode == mode) return;
92 d->mode = mode;
93 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) {
94 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode);
95 }
96 const float heights[max_SidebarMode] = { 1.2f, 2, 3, 3 };
97 d->itemHeight = heights[mode] * lineHeight_Text(default_FontId);
98}
99
15void init_SidebarWidget(iSidebarWidget *d) { 100void init_SidebarWidget(iSidebarWidget *d) {
16 iWidget *w = as_Widget(d); 101 iWidget *w = as_Widget(d);
17 init_Widget(w); 102 init_Widget(w);
18 setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); 103 setBackgroundColor_Widget(w, none_ColorId);
19 d->mode = documentOutline_SidebarMode; 104 setFlags_Widget(w, hover_WidgetFlag | arrangeHorizontal_WidgetFlag, iTrue);
20 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 105 d->scrollY = 0;
21 w->rect.size.x = 80 * gap_UI; 106 d->mode = -1;
107 w->rect.size.x = 100 * gap_UI;
108 init_Array(&d->items, sizeof(iSidebarItem));
109 d->hoverItem = iInvalidPos;
110 init_Click(&d->click, d, SDL_BUTTON_LEFT);
22 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue); 111 setFlags_Widget(w, fixedWidth_WidgetFlag, iTrue);
23 iWidget *modeButtons = makeHDiv_Widget(); 112 const char *buttonLabels[max_SidebarMode] = {
24 setFlags_Widget(modeButtons, arrangeWidth_WidgetFlag | arrangeHeight_WidgetFlag, iTrue); 113 "\U0001f5b9 Outline",
25 addChild_Widget(w, iClob(modeButtons)); 114 "\U0001f588 Bookmarks",
26 addChildFlags_Widget( 115 "\U0001f553 History",
27 modeButtons, 116 "\U0001f464 Identities",
28 iClob(new_LabelWidget( 117 };
29 "\U0001f5b9 Outline", 0, 0, format_CStr("sidebar.mode arg:%d", documentOutline_SidebarMode))), frameless_WidgetFlag); 118 for (int i = 0; i < max_SidebarMode; i++) {
30 addChildFlags_Widget( 119 d->modeButtons[i] = addChildFlags_Widget(
31 modeButtons, 120 w,
32 iClob(new_LabelWidget( 121 iClob(new_LabelWidget(buttonLabels[i], 0, 0, format_CStr("sidebar.mode arg:%d", i))),
33 "\U0001f588 Bookmarks", 0, 0, format_CStr("sidebar.mode arg:%d", bookmarks_SidebarMode))), frameless_WidgetFlag); 122 frameless_WidgetFlag);
34 addChildFlags_Widget( 123 }
35 modeButtons, 124 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
36 iClob(new_LabelWidget( 125 setThumb_ScrollWidget(d->scroll, 0, 0);
37 "\U0001f553 History", 0, 0, format_CStr("sidebar.mode arg:%d", history_SidebarMode))), frameless_WidgetFlag); 126 setMode_SidebarWidget(d, documentOutline_SidebarMode);
38 addChildFlags_Widget(
39 modeButtons,
40 iClob(new_LabelWidget(
41 "\U0001f464 Identities", 0, 0, format_CStr("sidebar.mode arg:%d", identities_SidebarMode))), frameless_WidgetFlag);
42} 127}
43 128
44void deinit_SidebarWidget(iSidebarWidget *d) { 129void deinit_SidebarWidget(iSidebarWidget *d) {
45 iUnused(d); 130 clearItems_SidebarWidget_(d);
131 deinit_Array(&d->items);
132}
133
134static iRect contentBounds_SidebarWidget_(const iSidebarWidget *d) {
135 iRect bounds = bounds_Widget(constAs_Widget(d));
136 adjustEdges_Rect(&bounds, as_Widget(d->modeButtons[0])->rect.size.y + gap_UI, 0, 0, 0);
137 return bounds;
138}
139
140static size_t itemIndex_SidebarWidget_(const iSidebarWidget *d, iInt2 pos) {
141 const iRect bounds = contentBounds_SidebarWidget_(d);
142 pos.y -= top_Rect(bounds);
143 if (pos.y < 0) return iInvalidPos;
144 size_t index = pos.y / d->itemHeight;
145 if (index >= size_Array(&d->items)) return iInvalidPos;
146 return index;
147}
148
149static void itemClicked_SidebarWidget_(iSidebarWidget *d, size_t index) {
150 const iSidebarItem *item = constAt_Array(&d->items, index);
151 switch (d->mode) {
152 case documentOutline_SidebarMode: {
153 const iGmDocument *doc = document_DocumentWidget(document_App());
154 const iGmHeading *head = constAt_Array(headings_GmDocument(doc), item->index);
155 postCommandf_App("document.goto loc:%p", head->text.start);
156 break;
157 }
158 }
46} 159}
47 160
48static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) { 161static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) {
49 iWidget *w = as_Widget(d); 162 iWidget *w = as_Widget(d);
163 /* Handle commands. */
164 if (ev->type == SDL_USEREVENT && ev->user.code == command_UserEventCode) {
165 const char *cmd = command_UserEvent(ev);
166 if (isCommand_Widget(w, ev, "sidebar.mode")) {
167 setMode_SidebarWidget(d, arg_Command(cmd));
168 updateItems_SidebarWidget_(d);
169 return iTrue;
170 }
171 else if (equal_Command(cmd, "tabs.changed") || equal_Command(cmd, "document.changed")) {
172 updateItems_SidebarWidget_(d);
173 }
174 }
175 if (ev->type == SDL_MOUSEMOTION) {
176 const iInt2 mouse = init_I2(ev->motion.x, ev->motion.y);
177 size_t hover = iInvalidPos;
178 if (contains_Widget(w, mouse)) {
179 hover = itemIndex_SidebarWidget_(d, mouse);
180
181 }
182 if (hover != d->hoverItem) {
183 d->hoverItem = hover;
184 refresh_Widget(w);
185 }
186 }
187 switch (processEvent_Click(&d->click, ev)) {
188 case started_ClickResult:
189 refresh_Widget(w);
190 break;
191 case finished_ClickResult:
192 if (contains_Rect(contentBounds_SidebarWidget_(d), pos_Click(&d->click)) &&
193 d->hoverItem != iInvalidSize) {
194 //printf("click:%zu\n", d->hoverItem); fflush(stdout);
195 itemClicked_SidebarWidget_(d, d->hoverItem);
196 }
197 refresh_Widget(w);
198 break;
199 default:
200 break;
201 }
50 return processEvent_Widget(w, ev); 202 return processEvent_Widget(w, ev);
51} 203}
52 204
53static void draw_SidebarWidget_(const iSidebarWidget *d) { 205static void draw_SidebarWidget_(const iSidebarWidget *d) {
54 const iWidget *w = constAs_Widget(d); 206 const iWidget *w = constAs_Widget(d);
207 const iRect bounds = contentBounds_SidebarWidget_(d);
208 const iBool isPressing = d->click.isActive && contains_Rect(bounds, pos_Click(&d->click));
209 iPaint p;
210 init_Paint(&p);
211 /* Draw the items. */ {
212 iInt2 pos = topLeft_Rect(bounds);
213 const int font = default_FontId;
214 iConstForEach(Array, i, &d->items) {
215 const iSidebarItem *item = i.value;
216 const iRect itemRect = { pos, init_I2(width_Rect(bounds), d->itemHeight) };
217 const iBool isHover = (d->hoverItem == index_ArrayConstIterator(&i));
218 if (isHover) {
219 fillRect_Paint(&p, itemRect, isPressing ? orange_ColorId : teal_ColorId);
220 }
221 setClip_Paint(&p, itemRect);
222 const int fg = isHover ? (isPressing ? black_ColorId : white_ColorId) : gray75_ColorId;
223 if (d->mode == documentOutline_SidebarMode) {
224 drawRange_Text(font, init_I2(pos.x + 3 * gap_UI + item->indent,
225 mid_Rect(itemRect).y - lineHeight_Text(font) / 2),
226 fg, range_String(&item->label));
227 }
228 unsetClip_Paint(&p);
229 pos.y += d->itemHeight;
230 }
231 }
55 draw_Widget(w); 232 draw_Widget(w);
56} 233}
57 234