summaryrefslogtreecommitdiff
path: root/popover/popover.c
blob: 2c2bf66deb148384a573282fa91550a17b2d3da5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// 9 october 2014
#include <stdlib.h>
#include <stdint.h>
#include "popover.h"

#define ARROWHEIGHT 8
#define ARROWWIDTH 8		/* should be the same for smooth lines on Windows (TODO is there a better/nicer looking way?) */

struct popover {
	void *gopopover;

	// a nice consequence of this design is that it allows four arrowheads to jut out at once; in practice only one will ever be used, but hey — simple implementation!
	intptr_t arrowLeft;
	intptr_t arrowTop;
	intptr_t arrowRight;
	intptr_t arrowBottom;
};

popover *popoverDataNew(void *gopopover)
{
	popover *p;

	p = (popover *) malloc(sizeof (popover));
	if (p != NULL) {
		p->gopopover = gopopover;
		p->arrowLeft = -1;
		p->arrowTop = 20;//TODO-1;
		p->arrowRight = -1;
		p->arrowBottom = -1;
	}
	return p;
}

int popoverMakeFramePoints(popover *p, intptr_t width, intptr_t height, popoverPoint pt[20])
{
	int n;
	intptr_t xmax, ymax;

	n = 0;

	// figure out the xmax and ymax of the box
	xmax = width;
	if (p->arrowRight >= 0)
		xmax -= ARROWWIDTH;
	ymax = height;
	if (p->arrowBottom >= 0)
		ymax -= ARROWHEIGHT;

	// the first point is either at (0,0), (0,arrowHeight), (arrowWidth,0), or (arrowWidth,arrowHeight)
	pt[n].x = 0;
	if (p->arrowLeft >= 0)
		pt[n].x = ARROWWIDTH;
	pt[n].y = 0;
	if (p->arrowTop >= 0)
		pt[n].y = ARROWHEIGHT;
	n++;

	// the left side
	pt[n].x = pt[n - 1].x;
	if (p->arrowLeft >= 0) {
		pt[n].y = pt[n - 1].y + p->arrowLeft;
		n++;
		pt[n].x = pt[n - 1].x - ARROWWIDTH;
		pt[n].y = pt[n - 1].y + ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x + ARROWWIDTH;
		pt[n].y = pt[n - 1].y + ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x;
	}
	pt[n].y = ymax;
	n++;

	// the bottom side
	pt[n].y = pt[n - 1].y;
	if (p->arrowBottom >= 0) {
		pt[n].x = pt[n - 1].x + p->arrowBottom;
		n++;
		pt[n].x = pt[n - 1].x + ARROWWIDTH;
		pt[n].y = pt[n - 1].y + ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x + ARROWWIDTH;
		pt[n].y = pt[n - 1].y - ARROWHEIGHT;
		n++;
		pt[n].y = pt[n - 1].y;
	}
	pt[n].x = xmax;
	n++;

	// the right side
	pt[n].x = pt[n - 1].x;
	if (p->arrowRight >= 0) {
		pt[n].y = pt[0].y + p->arrowRight + (ARROWHEIGHT * 2);
		n++;
		pt[n].x = pt[n - 1].x + ARROWWIDTH;
		pt[n].y = pt[n - 1].y - ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x - ARROWWIDTH;
		pt[n].y = pt[n - 1].y - ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x;
	}
	pt[n].y = pt[0].y;
	n++;

	// the top side
	pt[n].y = pt[n - 1].y;
	if (p->arrowTop >= 0) {
		pt[n].x = pt[0].x + p->arrowTop + (ARROWWIDTH * 2);
		n++;
		pt[n].x = pt[n - 1].x - ARROWWIDTH;
		pt[n].y = pt[n - 1].y - ARROWHEIGHT;
		n++;
		pt[n].x = pt[n - 1].x - ARROWWIDTH;
		pt[n].y = pt[n - 1].y + ARROWHEIGHT;
		n++;
		pt[n].y = pt[n - 1].y;
	}
	pt[n].x = pt[0].x;
	n++;

	return n;
}

void popoverWindowSizeToClientSize(popover *p, popoverRect *r)
{
	r->left++;
	r->top++;
	r->right--;
	r->bottom--;
	if (p->arrowLeft >= 0)
		r->left += ARROWWIDTH;
	if (p->arrowRight >= 0)
		r->right -= ARROWWIDTH;
	if (p->arrowTop >= 0)
		r->top += ARROWHEIGHT;
	if (p->arrowBottom >= 0)
		r->bottom -= ARROWHEIGHT;
}

// TODO window edge detection
popoverRect popoverPointAt(popover *p, popoverRect control, intptr_t width, intptr_t height, unsigned int side)
{
	intptr_t x, y;
	popoverRect out;

	// account for border
	width += 2;
	height += 2;
	p->arrowLeft = -1;
	p->arrowRight = -1;
	p->arrowTop = -1;
	p->arrowBottom = -1;
	// TODO right and bottom
	switch (side) {
	case popoverPointLeft:
		width += ARROWWIDTH;
		p->arrowLeft = height / 2 - ARROWHEIGHT;
		x = control.right;
		y = control.top - ((height - (control.bottom - control.top)) / 2);
		break;
	case popoverPointTop:
		height += ARROWHEIGHT;
		p->arrowTop = width / 2 - ARROWWIDTH;
		x = control.left - ((width - (control.right - control.left)) / 2);
		y = control.bottom;
		break;
	}
	out.left = x;
	out.top = y;
	out.right = x + width;
	out.bottom = y + height;
	return out;
}