PageRenderTime 27ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/branches/R0_17/libs/csws/csbutton.cpp

#
C++ | 486 lines | 433 code | 27 blank | 26 comment | 124 complexity | 035261832ce2e0b2d6fb550065aca896 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Crystal Space Windowing System: button class
  3. Copyright (C) 1998,1999 by Andrew Zabolotny <bit@eltech.ru>
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public
  6. License as published by the Free Software Foundation; either
  7. version 2 of the License, or (at your option) any later version.
  8. This library 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 GNU
  11. Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this library; if not, write to the Free
  14. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <string.h>
  17. #define SYSDEF_CASE
  18. #include "cssysdef.h"
  19. #include "csws/cscomp.h"
  20. #include "csws/csapp.h"
  21. #include "csws/csbutton.h"
  22. #include "csws/csstatic.h"
  23. csButton::csButton (csComponent *iParent, int iCommandCode,
  24. int iButtonStyle, csButtonFrameStyle iFrameStyle) : csComponent (iParent),
  25. ImageNormal (NULL), ImagePressed (NULL), delImages (false),
  26. CommandCode (iCommandCode), underline_pos (-1),
  27. ButtonStyle (iButtonStyle), FrameStyle (iFrameStyle),
  28. Pressed (false)
  29. {
  30. SetPalette (CSPAL_BUTTON);
  31. if (ButtonStyle & CSBS_SELECTABLE)
  32. SetState (CSS_SELECTABLE, true);
  33. if (FrameStyle == csbfsOblique)
  34. SetState (CSS_TRANSPARENT, true);
  35. id = iCommandCode;
  36. }
  37. csButton::~csButton ()
  38. {
  39. FreeBitmaps ();
  40. }
  41. void csButton::SetBitmap (csPixmap *iNormal, csPixmap *iPressed,
  42. bool iDelete)
  43. {
  44. FreeBitmaps ();
  45. ImageNormal = iNormal;
  46. if (iPressed)
  47. ImagePressed = iPressed;
  48. else
  49. ImagePressed = iNormal;
  50. delImages = iDelete;
  51. Invalidate ();
  52. }
  53. void csButton::GetBitmap (csPixmap **iNormal, csPixmap **iPressed)
  54. {
  55. if (iNormal)
  56. *iNormal = ImageNormal;
  57. if (iPressed)
  58. *iPressed = ImagePressed;
  59. }
  60. void csButton::FreeBitmaps ()
  61. {
  62. if (delImages)
  63. {
  64. if (ImageNormal)
  65. delete ImageNormal;
  66. if (ImagePressed && ImagePressed != ImageNormal)
  67. delete ImagePressed;
  68. } /* endif */
  69. delImages = false;
  70. ImageNormal = NULL;
  71. ImagePressed = NULL;
  72. }
  73. void csButton::Draw ()
  74. {
  75. int li, di; // light and dark colors
  76. int areaw, areah; // drawing area width and height
  77. if (Pressed)
  78. {
  79. di = CSPAL_BUTTON_LIGHT3D;
  80. li = CSPAL_BUTTON_DARK3D;
  81. } else
  82. {
  83. di = CSPAL_BUTTON_DARK3D;
  84. li = CSPAL_BUTTON_LIGHT3D;
  85. } /* endif */
  86. DefaultBorder = ((ButtonStyle & CSBS_NODEFAULTBORDER) == 0)
  87. && ((parent->GetDefault () == this));
  88. // Draw the frame
  89. switch (FrameStyle)
  90. {
  91. case csbfsNone:
  92. if (!GetState (CSS_TRANSPARENT))
  93. Clear (CSPAL_BUTTON_BACKGROUND);
  94. areaw = bound.Width (); areah = bound.Height ();
  95. break;
  96. case csbfsOblique:
  97. if (bound.Height () >= 6)
  98. {
  99. int aw = bound.Height () / 3;
  100. if (DefaultBorder)
  101. ObliqueRect3D (0, 0, bound.Width (), bound.Height (), aw,
  102. CSPAL_BUTTON_DEFFRAME, CSPAL_BUTTON_DEFFRAME);
  103. else
  104. ObliqueRect3D (0, 0, bound.Width (), bound.Height (), aw,
  105. CSPAL_BUTTON_LIGHT3D, CSPAL_BUTTON_DARK3D);
  106. ObliqueRect3D (1, 1, bound.Width () - 1, bound.Height () - 1, aw - 1, di, li);
  107. ObliqueRect3D (2, 2, bound.Width () - 2, bound.Height () - 2, aw - 2, di, li);
  108. int rvy = bound.Height ();
  109. // Fill the button background
  110. int dx = aw - 1;
  111. rvy = bound.Height () - 1;
  112. for (int i = 3; i < aw; i++, dx--)
  113. {
  114. Line (dx, i, bound.Width () - 3, i, CSPAL_BUTTON_BACKGROUND);
  115. Line (3, rvy - i, bound.Width () - dx, rvy - i, CSPAL_BUTTON_BACKGROUND);
  116. } /* endfor */
  117. Box (3, aw, bound.Width () - 3, bound.Height () - aw, CSPAL_BUTTON_BACKGROUND);
  118. areaw = bound.Width () - 6; areah = bound.Height () - 6;
  119. break;
  120. } // otherwise fallback to rectangular frame
  121. case csbfsThickRect:
  122. if (DefaultBorder)
  123. Rect3D (0, 0, bound.Width (), bound.Height (),
  124. CSPAL_BUTTON_DEFFRAME, CSPAL_BUTTON_DEFFRAME);
  125. else
  126. Rect3D (0, 0, bound.Width (), bound.Height (),
  127. CSPAL_BUTTON_LIGHT3D, CSPAL_BUTTON_DARK3D);
  128. Rect3D (1, 1, bound.Width () - 1, bound.Height () - 1, di, li);
  129. Rect3D (2, 2, bound.Width () - 2, bound.Height () - 2, di, li);
  130. Box (3, 3, bound.Width () - 3, bound.Height () - 3, CSPAL_BUTTON_BACKGROUND);
  131. areaw = bound.Width () - 6; areah = bound.Height () - 6;
  132. break;
  133. case csbfsThinRect:
  134. if (DefaultBorder)
  135. Rect3D (0, 0, bound.Width (), bound.Height (),
  136. CSPAL_BUTTON_DEFFRAME, CSPAL_BUTTON_DEFFRAME);
  137. else
  138. Rect3D (0, 0, bound.Width (), bound.Height (),
  139. CSPAL_BUTTON_LIGHT3D, CSPAL_BUTTON_DARK3D);
  140. Rect3D (1, 1, bound.Width () - 1, bound.Height () - 1, di, li);
  141. Box (2, 2, bound.Width () - 2, bound.Height () - 2, CSPAL_BUTTON_BACKGROUND);
  142. areaw = bound.Width () - 4; areah = bound.Height () - 4;
  143. break;
  144. case csbfsVeryThinRect:
  145. if (Pressed)
  146. {
  147. Rect3D (0, 0, bound.Width (), bound.Height (), di, li);
  148. areaw = bound.Width () - 2; areah = bound.Height () - 2;
  149. Box (1, 1, bound.Width () - 1, bound.Height () - 1, CSPAL_BUTTON_BACKGROUND);
  150. }
  151. else
  152. {
  153. areaw = bound.Width (); areah = bound.Height ();
  154. Clear (CSPAL_BUTTON_BACKGROUND);
  155. } /* endif */
  156. break;
  157. default:
  158. return;
  159. } /* endswitch */
  160. // Calculate image position
  161. int imgx = 0, imgy = 0, imgw = 0, imgh = 0;
  162. csPixmap *img = Pressed ? ImagePressed : ImageNormal;
  163. if (img)
  164. {
  165. imgw = img->Width (); imgh = img->Height ();
  166. if (imgw > areaw) imgw = areaw;
  167. if (imgh > areah) imgh = areah;
  168. imgx = (bound.Width () - imgw) / 2;
  169. imgy = (bound.Height () - imgh) / 2;
  170. if ((ButtonStyle & CSBS_SHIFT) && Pressed)
  171. { imgx++; imgy++; }
  172. } /* endif */
  173. // Calculate text position
  174. int txtx = 0, txty = 0;
  175. if (text)
  176. {
  177. txtx = (bound.Width () - TextWidth (text)) / 2;
  178. if (img)
  179. switch (ButtonStyle & CSBS_TEXTPLACEMENT)
  180. {
  181. case CSBS_TEXTABOVE:
  182. imgy += TextHeight () / 2;
  183. txty = imgy - TextHeight () - 1;
  184. break;
  185. case CSBS_TEXTBELOW:
  186. imgy -= TextHeight () / 2;
  187. txty = imgy + img->Height () + 1;
  188. break;
  189. } /* endswitch */
  190. else
  191. txty = (bound.Height () - TextHeight ()) / 2;
  192. if ((ButtonStyle & CSBS_SHIFT) && Pressed)
  193. { txtx++; txty++; }
  194. }
  195. // Draw image
  196. if (img)
  197. Sprite2D (img, imgx, imgy, imgw, imgh);
  198. // Draw text
  199. if (text)
  200. {
  201. Text (txtx, txty, GetState (CSS_DISABLED) ? CSPAL_BUTTON_DTEXT :
  202. CSPAL_BUTTON_TEXT, -1, text);
  203. if (!GetState (CSS_DISABLED))
  204. DrawUnderline (txtx, txty, text, underline_pos, CSPAL_BUTTON_TEXT);
  205. }
  206. csComponent::Draw ();
  207. }
  208. bool csButton::HandleEvent (iEvent &Event)
  209. {
  210. switch (Event.Type)
  211. {
  212. case csevCommand:
  213. switch (Event.Command.Code)
  214. {
  215. case cscmdAreYouDefault:
  216. if (GetState (CSS_FOCUSED) || (ButtonStyle & CSBS_DEFAULT))
  217. Event.Command.Info = this;
  218. return true;
  219. case cscmdButtonDeselect:
  220. if ((ButtonStyle & CSBS_MULTICHOOSE)
  221. && Pressed)
  222. SetPressed (false);
  223. return true;
  224. case cscmdActivate:
  225. Event.Command.Info = this;
  226. Press ();
  227. return true;
  228. case cscmdStaticHotKeyEvent:
  229. {
  230. iEvent *ev = (iEvent *)Event.Command.Info;
  231. ev->Key.Code = CSKEY_SPACE;
  232. return csButton::HandleEvent (*ev);
  233. }
  234. case cscmdStaticMouseEvent:
  235. {
  236. iEvent *ev = (iEvent *)Event.Command.Info;
  237. if (app->MouseOwner)
  238. {
  239. int dX = 0, dY = 0;
  240. app->MouseOwner->LocalToGlobal (dX, dY);
  241. GlobalToLocal (dX, dY);
  242. // release mouse ownership so that csButton::HandleEvent can capture it
  243. app->CaptureMouse (NULL);
  244. if ((ev->Type == csevMouseMove)
  245. && app->MouseOwner->bound.ContainsRel (ev->Mouse.x, ev->Mouse.y))
  246. ev->Mouse.x = ev->Mouse.y = 0;
  247. else
  248. {
  249. ev->Mouse.x -= dX;
  250. ev->Mouse.y -= dY;
  251. } /* endif */
  252. } /* endif */
  253. return csButton::HandleEvent (*ev);
  254. }
  255. } /* endswitch */
  256. break;
  257. case csevMouseDown:
  258. case csevMouseDoubleClick:
  259. switch (Event.Mouse.Button)
  260. {
  261. case 1:
  262. if (GetState (CSS_DISABLED)
  263. || app->MouseOwner)
  264. return true;
  265. app->CaptureMouse (this);
  266. SetPressed (true);
  267. if ((ButtonStyle & CSBS_NOMOUSEFOCUS) == 0)
  268. csComponent::HandleEvent (Event);
  269. return true;
  270. case 2:
  271. if (parent)
  272. parent->SendCommand (cscmdButtonRightClick, (void *)this);
  273. return true;
  274. }
  275. break;
  276. case csevMouseUp:
  277. if (Event.Mouse.Button == 1)
  278. {
  279. if (app->MouseOwner == this)
  280. {
  281. app->CaptureMouse (NULL);
  282. if (Pressed)
  283. {
  284. if (!(ButtonStyle & CSBS_MULTICHOOSE))
  285. SetPressed (false);
  286. Press ();
  287. }
  288. }
  289. return true;
  290. }
  291. break;
  292. case csevMouseMove:
  293. if ((app->MouseOwner == this)
  294. && !(ButtonStyle & CSBS_MULTICHOOSE))
  295. {
  296. bool inside = bound.ContainsRel (Event.Mouse.x, Event.Mouse.y);
  297. if (inside != Pressed)
  298. SetPressed (inside);
  299. return true;
  300. } /* endif */
  301. return true;
  302. case csevKeyDown:
  303. return HandleKeyPress (Event);
  304. case csevKeyUp:
  305. if (app->KeyboardOwner)
  306. if (((underline_pos >= 0)
  307. && (UPPERCASE (Event.Key.Char) == UPPERCASE (text [underline_pos])))
  308. || ((Event.Key.Code == CSKEY_SPACE)
  309. && (GetState (CSS_FOCUSED))))
  310. {
  311. if (!(ButtonStyle & CSBS_MULTICHOOSE))
  312. SetPressed (false);
  313. Invalidate ();
  314. app->CaptureKeyboard (NULL);
  315. Press ();
  316. return true;
  317. }
  318. return false;
  319. } /* endswitch */
  320. return csComponent::HandleEvent (Event);
  321. }
  322. bool csButton::PostHandleEvent (iEvent &Event)
  323. {
  324. if (parent->GetState (CSS_FOCUSED)
  325. && GetState (CSS_VISIBLE)
  326. && (Event.Type == csevKeyDown))
  327. return HandleKeyPress (Event);
  328. return csComponent::PostHandleEvent (Event);
  329. }
  330. bool csButton::HandleKeyPress (iEvent &Event)
  331. {
  332. // Check hot key
  333. if (!GetState (CSS_DISABLED))
  334. if (((underline_pos >= 0)
  335. && (app->KeyboardOwner == NULL)
  336. && CheckHotKey (Event, text [underline_pos]))
  337. || ((GetState (CSS_FOCUSED))
  338. && (Event.Key.Code == CSKEY_SPACE)
  339. && (Event.Key.Modifiers & CSMASK_FIRST)
  340. && (!(Event.Key.Modifiers & (CSMASK_ALLSHIFTS - CSMASK_ALT)))))
  341. {
  342. if (!app->KeyboardOwner)
  343. app->CaptureKeyboard (this);
  344. SetPressed (true);
  345. if ((ButtonStyle & CSBS_NOKEYBOARDFOCUS) == 0)
  346. Select ();
  347. return true;
  348. }
  349. return false;
  350. }
  351. void csButton::DeselectNeighbours ()
  352. {
  353. csComponent *c = this;
  354. while (((c = c->next) != this)
  355. && !c->GetState (CSS_GROUP))
  356. c->SendCommand (cscmdButtonDeselect, this);
  357. if ((c != this) && (!GetState (CSS_GROUP)))
  358. {
  359. c = this;
  360. while ((c = c->prev) != this)
  361. {
  362. c->SendCommand (cscmdButtonDeselect, this);
  363. if (c->GetState (CSS_GROUP))
  364. break;
  365. } /* endwhile */
  366. } /* endif */
  367. }
  368. void csButton::SetPressed (bool state)
  369. {
  370. if ((ButtonStyle & CSBS_MULTICHOOSE)
  371. && state)
  372. DeselectNeighbours ();
  373. Pressed = state;
  374. if (parent)
  375. parent->SendCommand (Pressed ? cscmdButtonDown : cscmdButtonUp,
  376. (void *)this);
  377. Invalidate ();
  378. }
  379. void csButton::Press ()
  380. {
  381. if (ButtonStyle & CSBS_DISMISS)
  382. app->Dismiss (CommandCode);
  383. if (parent && CommandCode)
  384. parent->SendCommand (CommandCode, (void *)this);
  385. }
  386. void csButton::SetState (int mask, bool enable)
  387. {
  388. int oldstate = state;
  389. csComponent::SetState (mask, enable);
  390. if (((oldstate ^ state) & CSS_FOCUSED)
  391. || ((oldstate ^ state) & CSS_DISABLED))
  392. {
  393. if (((state & CSS_FOCUSED) == 0)
  394. && (app->KeyboardOwner == this))
  395. {
  396. SetPressed (false);
  397. if (app->KeyboardOwner == this)
  398. app->CaptureKeyboard (NULL);
  399. } /* endif */
  400. if ((state & CSS_DISABLED)
  401. && (app->MouseOwner))
  402. {
  403. if (app->MouseOwner == this)
  404. app->CaptureMouse (NULL);
  405. if (Pressed)
  406. if (!(ButtonStyle & CSBS_MULTICHOOSE))
  407. SetPressed (false);
  408. } /* endif */
  409. Invalidate ();
  410. }
  411. }
  412. void csButton::SuggestSize (int &w, int &h)
  413. {
  414. w = 0; h = 0;
  415. if (ImagePressed)
  416. {
  417. w = ImagePressed->Width ();
  418. h = ImagePressed->Height ();
  419. } /* endif */
  420. if (ImageNormal)
  421. {
  422. if (w < ImageNormal->Width ())
  423. w = ImageNormal->Width ();
  424. if (h < ImageNormal->Height ())
  425. h = ImageNormal->Height ();
  426. } /* endif */
  427. if (text)
  428. {
  429. int tw = TextWidth (text) + 8;
  430. int th = TextHeight () + 4;
  431. if (tw > w) w = tw;
  432. h += th;
  433. } /* endif */
  434. switch (FrameStyle)
  435. {
  436. case csbfsOblique:
  437. h += 6;
  438. w += (h / 3) * 2;
  439. break;
  440. case csbfsThickRect:
  441. w += 6;
  442. h += 6;
  443. break;
  444. case csbfsThinRect:
  445. w += 4;
  446. h += 4;
  447. break;
  448. case csbfsVeryThinRect:
  449. w += 1;
  450. h += 1;
  451. break;
  452. case csbfsNone:
  453. default:
  454. break;
  455. } /* endswitch */
  456. }