ColorSelector.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. //******************************************************************************
  2. //
  3. //
  4. // Copyright 2001, Be Incorporated
  5. //
  6. //******************************************************************************
  7. #if !B_BEOS_VERSION_DANO
  8. #include "ColorSwatch.h"
  9. #endif
  10. #include "ColorSelector.h"
  11. #include "Vision.h"
  12. #include <ColorControl.h>
  13. #include <MenuField.h>
  14. #include <MenuItem.h>
  15. #include <MenuBar.h>
  16. #include <PopUpMenu.h>
  17. #include <Screen.h>
  18. #include <StringView.h>
  19. #include <Window.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. namespace ColorControlPrivate {
  24. static inline bool CompareColors (rgb_color left, rgb_color right)
  25. {
  26. return !memcmp (&left, &right, sizeof(rgb_color));
  27. }
  28. enum {
  29. CMD_CHOOSE_UI_COLOR = 'cuic',
  30. CMD_SET_UI_COLOR = 'suic'
  31. };
  32. class ColorMenuItem : public BMenuItem {
  33. public:
  34. ColorMenuItem( const char* label, BMessage* msg,
  35. rgb_color color, rgb_color initial_color)
  36. : BMenuItem(label, msg)
  37. {
  38. fColor = color;
  39. fInitialColor = initial_color;
  40. }
  41. void ResetColors(rgb_color col, rgb_color initial)
  42. {
  43. if (!CompareColors(fColor, col) || !CompareColors (fInitialColor, initial)) {
  44. fColor = col;
  45. fInitialColor = initial;
  46. BMenu* parent = Menu();
  47. if (parent) parent->Invalidate(Frame());
  48. }
  49. }
  50. void SetColor(rgb_color col)
  51. {
  52. if (!CompareColors (fColor, col)) {
  53. fColor = col;
  54. BMenu* parent = Menu();
  55. if (parent) parent->Invalidate(Frame());
  56. }
  57. }
  58. rgb_color Color() const
  59. {
  60. return fColor;
  61. }
  62. rgb_color InitialColor() const
  63. {
  64. return fInitialColor;
  65. }
  66. virtual void DrawContent()
  67. {
  68. BRect b = Frame();
  69. BMenu *parent = Menu();
  70. BPoint loc = parent->PenLocation();
  71. enum {
  72. W_CHAR = 0,
  73. A_CHAR = 1,
  74. OPEN_CHAR = 2,
  75. CLOSE_CHAR = 3,
  76. SPACE_CHAR = 4,
  77. NUM_CHARS = 5
  78. };
  79. float escapements[NUM_CHARS];
  80. BFont font;
  81. parent->GetFont(&font);
  82. font.GetEscapements("WA() ", NUM_CHARS, escapements);
  83. for (int32 i=0; i<NUM_CHARS; i++) {
  84. escapements[i] *= font.Size();
  85. }
  86. const float blockWidth = escapements[W_CHAR]+escapements[A_CHAR];
  87. const rgb_color old_col = parent->HighColor();
  88. font_height fh;
  89. const bool showInitial = !CompareColors(fInitialColor, fColor);
  90. b.InsetBy(1, 1);
  91. b.bottom -= 1;
  92. b.left = loc.x;
  93. if (showInitial) {
  94. parent->GetFontHeight(&fh);
  95. parent->DrawString("(", BPoint(b.left, loc.y+fh.ascent));
  96. }
  97. b.left += escapements[OPEN_CHAR];
  98. b.InsetBy(2, 2);
  99. b.right = b.left + escapements[W_CHAR];
  100. if (showInitial) {
  101. parent->SetHighColor(fInitialColor);
  102. parent->FillRect(b);
  103. }
  104. b.InsetBy(-1, -1);
  105. if (showInitial) {
  106. parent->SetHighColor(old_col);
  107. parent->StrokeRect(b);
  108. }
  109. b.InsetBy(-1, -1);
  110. if (showInitial) {
  111. parent->DrawString(")", BPoint(b.right+1, loc.y+fh.ascent));
  112. }
  113. b.right += escapements[CLOSE_CHAR] + 1;
  114. b.left = b.right + escapements[SPACE_CHAR];
  115. b.right = b.left + blockWidth;
  116. parent->SetHighColor(fColor);
  117. parent->FillRect(b);
  118. parent->SetHighColor(old_col);
  119. b.InsetBy(-1, -1);
  120. parent->StrokeRect(b);
  121. parent->MovePenTo(b.right + escapements[SPACE_CHAR]*2 + 2, loc.y);
  122. BMenuItem::DrawContent();
  123. }
  124. virtual void GetContentSize(float *w, float *h)
  125. {
  126. BMenuItem::GetContentSize(w, h);
  127. *w += Menu()->StringWidth("(W) WA ")+4 + 2;
  128. }
  129. private:
  130. rgb_color fColor, fInitialColor;
  131. };
  132. }
  133. using namespace ColorControlPrivate;
  134. static void populate_colors(BMenu* dest, const BMessage& src,
  135. const BMessage& names, const BMessage* initial)
  136. {
  137. type_code type;
  138. int32 n;
  139. ssize_t size;
  140. rgb_color *col;
  141. const char *name;
  142. src.GetInfo ("color", &type, &n);
  143. for (int32 j = 0; j < n; j++) {
  144. names.FindString ("color", j, &name);
  145. if (src.FindData ("color", B_RGB_COLOR_TYPE, j, (const void **)(&col), &size) == B_OK)
  146. {
  147. // See if this field already exists in the menu.
  148. const int32 k = dest->CountItems();
  149. int32 i;
  150. bool found = false;
  151. for (i=0; i<k; i++) {
  152. BMenuItem* it = dest->ItemAt(i);
  153. const char* field;
  154. if (it && it->Message() &&
  155. it->Message()->FindString("field", &field) == B_OK
  156. && strcmp(field, name) == 0) {
  157. ColorMenuItem* ci = dynamic_cast<ColorMenuItem*>(it);
  158. if (ci) ci->SetColor(*col);
  159. found = true;
  160. break;
  161. }
  162. }
  163. if (found) continue;
  164. // This color doesn't currently exist; add it in.
  165. BMessage* msg = new BMessage(CMD_CHOOSE_UI_COLOR);
  166. msg->AddString("field", name);
  167. msg->AddInt32("index", j);
  168. const char* label = name;
  169. // Alphabetical order.
  170. for (i=0; i<n; i++) {
  171. BMenuItem* it = dest->ItemAt(i);
  172. if (it && strcmp(it->Label(), label) > 0)
  173. break;
  174. }
  175. rgb_color *init_col;
  176. if (!initial || initial->FindData ("color", B_RGB_COLOR_TYPE, j,
  177. (const void **)&init_col, &size) != B_OK)
  178. *init_col = *col;
  179. ColorMenuItem* ci = new ColorMenuItem(label, msg, *col, *init_col);
  180. dest->AddItem(ci);
  181. }
  182. }
  183. }
  184. enum {
  185. FRAME = 5,
  186. SPACE = 5
  187. };
  188. ColorSelector::ColorSelector( BRect frame, const char* name,
  189. const char* label,
  190. const BMessage& colors, const BMessage& names,
  191. BMessage* model,
  192. uint32 resizeMask, uint32 flags)
  193. : BControl(frame, name, label, model, resizeMask, flags),
  194. fNames(names), fInitColors(colors), fColors(colors), fSizeValid(false)
  195. {
  196. const BRect dummyRect(-100, -100, -10, -10);
  197. fColorMenu = new BPopUpMenu("Colors");
  198. populate_colors(fColorMenu, fColors, fNames, &fInitColors);
  199. fColorField = new BMenuField(dummyRect, "Color", "Color: ", fColorMenu,
  200. B_FOLLOW_LEFT | B_FOLLOW_TOP,
  201. B_WILL_DRAW|B_FRAME_EVENTS|B_NAVIGABLE);
  202. AddChild(fColorField);
  203. fColorField->SetFont(be_bold_font);
  204. fColorPalette = new BColorControl(dummyRect.LeftTop(), B_CELLS_32x8, 8,
  205. "Palette", new BMessage(CMD_SET_UI_COLOR),
  206. true);
  207. #if B_BEOS_VERSION_DANO
  208. fColorPalette->SetModeFlags(B_CC_32BIT_MODE | B_CC_SHOW_SWATCH);
  209. fColorPalette->SetDoubleBuffering (B_UPDATE_INVALIDATED | B_UPDATE_RESIZED | B_UPDATE_EXPOSED);
  210. #else
  211. rgb_color *color (NULL);
  212. ssize_t size (0);
  213. fColors.FindData ("color", B_RGB_COLOR_TYPE, 0, (const void **)(&color), &size);
  214. swatch = new ColorSwatch (dummyRect, "swatch", *color);
  215. AddChild (swatch);
  216. #endif
  217. AddChild(fColorPalette);
  218. }
  219. ColorSelector::~ColorSelector()
  220. {
  221. }
  222. void ColorSelector::ExtractColors(BMessage* dest, const BMessage& src)
  223. {
  224. type_code type;
  225. int32 n;
  226. src.GetInfo ("color", &type, &n);
  227. for (int32 i=0; i<n; i++)
  228. {
  229. const void* data;
  230. ssize_t size;
  231. if (src.FindData("color", B_RGB_COLOR_TYPE, i, &data, &size) == B_OK
  232. && size == sizeof(rgb_color))
  233. dest->AddData("color", B_RGB_COLOR_TYPE, data, size, true, i==0 ? n : 1);
  234. }
  235. }
  236. void ColorSelector::AttachedToWindow()
  237. {
  238. BControl::AttachedToWindow();
  239. BMessenger me(this);
  240. fColorPalette->SetTarget(me);
  241. fColorMenu->SetTargetForItems(me);
  242. BMenuItem* it = fColorMenu->ItemAt(0);
  243. if (it)
  244. {
  245. it->SetMarked(true);
  246. dynamic_cast<BInvoker *>(it)->Invoke();
  247. }
  248. #if B_BEOS_VERSION_DANO
  249. LayoutViews(true);
  250. #endif
  251. }
  252. void ColorSelector::AllAttached()
  253. {
  254. BControl::AllAttached ();
  255. LayoutViews(true);
  256. }
  257. void ColorSelector::LayoutViews(bool really)
  258. {
  259. float mw, mh, cw, ch;
  260. fColorField->SetDivider(fColorField->StringWidth(fColorField->Label()) + 5);
  261. fColorField->GetPreferredSize(&mw, &mh);
  262. fColorPalette->GetPreferredSize(&cw, &ch);
  263. if (really) {
  264. BRect b(Bounds());
  265. if (Window()) Window()->BeginViewTransaction();
  266. fColorField->MoveTo(b.left, b.top);
  267. fColorField->ResizeTo(b.Width()+1, mh);
  268. #if !B_BEOS_VERSION_DANO
  269. fColorField->MenuBar()->SetMaxContentWidth(99999999);
  270. #endif
  271. fColorPalette->MoveTo(b.left, b.top+mh+SPACE);
  272. fColorPalette->ResizeTo(cw, ch);
  273. #if !B_BEOS_VERSION_DANO
  274. swatch->MoveTo (fColorPalette->Bounds().Width() + 5, b.top+mh+SPACE);
  275. swatch->ResizeTo (ch, ch);
  276. #endif
  277. if (Window()) Window()->EndViewTransaction();
  278. }
  279. #if B_BEOS_VERSION_DANO
  280. fPrefWidth = (mw > cw ? mw : cw);
  281. #else
  282. fPrefWidth = (mw > cw ? mw : cw) + 5 + swatch->Bounds().Width();
  283. #endif
  284. fPrefHeight = mh + SPACE + ch;
  285. fSizeValid = true;
  286. }
  287. void ColorSelector::MessageReceived(BMessage *msg)
  288. {
  289. if (msg->WasDropped()) {
  290. rgb_color *color;
  291. ssize_t size;
  292. if (msg->FindData ("RGBColor", B_RGB_COLOR_TYPE, (const void **)&color,
  293. &size) == B_OK) {
  294. if (fColorPalette) {
  295. fColorPalette->SetValue(*color);
  296. #if !B_BEOS_VERSION_DANO
  297. swatch->SetColor (*color);
  298. #endif
  299. fColorPalette->Invoke();
  300. }
  301. } else {
  302. BControl::MessageReceived(msg);
  303. }
  304. return;
  305. }
  306. switch (msg->what) {
  307. case CMD_CHOOSE_UI_COLOR: {
  308. const char* field;
  309. int32 index (0);
  310. ssize_t size;
  311. if (msg->FindString("field", &field) == B_OK) {
  312. msg->FindInt32 ("index", &index);
  313. fCurrentField = field;
  314. rgb_color *color;
  315. if (fColors.FindData ("color", B_RGB_COLOR_TYPE, index,
  316. (const void **)(&color), &size) == B_OK) {
  317. fColorPalette->SetValue(*color);
  318. #if !B_BEOS_VERSION_DANO
  319. swatch->SetColor (*color);
  320. #endif
  321. }
  322. }
  323. } break;
  324. case CMD_SET_UI_COLOR: {
  325. if (Message()) {
  326. BMessage upd(*Message());
  327. BMessage colors;
  328. int32 index;
  329. rgb_color c = fColorPalette->ValueAsColor();
  330. #if !B_BEOS_VERSION_DANO
  331. swatch->SetColor (c);
  332. #endif
  333. ColorMenuItem *item ((ColorMenuItem *)(fColorMenu->FindItem (fCurrentField.String())));
  334. if (item)
  335. {
  336. BMessage *curMsg (item->Message());
  337. curMsg->FindInt32 ("index", &index);
  338. }
  339. c.alpha = 255;
  340. colors.AddData ("color", B_RGB_COLOR_TYPE, &c, sizeof(rgb_color));
  341. colors.AddInt32 ("index", index);
  342. vision_app->SetColor (index, c);
  343. Update (colors);
  344. Invoke(&upd);
  345. }
  346. } break;
  347. default:
  348. BControl::MessageReceived(msg);
  349. break;
  350. }
  351. }
  352. void ColorSelector::FrameResized(float, float)
  353. {
  354. LayoutViews(true);
  355. }
  356. void ColorSelector::GetPreferredSize(float* width, float* height)
  357. {
  358. if (!fSizeValid)
  359. LayoutViews(false);
  360. *width = fPrefWidth;
  361. *height = fPrefHeight;
  362. }
  363. /*------------------------------------------------------------*/
  364. bool ColorSelector::IsDirty() const
  365. {
  366. bool dirty = false;
  367. type_code type;
  368. int32 n;
  369. fInitColors.GetInfo ("color", &type, &n);
  370. for (int32 i=0; i<n; i++) {
  371. const void* data1;
  372. const void* data2;
  373. ssize_t size1;
  374. ssize_t size2;
  375. if (fInitColors.FindData("color", B_RGB_COLOR_TYPE, i, &data1, &size1) == B_OK &&
  376. ( fColors.FindData("color", B_RGB_COLOR_TYPE, i, &data2, &size2) != B_OK ||
  377. size1 != size2 || memcmp(data1, data2, size1) != 0)) {
  378. dirty = true;
  379. break;
  380. }
  381. }
  382. return dirty;
  383. }
  384. void ColorSelector::SetTo(const BMessage& colors)
  385. {
  386. fInitColors.MakeEmpty();
  387. ExtractColors(&fInitColors, colors);
  388. fColors = fInitColors;
  389. fColorMenu->RemoveItems(0, fColorMenu->CountItems(), true);
  390. populate_colors(fColorMenu, fColors, fNames, &fInitColors);
  391. if (Window()) ColorSelector::AttachedToWindow();
  392. }
  393. void ColorSelector::Update(const BMessage& changes)
  394. {
  395. int32 index (0);
  396. ssize_t size (0);
  397. rgb_color *color;
  398. changes.FindInt32 ("index", &index);
  399. changes.FindData ("color", B_RGB_COLOR_TYPE, (const void **)(&color), &size);
  400. fColors.ReplaceData ("color", B_RGB_COLOR_TYPE, index, color, sizeof(rgb_color));
  401. populate_colors(fColorMenu, fColors, fNames, &fInitColors);
  402. ColorMenuItem *item ((ColorMenuItem *)(fColorMenu->FindItem (fCurrentField.String())));
  403. if (item)
  404. {
  405. BMessage *curMsg (item->Message());
  406. curMsg->FindInt32 ("index", &index);
  407. }
  408. if (fColors.FindData ("color", B_RGB_COLOR_TYPE, index,
  409. (const void **)(&color), &size) == B_OK) {
  410. fColorPalette->SetValue(*color);
  411. #if !B_BEOS_VERSION_DANO
  412. swatch->SetColor (*color);
  413. #endif
  414. }
  415. }
  416. void ColorSelector::Revert()
  417. {
  418. // duplicate the message since SetTo destroys fInitColors
  419. BMessage OriginalColors = fInitColors;
  420. SetTo (OriginalColors);
  421. rgb_color *color;
  422. ssize_t size (0);
  423. for (int32 i = 0; i < MAX_COLORS; i++)
  424. if (fInitColors.FindData ("color", B_RGB_COLOR_TYPE, i, (const void **)(&color), &size) == B_OK)
  425. if (!CompareColors (*color, vision_app->GetColor (i)))
  426. vision_app->SetColor (i, *color);
  427. }
  428. const BMessage& ColorSelector::CurrentColors() const
  429. {
  430. return fColors;
  431. }
  432. const BMessage& ColorSelector::InitialColors() const
  433. {
  434. return fInitColors;
  435. }
  436. /*------------------------------------------------------------*/
  437. /*------------------------------------------------------------*/