buttbar.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "precomp.h"
  2. //PORTABLE
  3. #include <bfc/wasabi_std.h>
  4. #include <api/wnd/wndclass/buttbar.h>
  5. #include <api/wnd/notifmsg.h>
  6. #include <api/wnd/wndclass/buttwnd.h>
  7. #include <api/wnd/popup.h>
  8. #include <api/script/objects/c_script/c_text.h>
  9. #include <api/script/objects/c_script/h_button.h>
  10. class ButtHooker : public H_Button {
  11. public:
  12. ButtHooker(ButtBar *hangout, ScriptObject *butt) : bb(hangout), H_Button(butt) { }
  13. void hook_onLeftClick() {
  14. bb->onLeftPush(0, 0);
  15. }
  16. private:
  17. ButtBar *bb;
  18. };
  19. ButtBar::ButtBar(int resizemode) {
  20. spacer = 0;
  21. resize_mode = resizemode;
  22. hooker = NULL;
  23. if (resize_mode == STACK) {
  24. setContent(L"wasabi.buttonbar.stack");
  25. }
  26. }
  27. ButtBar::~ButtBar() {
  28. buttons.deleteAll();
  29. delete hooker;
  30. }
  31. void ButtBar::setResizeMode(int resizemode) {
  32. if (resize_mode == resizemode) return;
  33. resize_mode = resizemode;
  34. if (isPostOnInit()) onResize();
  35. }
  36. int ButtBar::onInit() {
  37. int i;
  38. BUTTBAR_PARENT::onInit();
  39. // create the buttons
  40. for (i = 0; i < buttons.getNumItems(); i++) {
  41. buttons[i]->init(this);
  42. if (resize_mode == STACK) {
  43. if (i != 0) buttons[i]->setVisible(FALSE);
  44. if (i == 0) setGroupLabel(buttons[i]->getButtonText());
  45. }
  46. }
  47. return 1;
  48. }
  49. int ButtBar::addChild(ButtonWnd *child) {
  50. buttons.addItem(child);
  51. if (isInited()) {
  52. child->init(this);
  53. child->setParent(this);
  54. onResize();
  55. if (buttons.getNumItems() == 1)
  56. setGroupLabel(child->getButtonText());
  57. }
  58. return 1;
  59. }
  60. int ButtBar::removeChild(ButtonWnd *child) {
  61. if (!buttons.haveItem(child)) return 0;
  62. if (isInited()) onResize();
  63. return 1;
  64. }
  65. int ButtBar::getNumChildren() {
  66. return buttons.getNumItems();
  67. }
  68. ButtonWnd *ButtBar::enumChild(int n) {
  69. return buttons[n];
  70. }
  71. int ButtBar::getWidth() {
  72. int w = 0;
  73. for (int i = 0; i < buttons.getNumItems(); i++) {
  74. w += buttons[i]->getWidth()+spacer;
  75. }
  76. return w;
  77. }
  78. int ButtBar::getHeight() {
  79. if (resize_mode == STACK) {
  80. ifc_window *rw = getContentRootWnd();
  81. return rw->getPreferences(SUGGESTED_H);
  82. } else {
  83. int h = 0;
  84. for (int i = 0; i < buttons.getNumItems(); i++) {
  85. h = MAX(h, buttons[i]->getHeight()+1);
  86. }
  87. return h;
  88. }
  89. }
  90. void ButtBar::onLeftPush(int x, int y)
  91. {
  92. if (resize_mode == STACK)
  93. {
  94. PopupMenu pop(this);
  95. foreach(buttons)
  96. pop.addCommand(buttons.getfor()->getButtonText(), foreach_index);
  97. endfor
  98. int r = pop.popAnchored();
  99. if (r >= 0) {
  100. buttons[r]->onLeftPush(0, 0);
  101. setGroupLabel(buttons[r]->getButtonText());
  102. }
  103. }
  104. }
  105. int ButtBar::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2) {
  106. switch (msg) {
  107. case ChildNotify::BUTTON_LEFTPUSH: {
  108. int ret;
  109. if (ret = onLeftPush(child->getNotifyId())) {
  110. return ret;
  111. } else {
  112. // This won't fit the current notification schema.
  113. // We _must_ change it -- too many interfaces assume that the
  114. // button notification is called back through the parent.
  115. // return notifyParent(msg, p1, p2);
  116. // So, I made a new basewnd method passNotifyUp() to defer a notification
  117. // to the current object's notification target.
  118. return passNotifyUp(child, msg, p1, p2);
  119. }
  120. }
  121. break;
  122. }
  123. return BUTTBAR_PARENT::childNotify(child, msg, p1, p2);
  124. }
  125. int ButtBar::onResize() {
  126. BUTTBAR_PARENT::onResize(); // calling your parent is good(tm) =)
  127. if (!isPostOnInit()) return 0; // that's just an optim, in case someone's dumb and calling us directly when it shouldnt
  128. switch (resize_mode) {
  129. case NORMAL: {
  130. RECT r = clientRect();
  131. int height = r.bottom - r.top;
  132. int x = r.left;
  133. for (int i = 0; i < buttons.getNumItems(); i++) {
  134. int w = buttons[i]->getWidth()+spacer;
  135. buttons[i]->resize(x, r.top, w, height);
  136. x += w;
  137. if (x > r.right) break;
  138. }
  139. }
  140. break;
  141. case STRETCH: {
  142. if (buttons.getNumItems() > 0) {
  143. RECT r = clientRect();
  144. int height = r.bottom - r.top;
  145. int w = (r.right - r.left) / buttons.getNumItems();
  146. int x = r.left;
  147. for (int i = 0; i < buttons.getNumItems(); i++) {
  148. if (i == buttons.getNumItems()-1) w = (r.right - r.left) - x;
  149. buttons[i]->resize(x, r.top, w, height);
  150. x += w;
  151. }
  152. }
  153. }
  154. break;
  155. case STACK: // no point
  156. break;
  157. }
  158. return 1;
  159. }
  160. int ButtBar::onPaint(Canvas *canvas) {
  161. ASSERT(canvas != NULL);
  162. if (resize_mode != STACK) {
  163. BUTTBAR_PARENT::onPaint(canvas);
  164. renderBaseTexture(canvas, clientRect());
  165. }
  166. return 1;
  167. }
  168. void ButtBar::setGroupLabel(const wchar_t *l) {
  169. setName(l);
  170. onNewContent();
  171. }
  172. void ButtBar::onNewContent()
  173. {
  174. if (resize_mode != STACK) return;
  175. ScriptObject *text = findScriptObject(L"buttonbar.text");
  176. if (text == NULL) return;
  177. C_Text(text).setText(getNameSafe(L"no tabs"));
  178. // hook the clicks
  179. delete hooker;
  180. ScriptObject *mousetrap = findScriptObject(L"mousetrap");
  181. hooker = new ButtHooker(this, mousetrap);
  182. }