1 /// module containing the button UI element
2 module ysge.ui.button;
3 
4 import std.string;
5 import ysge.project;
6 
7 alias ButtonOnClick = void delegate(Project, Button);
8 
9 /// button UI element
10 class Button : UIElement {
11 	private string       label; /// the text that displays on the button
12 	private SDL_Texture* labelTexture;
13 	ButtonOnClick        onClick; /// called when the button is clicked
14 	SDL_Rect             rect; /// the rectangle the button will be rendered in
15 	SDL_Color            fill; /// the background colour of the button
16 	SDL_Color            outline; /// the colour of the button outline
17 	SDL_Color            outlineHover; /// the colour of the button outline when the cursor is hovering on it
18 	SDL_Color            fillHover; /// the colour of the button fill when the cursor is hovering on it
19 	SDL_Color            labelColour; /// the colour of the label text
20 
21 	/// sets the button's label
22 	void SetLabel(string newLabel) {
23 		if (newLabel != label) {
24 			labelTexture = null;
25 		}
26 
27 		label = newLabel;
28 	}
29 
30 	/// copies this UI element to a new class instance
31 	Button CreateCopy() {
32 		Button ret = new Button();
33 		
34 		ret.SetLabel(label);
35 		ret.onClick      = onClick;
36 		ret.rect         = rect;
37 		ret.fill         = fill;
38 		ret.outline      = outline;
39 		ret.outlineHover = outlineHover;
40 		ret.labelColour  = labelColour;
41 
42 		return ret;
43 	}
44 
45 	/// checks if a position is inside the button
46 	bool OnButton(Vec2!int pos) {
47 		return (
48 			(pos.x > rect.x) &&
49 			(pos.y > rect.y) &&
50 			(pos.x < rect.x + rect.w) &&
51 			(pos.y < rect.y + rect.h)
52 		);
53 	}
54 
55 	override bool HandleEvent(Project project, SDL_Event e) {
56 		switch (e.type) {
57 			case SDL_MOUSEBUTTONDOWN: {
58 				if (e.button.button != SDL_BUTTON_LEFT) {
59 					return false;
60 				}
61 
62 				auto mouse = project.mousePos;
63 
64 				if (OnButton(mouse)) {
65 					onClick(project, this);
66 				}
67 				else {
68 					return false;
69 				}
70 				break;
71 			}
72 			default: return false;
73 		}
74 
75 		return false;
76 	}
77 
78 	override void Render(Project project) {
79 		auto fillColour    = OnButton(project.mousePos)? fillHover : fill;
80 		auto outlineColour = OnButton(project.mousePos)? outlineHover : outline;
81 	
82 		SDL_SetRenderDrawColor(
83 			project.renderer, fillColour.r, fillColour.g, fillColour.b,
84 			fillColour.a
85 		);
86 		SDL_RenderFillRect(project.renderer, &rect);
87 		SDL_SetRenderDrawColor(
88 			project.renderer, outlineColour.r, outlineColour.g, outlineColour.b,
89 			outlineColour.a
90 		);
91 		SDL_RenderDrawRect(project.renderer, &rect);
92 
93 		if (label.strip() == "") {
94 			return;
95 		}
96 
97 		if (labelTexture is null) {
98 			SDL_Surface* labelSurface = TTF_RenderText_Solid(
99 				project.font, toStringz(label), labelColour
100 			);
101 
102 			if (labelSurface is null) {
103 				throw new ProjectException("Failed to render text");
104 			}
105 
106 			labelTexture = SDL_CreateTextureFromSurface(
107 				project.renderer, labelSurface
108 			);
109 
110 			if (labelTexture is null) {
111 				throw new ProjectException("Failed to create text texture");
112 			}
113 		}
114 
115 		SDL_Rect textBox;
116 		SDL_QueryTexture(labelTexture, null, null, &textBox.w, &textBox.h);
117 		textBox.x  = rect.x;
118 		textBox.y  = rect.y;
119 		textBox.x += (rect.w / 2) - (textBox.w / 2);
120 		textBox.y += (rect.h / 2) - (textBox.h / 2);
121 
122 		SDL_RenderCopy(project.renderer, labelTexture, null, &textBox);
123 	}
124 }