summaryrefslogtreecommitdiff
path: root/sw/emu/knob.cpp
blob: 0883ab3a2e09fefacd1a91e0e097931081095ec5 (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
#include "imgui.h"
#include <math.h>
#include <stdio.h>
#define PI 3.1415926535897932384626433832795f
typedef unsigned int u32;
 
inline float lerp(float a, float b, float t) { return a+(b-a)*t; }
inline float saturate(float a) { return (a<0.f)?0.f:(a>1.f)?1.f:a; }
inline float length(float x, float y ){ return sqrtf(x*x+y*y); }

int TactileButton(const char *label, float size) {
	ImVec4 hilitecol = ImGui::GetStyle().Colors[ImGuiCol_FrameBg];
	hilitecol.x+=0.1f;
	auto style=ImGui::GetStyle();		
	ImDrawList* draw_list = ImGui::GetWindowDrawList();
	ImVec2 mouse_pos = ImGui::GetIO().MousePos;
	ImVec2 canvas_pos = ImGui::GetCursorScreenPos();            // ImDrawList API uses screen coordinates!
	float w=size,/*ImGui::CalcItemWidth(),*/ h=size;
	ImVec2 canvas_size = ImVec2(w,h);
	ImVec2 centre=ImVec2(canvas_pos.x+w*0.5f,canvas_pos.y+h*0.45f);
	ImGui::InvisibleButton(label, canvas_size);
	draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y),true);      // clip lines within the canvas (if we resize it, etc.)
	bool active=ImGui::IsItemActive();
	draw_list->AddCircleFilled(ImVec2(centre.x,centre.y),h*0.45f,active ? 0x80ffffff : 0x40ffffff, 32);
	ImVec2 labelsize=ImGui::CalcTextSize(label);
	draw_list->AddText(ImVec2(centre.x-labelsize.x*0.5f,canvas_pos.y-labelsize.y+h*0.5f),ImColor(style.Colors[ImGuiCol_Text]),label);
	draw_list->PopClipRect();		
	return active;
}

int Knob(const char *label, float &curval, float *randamount, float minval, float maxval, u32 encodercol, float size)
{

	ImVec4 hilitecol = ImGui::GetStyle().Colors[ImGuiCol_FrameBg];
	hilitecol.x+=0.1f*(curval-minval)/(maxval-minval);
//	hilitecol.z-=0.3f;
	static ImVec2 click_pos;	
	static float click_val,click_rand;
	static int grabrand;
	static bool clickedbutton;
	auto style=ImGui::GetStyle();		
	ImDrawList* draw_list = ImGui::GetWindowDrawList();
	ImVec2 mouse_pos = ImGui::GetIO().MousePos;
	ImVec2 canvas_pos = ImGui::GetCursorScreenPos();            // ImDrawList API uses screen coordinates!
	float w=size,/*ImGui::CalcItemWidth(),*/ h=size;
	ImVec2 canvas_size = ImVec2(w,h);
	ImVec2 centre=ImVec2(canvas_pos.x+w*0.5f,canvas_pos.y+h*0.45f);
	ImGui::InvisibleButton(label, canvas_size);
	draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y),true);      // clip lines within the canvas (if we resize it, etc.)
	float rad=h*0.4f;
	ImColor bg= hilitecol;// : style.Colors[ImGuiCol_FrameBg];	
	u32 tickcol=0x80ffffff;
	if (encodercol==1)
		encodercol=bg;
	float angrange=encodercol ? 3.141592f : 2.5f;
	float curang=lerp(-angrange,angrange,(curval-minval)/(maxval-minval));

	draw_list->PathClear();
	draw_list->PathArcTo(centre,rad,-angrange - PI/2,angrange - PI/2,20);
	draw_list->PathStroke(bg,false,rad*0.2f);
	bool active=ImGui::IsItemActive();
	if (active && ImGui::IsMouseClicked(0)) { 
		clickedbutton=false;
		click_pos=mouse_pos; click_val=curval; click_rand=randamount ? *randamount : 0.f; 
		grabrand=randamount && ImGui::GetIO().KeyShift;
		if (length(mouse_pos.x-centre.x, mouse_pos.y-centre.y)<h*0.3f)
			clickedbutton=true;
	}	

	if (!encodercol) {
		draw_list->PathClear();
		draw_list->PathArcTo(centre,rad,-angrange-PI/2,curang-PI/2,20);
		draw_list->PathStroke(tickcol,false,rad*0.2f);
	} else {
		draw_list->AddCircleFilled(ImVec2(centre.x,centre.y),h*0.3f,active && clickedbutton ? tickcol : encodercol, 32);
	}
	draw_list->AddCircleFilled(ImVec2(centre.x+0.f,centre.y-h*0.48f),h*0.02f,tickcol);

	ImColor barcol=(style.Colors[ImGuiCol_SliderGrabActive]); //:(i==hover)?ImGuiCol_CheckMark:ImGuiCol_ScrollbarGrab]))
	if (randamount && *randamount>0.f) {
		float minang=curang-angrange**randamount; if (minang<-angrange) minang=-angrange;
		float maxang=minang+angrange**randamount; if (maxang>angrange) { maxang=angrange; minang=maxang-angrange**randamount*2.f; }
		draw_list->PathClear();
		draw_list->PathArcTo(centre,rad,minang,maxang,20);
		draw_list->PathStroke(barcol,false,rad*0.05f);
	}
	float rad0=rad*0.4f;
	float rad2=rad+0.05f*h;
	draw_list->AddLine(ImVec2(centre.x+rad0*sinf(curang),centre.y-rad0*cosf(curang)), ImVec2(centre.x+rad2*sinf(curang),centre.y-rad2*cosf(curang)),tickcol, 2.f);
	int rv=0;
	if (active) {
		float angdelta = -atan2f(mouse_pos.x-centre.x, mouse_pos.y-centre.y) + atan2f(click_pos.x-centre.x,click_pos.y-centre.y);
//		if (clickedbutton)
//			angdelta=0.f;
		if (angdelta>PI) angdelta-=PI*2.f;
		if (angdelta<-PI) angdelta+=PI*2.f;
		angdelta*=1.f/(angrange*2.f);
//		ImVec2 delta(mouse_pos.x-click_pos.x,mouse_pos.y-click_pos.y);
//		float angdelta=((fabsf(delta.x)>fabsf(delta.y)) ? delta.x : -delta.y) / h;
		if (grabrand && randamount) 
			*randamount=saturate(click_rand+angdelta);
		else
		{
			curval=click_val+angdelta*(maxval-minval);
			if (!encodercol) {
				if (curval<minval) curval=minval;
				if (curval>maxval) curval=maxval;
			}
		}
		click_pos=mouse_pos; click_val=curval; click_rand=randamount ? *randamount : 0.f; 
	}
	draw_list->PopClipRect();		

//	char valuebuf[64];
	//snprintf(valuebuf,sizeof(valuebuf),"%.1f%%",curval*100.f);
   ImVec2 labelsize=ImGui::CalcTextSize(label);
//   ImVec2 valuesize=ImGui::CalcTextSize(valuebuf);

	draw_list->AddText(ImVec2(centre.x-labelsize.x*0.5f,canvas_pos.y-labelsize.y+h*0.5f),ImColor(style.Colors[ImGuiCol_Text]),label);
//	if (!encodercol)
//		draw_list->AddText(ImVec2(centre.x-valuesize.x*0.5f,canvas_pos.y+canvas_size.y-valuesize.y-2.f),ImColor(style.Colors[ImGuiCol_Text]),valuebuf);
	return clickedbutton && active;
}