SimpleGUI
simplegui.h
1 #ifndef GUI
2 #define GUI
3 
4 #include <X11/Xlib.h>
5 #include <cstring>
6 #include <X11/Xutil.h>
7 #include <sys/time.h>
8 #include <algorithm>
9 
10 using namespace std;
11 
12 unsigned long rgb(unsigned long red, unsigned long green, unsigned long blue) {
13  return red<<16 | green<<8 | blue;
14 }
15 
16 //===================================================================================
17 
25 class Widget {
26 protected:
27  int x,y;
28  int width,height;
29  char text[256];
30  bool focused;
31  bool hidden;
32  Display* display;
33  int screen;
34  Window window;
35  GC gc;
36 
37  //-------------------------------------------------------------------------------
38  static void defaultAction() {}
39  //-------------------------------------------------------------------------------
40  static void defaultTaggedAction(char []) {}
41 
42 public:
43  void (*action)();
44  void (*taggedAction)(char text[]);
45 
46  Widget(int x,int y,int width,int height,const char text[])
47  : x(x), y(y), width(width), height(height), focused(false), hidden(true) {
48  strcpy(this->text,text);
49  action = &defaultAction;
50  taggedAction = &defaultTaggedAction;
51  }
52  //-------------------------------------------------------------------------------
53  void updateGraphVariables(Display* display,int screen,Window window,GC gc) {
54  this->display = display;
55  this->screen = screen;
56  this->window = window;
57  this->gc = gc;
58  }
59  //-------------------------------------------------------------------------------
60  virtual ~Widget() {
61  }
62  //-------------------------------------------------------------------------------
63  virtual void draw() {
64  }
65  //-------------------------------------------------------------------------------
66  virtual bool triggerEvent(XEvent&) {
67  return false;
68  }
69  //-------------------------------------------------------------------------------
70  bool mouseInArea(XEvent& event) {
71  int mx = event.xbutton.x;
72  int my = event.xbutton.y;
73  if (mx > x && mx < x+width && my > y && my < y+height) {
74  return true;
75  }
76  return false;
77  }
78  //-------------------------------------------------------------------------------
79  virtual void setFocused(bool) {
80  this->focused = false;
81  }
82  //-------------------------------------------------------------------------------
83  char* getText() {
84  return text;
85  }
86  //-------------------------------------------------------------------------------
87  void setText(const char text[]) {
88  strcpy(this->text,text);
89  draw();
90  }
91  //-------------------------------------------------------------------------------
92  void show() {
93  hidden = false;
94  draw();
95  }
96 };
97 
98 //===================================================================================
99 
106 class Label : public Widget {
107 public:
108  Label(int x,int y,int width,int height=20,const char text[]="")
109  : Widget(x,y,width,height,text){
110  }
111  //-------------------------------------------------------------------------------
112  void draw() {
113  if (hidden) return;
114  XClearArea(display,window,x+1,y+1,width-1,height-1,false);
115  unsigned int columns = (width-8)/6;
116  char* visibletext = new char[columns+1];
117  strncpy(visibletext,text,columns);
118  visibletext[columns]=0;
119  XDrawString(display,window,gc,x+5,y+height/2+5,visibletext,strlen(visibletext));
120  }
121 };
122 
123 //===================================================================================
124 
130 class TextField : public Widget {
131 private:
132  bool editing;
133  bool tilde;
134 public:
135  TextField(int x,int y,int width,int height=20)
136  : Widget(x,y,width,height,""), editing(false), tilde(false){
137  }
138  //-------------------------------------------------------------------------------
139  void draw() {
140  if (hidden) return;
141  XDrawRectangle(display,window,gc,x,y,width,height);
142  XClearArea(display,window,x+1,y+1,width-1,height-1,false);
143  XDrawString(display,window,gc,x+5,y+height/2+5,text,strlen(text));
144  if (editing) {
145  XDrawLine(display,window,gc,x+5+strlen(text)*6,y+height/2-6,x+5+strlen(text)*6,y+height/2+6);
146  }
147  }
148  //-------------------------------------------------------------------------------
149  bool triggerEvent(XEvent& event) {
150  switch (event.type) {
151  case ButtonPress:
152  if (mouseInArea(event)) return true;
153  break;
154  case KeyPress:
155  if (!editing) return false;
156  char buffer[40];
157  KeySym keysym;
158  XComposeStatus compose;
159  XLookupString(&event.xkey,buffer,10,&keysym,&compose);
160  switch(keysym) {
161  case XK_Escape:
162  return false;
163  case XK_Return:
164  (*action)();
165  (*taggedAction)(text);
166  return true;
167  case XK_Tab:
168  return false;
169  case XK_BackSpace:
170  if (strlen(text)>0) {
171  text[strlen(text)-1]=0;
172  }
173  break;
174  default:
175  unsigned int columns = (width-10)/6;
176  if (strlen(text) >= columns) break;
177 
178  if (keysym==65105) { // Tilde
179  tilde = true;
180  break;
181  }
182 
183  if (keysym>65000) break; // Special Keys
184 
185  if (tilde) {
186  switch (keysym) {
187  case XK_a: keysym = XK_aacute; break;
188  case XK_e: keysym = XK_eacute; break;
189  case XK_i: keysym = XK_iacute; break;
190  case XK_o: keysym = XK_oacute; break;
191  case XK_u: keysym = XK_uacute; break;
192  }
193  tilde=false;
194  }
195 
196  int pos = strlen(text);
197  text[pos]=keysym;
198  text[pos+1]=0;
199  break;
200  }
201  draw();
202  return true;
203  }
204  return false;
205  }
206  //-------------------------------------------------------------------------------
207  void setFocused(bool focused) {
208  if (focused && !this->focused) {
209  editing=true;
210  draw();
211  }
212  else if (!focused && this->focused) {
213  editing=false;
214  draw();
215  }
216  this->focused = focused;
217  }
218 };
219 
220 //===================================================================================
221 
228 class Button : public Widget {
229 private:
230  bool active;
231 public:
232  Button(int x,int y,int width,int height=20,const char text[]="")
233  : Widget(x,y,width,height,text), active(false) {
234  }
235  //-------------------------------------------------------------------------------
236  void draw() {
237  if (hidden) return;
238  XDrawRectangle(display,window,gc,x,y,width,height);
239 
240  if (active) {
241  XSetForeground(display,gc,rgb(200,200,200));
242  XFillRectangle(display,window,gc,x+1,y+1,width-1,height-1);
243  XSetForeground(display,gc,rgb(0,0,0));
244  }
245  else {
246  XClearArea(display,window,x+1,y+1,width-1,height-1,false);
247  }
248  int cx = x+width/2;
249  int cy = y+height/2;
250  int twidth = strlen(text)*7;
251  int theight = 10;
252  XDrawString(display,window,gc,cx-twidth/2,cy+theight/2,text,strlen(text));
253  }
254  //-------------------------------------------------------------------------------
255  bool triggerEvent(XEvent& event) {
256  switch (event.type) {
257  case ButtonPress:
258  if (mouseInArea(event)) {
259  active = true;
260  draw();
261  }
262  break;
263  case ButtonRelease:
264  if (active && mouseInArea(event)) {
265  active = false;
266  draw();
267  (*action)();
268  (*taggedAction)(text);
269  return true;
270  }
271  break;
272  case MotionNotify:
273  if (active && !mouseInArea(event)) {
274  active = false;
275  draw();
276  }
277  }
278  return false;
279  }
280 };
281 
282 //===================================================================================
283 
284 #include <vector>
285 
292 class List : public Widget {
293 private:
294  std::vector<char*> items;
295  int current,first;
296  timeval previewsclicktime;
297 
298  //-------------------------------------------------------------------------------
299  static bool less(char* item1,char* item2) {
300  return (strcmp(item1,item2)<0);
301  }
302 
303  //-------------------------------------------------------------------------------
304  static void defaultSelectionChanged(const char[]) {}
305  static void defaultDoubleClicked(const char[]){}
306 
307 public:
308  void (*selectionChanged)(const char[]);
309  void (*doubleClicked)(const char[]);
310 
311  List(int x,int y,int width=100,int height=100)
312  : Widget(x,y,width,height,"") {
313  current=-1;
314  first=0;
315  selectionChanged = &defaultSelectionChanged;
316  doubleClicked = &defaultDoubleClicked;
317  gettimeofday(&previewsclicktime,NULL);
318  }
319  //-------------------------------------------------------------------------------
320  ~List() {
321  removeAll();
322  }
323  //-------------------------------------------------------------------------------
324  void draw() {
325  if (hidden) return;
326  XDrawRectangle(display,window,gc,x,y,width,height);
327  XClearArea(display,window,x+1,y+1,width-1,height-1,false);
328 
329  unsigned int rows = height/15;
330  unsigned int columns = (width-8)/6;
331 
332  strcpy(text,"");
333  if (current>=0 && items.size()>0) {
334  XSetForeground(display,gc,rgb(150,150,255));
335  XFillRectangle(display,window,gc,x+1,y+1+current*15,width-1,15);
336  XSetForeground(display,gc,rgb(0,0,0));
337  strcpy(text,items.at(current));
338  }
339  for (unsigned int i=first,r=0; i<items.size() && r<rows; i++) {
340  char* item = new char[columns+1];
341  strncpy(item,items[i],columns);
342  item[columns]=0;
343  XDrawString(display,window,gc,x+5,y+12+r*15,item,strlen(item));
344  delete item;
345  r++;
346  }
347  }
348  //-------------------------------------------------------------------------------
349  void add(const char item[]) {
350  char* buffer = new char[strlen(item)+1];
351  strcpy(buffer,item);
352  items.push_back(buffer);
353  draw();
354  }
355  //-------------------------------------------------------------------------------
356  bool triggerEvent(XEvent& event) {
357  switch (event.type) {
358  case ButtonPress:
359  switch (event.xbutton.button) {
360  case 1: // left button
361  if (mouseInArea(event)) {
362  unsigned int position = (event.xbutton.y-y)/15;
363  unsigned int rows = height/15;
364  if (position<items.size()-first && position<rows) {
365  bool sameitem = false;
366  if ((unsigned int)current==position) {
367  sameitem = true;
368  }
369  current = position;
370  (*selectionChanged)(items.at(current+first));
371 
372  struct timeval currentclicktime;
373  gettimeofday(&currentclicktime,NULL);
374  if (sameitem) {
375  unsigned long dif =
376  currentclicktime.tv_sec%10000*1000000+currentclicktime.tv_usec -
377  previewsclicktime.tv_sec%10000*1000000+previewsclicktime.tv_usec;
378  if (dif <2000000) {
379  (*doubleClicked)(items.at(current+first));
380  }
381  }
382  previewsclicktime = currentclicktime;
383  }
384 
385  draw();
386  }
387  break;
388  case 5: // scrollmouse down
389  if (mouseInArea(event)) if (first>0) {
390  int rows = height/15;
391  first--;
392  if (current>=0 && current<rows-1) {
393  current++;
394  }
395  draw();
396  }
397  break;
398  case 4: // scrollmouse up
399  if (mouseInArea(event)) if (first<(int)items.size()-1){
400  first++;
401  if (current>0) {
402  current--;
403  }
404  draw();
405  }
406  break;
407  }
408  break;
409  }
410  return false;
411  }
412  //-------------------------------------------------------------------------------
413  int getCurrentIndex() {
414  return current;
415  }
416 
417  //-------------------------------------------------------------------------------
418  int count() {
419  return items.size();
420  }
421  //-------------------------------------------------------------------------------
422  void remove(int i) {
423  if (i<0) return;
424  delete items[i];
425  items.erase(items.begin()+i);
426  current = -1;
427  first = 0;
428  draw();
429  }
430  //-------------------------------------------------------------------------------
431  void removeAll() {
432  for (unsigned int i=0; i<items.size(); i++) {
433  delete items[i];
434  }
435  items.clear();
436  current = -1;
437  first = 0;
438  draw();
439  }
440  //-------------------------------------------------------------------------------
441  void sort() {
442  std::sort(items.begin(), items.end(), less );
443  draw();
444  }
445 };
446 
447 //===================================================================================
448 
454 class Frame : public Widget {
455  static const int MAX = 500;
456 private:
457  bool active;
458  Widget* widgets[MAX];
459  Widget* current;
460 
461 public:
462  Frame(int x=100,int y=100,int width=600,int height=400,const char title[]="")
463  : Widget(x,y,width,height,title), active(true) {
464  strcpy(this->text,title);
465  display = XOpenDisplay(NULL);
466  screen = DefaultScreen(display);
467  window = XCreateSimpleWindow(display,RootWindow(display,screen),
468  x,y,width,height,1,0,255<<16|255<<8|255);
469  gc = XDefaultGC(display,screen);
470  XMapWindow(display,window);
471  XSelectInput(display,window,ExposureMask|ButtonPressMask|ButtonReleaseMask
472  |KeyPressMask|PointerMotionMask);
473  Atom WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
474  XSetWMProtocols(display, window, &WM_DELETE_WINDOW, 1);
475 
476  XStoreName(display,window,text);
477 
478  const char* fontname = "-bitstream-bitstream vera sans mono-medium-r-normal--10-0-0-0-m-0-iso8859-1";
479 
480  XFontStruct* font = XLoadQueryFont (display, fontname);
481  if (!font) {
482  font = XLoadQueryFont (display, "fixed");
483  }
484  XSetFont (display, gc, font->fid);
485 
486  for (int i=0; i<MAX; i++) widgets[i]=NULL;
487  current = NULL;
488  }
489  //-------------------------------------------------------------------------------
490  ~Frame() {
491  for (int i=0; i<MAX; i++) {
492  if (widgets[i]) {
493  delete widgets[i];
494  }
495  }
496  XCloseDisplay(display);
497  }
498  //-------------------------------------------------------------------------------
499  void run() {
500  for (int i=0; i<MAX; i++) if (widgets[i]){
501  widgets[i]->show();
502  }
503  while(active) {
504  XEvent event;
505  XNextEvent(display,&event);
506 
507  if (current) if (current->triggerEvent(event)) goto done;
508 
509  for (int i=0; i<MAX; i++) {
510  if (widgets[i]) {
511  if (widgets[i]->triggerEvent(event)) {
512  changeFocus(widgets[i]);
513  goto done;
514  }
515  }
516  }
517 
518  switch (event.type) {
519  case KeyPress:
520  break;
521  case Expose:
522  for (int i=0; i<MAX; i++) if (widgets[i]) {
523  widgets[i]->draw();
524  }
525  case MotionNotify:
526  break;
527  case ClientMessage:
528  dispose();
529  break;
530  default:
531  break;
532  }
533  done: {}
534  }
535  }
536  //-------------------------------------------------------------------------------
537  Widget* add(Widget* widget) {
538  for (int i=0; i<MAX; i++) if (!widgets[i]) {
539  widgets[i] = widget;
540  widgets[i]->updateGraphVariables(display,screen,window,gc);
541  return widget;
542  }
543  return NULL;
544  }
545  //-------------------------------------------------------------------------------
546  void dispose() {
547  active = false;
548  }
549  //-------------------------------------------------------------------------------
550  void changeFocus(Widget* widget) {
551  if (current) current->setFocused(false);
552  current = widget;
553  current->setFocused(true);
554  }
555 };
556 
568 #endif // GUI
569 
The Button class is the prefered object usted to execute actions in common applications. This object is actionated by means of a click with the mouse device. This class can program the two actions inherited of Widget class.
Definition: simplegui.h:228
The Label class is the most simple visual class, useful show information to an application final user...
Definition: simplegui.h:106
The List class is a containter of textual items, it object can be stored more items as it can to show...
Definition: simplegui.h:292
The Widget class is the base of all classes in the simplegui library, this class has the main visual ...
Definition: simplegui.h:25
The Frame class manage all visual objects: Labels, InputText, Buttons, Lists, so on. One frame works like a window, and send all actions to each object after use them.
Definition: simplegui.h:454
The TextField class is the object used to get information since the final user. To activate its funct...
Definition: simplegui.h:130