/unix/tx/TXMenu.cxx

https://github.com/mcr/xorg-xvnc4 · C++ · 186 lines · 153 code · 13 blank · 20 comment · 50 complexity · f6c598d8165233f2f948addb4a27fd39 MD5 · raw file

  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. //
  19. // TXMenu.cxx
  20. //
  21. #include "TXMenu.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <assert.h>
  26. #include <rfb/util.h>
  27. #include <X11/keysym.h>
  28. TXMenu::TXMenu(Display* dpy_, TXMenuCallback* cb_, int w, int h,
  29. TXWindow* parent_)
  30. : TXWindow(dpy_, w, h, parent_), cb(cb_), nEntries(0),
  31. highlight(-1)
  32. {
  33. setEventHandler(this);
  34. gc = XCreateGC(dpy, win(), 0, 0);
  35. addEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask |
  36. PointerMotionMask | EnterWindowMask | LeaveWindowMask);
  37. }
  38. TXMenu::~TXMenu()
  39. {
  40. XFreeGC(dpy, gc);
  41. for (int i = 0; i < nEntries; i++)
  42. delete [] text[i];
  43. }
  44. inline int TXMenu::entryHeight(int i)
  45. {
  46. if (text[i])
  47. return defaultFS->ascent + defaultFS->descent + bevel*2 + yPad*2;
  48. else
  49. return yPad*2 + 1;
  50. }
  51. void TXMenu::addEntry(const char* text_, long id_)
  52. {
  53. assert(nEntries < maxEntries);
  54. text[nEntries] = rfb::strDup(text_);
  55. checked[nEntries] = false;
  56. id[nEntries++] = id_;
  57. int tw = 0;
  58. if (text_)
  59. tw = XTextWidth(defaultFS, text_, strlen(text_));
  60. int newWidth = width();
  61. if (tw + bevel*2 + xPad*5 + tickSize > width())
  62. newWidth = tw + bevel*2 + xPad*5 + tickSize;
  63. int newHeight = 0;
  64. for (int i = 0; i < nEntries; i++)
  65. newHeight += entryHeight(i);
  66. resize(newWidth, newHeight);
  67. }
  68. void TXMenu::check(long id_, bool checked_)
  69. {
  70. for (int i = 0; i < nEntries; i++) {
  71. if (id[i] == id_) {
  72. checked[i] = checked_;
  73. break;
  74. }
  75. }
  76. }
  77. void TXMenu::paint()
  78. {
  79. int y = 0;
  80. for (int i = 0; i < nEntries; i++) {
  81. if (text[i]) {
  82. if (i == highlight)
  83. drawBevel(gc, 0, y, width(), entryHeight(i), bevel,
  84. defaultBg, darkBg, lightBg);
  85. else
  86. XClearArea(dpy, win(), 0, y, width(), entryHeight(i), false);
  87. if (checked[i])
  88. XCopyPlane(dpy, tick, win(), defaultGC, 0, 0, tickSize, tickSize,
  89. bevel + xPad,
  90. y + bevel + yPad + defaultFS->ascent - tickSize, 1);
  91. XDrawImageString(dpy, win(), defaultGC, bevel + xPad*2 + tickSize,
  92. y + bevel + yPad + defaultFS->ascent,
  93. text[i], strlen(text[i]));
  94. } else {
  95. XDrawLine(dpy, win(), defaultGC, bevel + xPad, y + entryHeight(i) / 2,
  96. width() - bevel - xPad, y + entryHeight(i) / 2);
  97. }
  98. y += entryHeight(i);
  99. }
  100. }
  101. void TXMenu::handleEvent(TXWindow* w, XEvent* ev)
  102. {
  103. switch (ev->type) {
  104. case Expose:
  105. paint();
  106. break;
  107. case ButtonRelease:
  108. {
  109. int y = ev->xmotion.y;
  110. int entryY = 0;
  111. for (int i = 0; i < nEntries; i++) {
  112. if (y >= entryY && y <= entryY + entryHeight(i)) {
  113. if (cb && text[i])
  114. cb->menuSelect(id[i], this);
  115. break;
  116. }
  117. entryY += entryHeight(i);
  118. }
  119. highlight = -1;
  120. paint();
  121. break;
  122. }
  123. case ButtonPress:
  124. case MotionNotify:
  125. {
  126. int y = ev->xmotion.y;
  127. int entryY = 0;
  128. for (int i = 0; i < nEntries; i++) {
  129. if (y >= entryY && y <= entryY + entryHeight(i)) {
  130. if (highlight != i) {
  131. highlight = i;
  132. paint();
  133. }
  134. break;
  135. }
  136. entryY += entryHeight(i);
  137. }
  138. break;
  139. }
  140. case KeyPress:
  141. {
  142. KeySym ks;
  143. char str[256];
  144. XLookupString(&ev->xkey, str, 256, &ks, NULL);
  145. if (ks == XK_Escape) {
  146. highlight = -1;
  147. unmap();
  148. } else if (ks == XK_Down || ks == XK_Up) {
  149. if (nEntries < 1) break;
  150. if (highlight < 0)
  151. highlight = (ks == XK_Down ? nEntries-1 : 0);
  152. int start = highlight;
  153. int inc = (ks == XK_Down ? 1 : nEntries-1);
  154. do {
  155. highlight = (highlight + inc) % nEntries;
  156. } while (highlight != start && !text[highlight]);
  157. paint();
  158. } else if (ks == XK_space || ks == XK_KP_Space ||
  159. ks == XK_Return || ks == XK_KP_Enter) {
  160. if (cb && highlight >= 0 && text[highlight])
  161. cb->menuSelect(id[highlight], this);
  162. highlight = -1;
  163. paint();
  164. }
  165. break;
  166. }
  167. case EnterNotify:
  168. case LeaveNotify:
  169. highlight = -1;
  170. paint();
  171. break;
  172. }
  173. }