1 /*
2 * 0BSD
3 *
4 * BSD Zero Clause License
5 *
6 * Copyright (c) 2019 Hermann Meyer
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted.
10
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "xcombobox.h"
22 #include "xcombobox_private.h"
23 #include "xtooltip.h"
24 #include "xslider.h"
25
26
combobox_set_active_entry(Widget_t * w,int active)27 void combobox_set_active_entry(Widget_t *w, int active) {
28 float value = (float)active;
29 if (value>w->adj->max_value) value = w->adj->max_value;
30 else if (value<w->adj->min_value) value = w->adj->min_value;
31 adj_set_value(w->adj, value);
32 }
33
combobox_mem_free(void * w_,void * user_data)34 void combobox_mem_free(void *w_, void* user_data) {
35 Widget_t *w = (Widget_t*)w_;
36 ComboBox_t *comboboxlist = (ComboBox_t*)w->parent_struct;
37 unsigned int j = 0;
38 for(; j<comboboxlist->list_size;j++) {
39 free(comboboxlist->list_names[j]);
40 comboboxlist->list_names[j] = NULL;
41 }
42 free(comboboxlist);
43 }
44
combobox_delete_entrys(Widget_t * combobox)45 void combobox_delete_entrys(Widget_t *combobox) {
46 Widget_t * menu = combobox->childlist->childs[1];
47 Widget_t* view_port = menu->childlist->childs[0];
48 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
49 unsigned int j = 0;
50 for(; j<comboboxlist->list_size;j++) {
51 free(comboboxlist->list_names[j]);
52 comboboxlist->list_names[j] = NULL;
53 }
54 comboboxlist->list_size = 0;
55 set_adjustment(combobox->adj,0.0, 0.0, 0.0, -1.0,1.0, CL_ENUM);
56 set_adjustment(view_port->adj,0.0, 0.0, 0.0, -6.0,1.0, CL_ENUM);
57 set_adjustment(comboboxlist->slider->adj,0.0, 0.0, 0.0, 1.0,0.0085, CL_VIEWPORTSLIDER);
58 }
59
pop_combobox_menu_show(Widget_t * parent,Widget_t * menu,int elem,bool above)60 void pop_combobox_menu_show(Widget_t *parent, Widget_t *menu, int elem, bool above) {
61 if (!childlist_has_child(menu->childlist)) return;
62 Widget_t* view_port = menu->childlist->childs[0];
63 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
64 if (!comboboxlist->list_size) return;
65 _configure_combobox_menu(parent, menu, elem, above);
66 pop_widget_show_all(menu);
67 int err = XGrabPointer(menu->app->dpy, DefaultRootWindow(parent->app->dpy), True,
68 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
69 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
70 menu->app->hold_grab = menu;
71
72 if (err) debug_print("Error grap pointer\n");
73 }
74
75
create_combobox_viewport(Widget_t * parent,int elem,int width,int height)76 Widget_t* create_combobox_viewport(Widget_t *parent, int elem, int width, int height) {
77 Widget_t *wid = create_widget(parent->app, parent, 0, 0, width, height);
78 XSelectInput(wid->app->dpy, wid->widget,StructureNotifyMask|ExposureMask|KeyPressMask
79 |EnterWindowMask|LeaveWindowMask|ButtonReleaseMask
80 |ButtonPressMask|Button1MotionMask|PointerMotionMask);
81 wid->scale.gravity = CENTER;
82 ComboBox_t *comboboxlist;
83 comboboxlist = (ComboBox_t*)malloc(sizeof(ComboBox_t));
84 comboboxlist->show_items = elem;
85 comboboxlist->list_names = NULL;
86 comboboxlist->list_size = 0;
87 wid->flags |= HAS_MEM;
88 wid->parent_struct = comboboxlist;
89 float max_value = -elem;
90 wid->adj_y = add_adjustment(wid,0.0, 0.0, 0.0, max_value,1.0, CL_VIEWPORT);
91 wid->adj = wid->adj_y;
92 wid->func.adj_callback = _set_combobox_viewpoint;
93 wid->func.motion_callback = _combobox_motion;
94 wid->func.leave_callback = _leave_combobox;
95 wid->func.button_release_callback = _combobox_entry_released;
96 wid->func.key_press_callback = _combobox_key_pressed;
97 wid->func.expose_callback = _draw_combobox_entrys;
98 wid->func.configure_notify_callback = _reconfigure_combobox_viewport;
99 wid->func.mem_free_callback = combobox_mem_free;
100 return wid;
101 }
102
create_combobox_menu(Widget_t * parent,int height)103 Widget_t* create_combobox_menu(Widget_t *parent, int height) {
104
105 int x1, y1;
106 Window child;
107 XTranslateCoordinates( parent->app->dpy, parent->widget, DefaultRootWindow(parent->app->dpy), 0, 0, &x1, &y1, &child );
108 Widget_t *wid = create_window(parent->app, DefaultRootWindow(parent->app->dpy), x1, y1, 10, height);
109 Widget_t *viewport = create_combobox_viewport(wid, 6, 10, 5*height);
110 ComboBox_t *comboboxlist = (ComboBox_t*)viewport->parent_struct;
111 comboboxlist->combobox = parent;
112
113 XSetWindowAttributes attributes;
114 attributes.override_redirect = True;
115 XChangeWindowAttributes(parent->app->dpy, wid->widget, CWOverrideRedirect, &attributes);
116
117 Atom window_type = XInternAtom(wid->app->dpy, "_NET_WM_WINDOW_TYPE", False);
118 Atom window_type_popup = XInternAtom(wid->app->dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
119 XChangeProperty(wid->app->dpy, wid->widget, window_type,
120 XA_ATOM, 32, PropModeReplace, (unsigned char *) &window_type_popup,1 );
121
122 Atom window_state = XInternAtom(wid->app->dpy, "_NET_WM_STATE", False);
123 Atom window_state_modal = XInternAtom(wid->app->dpy, "_NET_WM_STATE_MODAL", False);
124 XChangeProperty(wid->app->dpy, wid->widget, window_state,
125 XA_ATOM, 32, PropModeReplace, (unsigned char *) &window_state_modal, 1);
126
127 XSetTransientForHint(parent->app->dpy,wid->widget,parent->widget);
128 wid->func.expose_callback = _draw_combobox_menu;
129 wid->flags |= IS_POPUP;
130 wid->scale.gravity = NONE;
131 childlist_add_child(parent->childlist, wid);
132
133 comboboxlist->slider = add_vslider(wid, "", 0, 0, 10, height);
134 comboboxlist->slider->func.expose_callback = _draw_combobox_menu_slider;
135 comboboxlist->slider->adj_y = add_adjustment(comboboxlist->slider,0.0, 0.0, 0.0, 1.0,0.0085, CL_VIEWPORTSLIDER);
136 comboboxlist->slider->adj = comboboxlist->slider->adj_y;
137 comboboxlist->slider->func.value_changed_callback = _set_combobox_menu_viewport;
138 comboboxlist->slider->scale.gravity = NORTHWEST;
139 comboboxlist->slider->flags &= ~USE_TRANSPARENCY;
140 comboboxlist->slider->flags |= NO_AUTOREPEAT | NO_PROPAGATE;
141 comboboxlist->slider->parent_struct = viewport;
142
143 return wid;
144 }
145
add_combobox(Widget_t * parent,const char * label,int x,int y,int width,int height)146 Widget_t* add_combobox(Widget_t *parent, const char * label, int x, int y, int width, int height) {
147
148 Widget_t *wid = create_widget(parent->app, parent, x, y, width, height);
149 wid->label = label;
150 wid->scale.gravity = CENTER;
151 wid->adj_y = add_adjustment(wid,0.0, 0.0, 0.0, -1.0,1.0, CL_ENUM);
152 wid->adj = wid->adj_y;
153 wid->func.adj_callback = _set_entry;
154 wid->func.expose_callback = _draw_combobox;
155 wid->func.enter_callback = transparent_draw;
156 wid->func.leave_callback = transparent_draw;
157 wid->func.button_release_callback = _combobox_button_released;
158
159 Widget_t* button = add_button(wid, "", width-20, 0, 20, height);
160 button->func.expose_callback = _draw_combobox_button;
161 button->func.button_release_callback = _button_combobox_released;
162
163 Widget_t* menu = create_combobox_menu(wid, 25);
164 menu->func.button_release_callback = _entry_released;
165
166 return wid;
167 }
168
combobox_add_entry(Widget_t * wid,const char * label)169 void combobox_add_entry(Widget_t *wid, const char * label) {
170 Widget_t *menu = wid->childlist->childs[1];
171 Widget_t* view_port = menu->childlist->childs[0];
172 ComboBox_t *comboboxlist = (ComboBox_t*)view_port->parent_struct;
173 comboboxlist->list_names = (char **)realloc(comboboxlist->list_names,
174 (comboboxlist->list_size + 1) * sizeof(char *));
175 asprintf(&comboboxlist->list_names[comboboxlist->list_size++],"%s",label);
176 assert(comboboxlist->list_names != NULL);
177 float max_value = wid->adj->max_value+1.0;
178 set_adjustment(wid->adj,0.0, max_value, 0.0, max_value,1.0, CL_ENUM);
179
180 }
181
combobox_add_numeric_entrys(Widget_t * wid,int imin,int imax)182 void combobox_add_numeric_entrys(Widget_t *wid, int imin, int imax) {
183 int i = imin;
184 int o = imax+1;
185 for (;i<o;i++) {
186 char s[32];
187 snprintf(s, 31, "%i",i);
188 combobox_add_entry(wid, s);
189 }
190 }
191