Bug Summary

File:home/HaikuArchives/ArtPaint/artpaint/controls/ColorPalette.cpp
Warning:line 676, column 12
Although the value stored to 'bytes_read' is used in the enclosing expression, the value is never actually read from 'bytes_read'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-haiku -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ColorPalette.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /boot/system/lib/clang/12.0.1 -iquote ./ -iquote artpaint/ -iquote artpaint/Utilities/ -iquote artpaint/application/ -iquote artpaint/controls/ -iquote artpaint/layers/ -iquote artpaint/paintwindow/ -iquote artpaint/tools/ -iquote artpaint/viewmanipulators/ -iquote artpaint/windows/ -iquote objects_artpaint/ -isystem /boot/system/develop/headers/private/interface -internal-isystem /system/develop/headers/c++ -internal-isystem /system/develop/headers/c++/x86_64-unknown-haiku -internal-isystem /system/develop/headers/c++/backward -O3 -fdeprecated-macro -fdebug-compilation-dir /boot/home/HaikuArchives/ArtPaint -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2022-06-19-103017-1294-1 -x c++ artpaint/controls/ColorPalette.cpp
1/*
2 * Copyright 2003, Heikki Suhonen
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Heikki Suhonen <heikki.suhonen@gmail.com>
7 * Dale Cieslak <dcieslak@yahoo.com>
8 *
9 */
10
11#include "ColorPalette.h"
12
13#include "CMYControl.h"
14#include "FileIdentificationStrings.h"
15#include "FilePanels.h"
16#include "FloaterManager.h"
17#include "HSVControl.h"
18#include "MessageConstants.h"
19#include "MessageFilters.h"
20#include "Patterns.h"
21#include "PaintApplication.h"
22#include "PaletteWindowClient.h"
23#include "ResourceServer.h"
24#include "RGBControl.h"
25#include "SettingsServer.h"
26#include "StatusView.h"
27#include "UtilityClasses.h"
28#include "YIQControl.h"
29#include "YUVControl.h"
30
31
32#include <Alert.h>
33#include <Bitmap.h>
34#include <Catalog.h>
35#include <FilePanel.h>
36#include <MenuBar.h>
37#include <MenuItem.h>
38#include <NodeInfo.h>
39#include <Path.h>
40#include <PictureButton.h>
41#include <Resources.h>
42#include <Roster.h>
43#include <TextControl.h>
44
45
46#include <stdlib.h>
47#include <string.h>
48
49
50#undef B_TRANSLATION_CONTEXT"ColorPalette"
51#define B_TRANSLATION_CONTEXT"ColorPalette" "ColorPalette"
52
53
54// Initialize the static variable to NULL.
55ColorPaletteWindow* ColorPaletteWindow::palette_window = NULL__null;
56BList* ColorPaletteWindow::master_window_list = new BList();
57BList* ColorPaletteWindow::palette_window_clients = new BList();
58
59
60ColorPaletteWindow::ColorPaletteWindow(BRect frame, int32 mode)
61 : BWindow(frame, B_TRANSLATE("Colors")BLocaleRoster::Default()->GetCatalog()->GetString(("Colors"
), "ColorPalette")
,
62 B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NOT_RESIZABLE |
63 B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FRONT)
64 , open_panel(NULL__null)
65 , save_panel(NULL__null)
66{
67 // here we just record the mode that user has requested
68 // for displaying the controls (eg. RGBA, HSV, something else)
69 selector_mode = mode;
70
71 color_control = NULL__null;
72 color_slider = NULL__null;
73
74 window_feel feel = B_NORMAL_WINDOW_FEEL;
75 if (SettingsServer* server = SettingsServer::Instance()) {
76 server->SetValue(SettingsServer::Application, skPaletteWindowVisible,
77 true);
78
79 BMessage settings;
80 if (server->GetApplicationSettings(&settings) == B_OK((int)0))
81 settings.FindInt32(skPaletteWindowFeel, (int32*)&feel);
82 }
83 SetFeel(feel);
84
85 window_look look = B_FLOATING_WINDOW_LOOK;
86 if (feel == B_NORMAL_WINDOW_FEEL)
87 look = B_TITLED_WINDOW_LOOK;
88 SetLook(look);
89
90 openMenuBar();
91 // call some function that initializes the views depending on the mode
92 if (!openControlViews(mode)) {
93 // if for some reason view opening did not succeed we delete all of them
94 // that were created
95 deleteControlViews(mode);
96 } else {
97 // we can assume that everything went OK show ourselves on screen
98 Show();
99 }
100
101 if (Lock()) {
102 AddCommonFilter(new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE,
103 B_MOUSE_DOWN, window_activation_filter));
104 AddCommonFilter(new BMessageFilter(B_KEY_DOWN,AppKeyFilterFunction));
105 Unlock();
106 }
107
108 palette_window = this;
109 FloaterManager::AddFloater(this);
110}
111
112
113ColorPaletteWindow::~ColorPaletteWindow()
114{
115 delete open_panel;
116 delete save_panel;
117
118 if (SettingsServer* server = SettingsServer::Instance()) {
119 server->SetValue(SettingsServer::Application, skPaletteWindowFrame,
120 Frame());
121 server->SetValue(SettingsServer::Application, skPaletteWindowVisible,
122 false);
123 server->SetValue(SettingsServer::Application, skPaletteColorMode,
124 selector_mode);
125 }
126
127 FloaterManager::RemoveFloater(this);
128 palette_window = NULL__null;
129}
130
131
132void ColorPaletteWindow::MessageReceived(BMessage *message)
133{
134 // this path is used when getting the applications path to save
135 // the palettes. It must be defined here instead of inside the
136 // switch-clause
137 BPath path;
138 BMessage *color_message;
139 rgb_color color;
140 int32 buttons;
141
142 switch (message->what) {
143
144 // this comes from the HSColorControl object and indicates that it's value has changed
145 case HS_COLOR_CONTROL_INVOKED'CCIn':
146 // send message to each container
147 // message should contain the index of that color in color-set
148 // this should only be done if the color_container is in edit-mode
149 // and set the current color in the set for that color too
150 color_message = new BMessage(HS_COLOR_CHANGED'CoCH');
151 color_message->AddInt32("index",ColorSet::currentSet()->currentColorIndex());
152 // For some reason the alpha channel needs to be forced to 255
153 color = color_control->ValueAsColor();
154 color.alpha = 255;
155 ColorSet::currentSet()->setCurrentColor(color);
156 ColorContainer::sendMessageToAllContainers(color_message);
157 SelectedColorsView::sendMessageToAll(color_message);
158
159 // also change the color for mousebutton that was used
160 message->FindInt32("buttons",&buttons);
161 if (buttons & B_PRIMARY_MOUSE_BUTTON)
162 ((PaintApplication*)be_app)->SetColor(color, TRUE1);
163 else
164 ((PaintApplication*)be_app)->SetColor(color, FALSE0);
165
166 InformClients(ColorSet::currentSet()->currentColor());
167 break;
168
169 // This comes from the RGBControl-object and indicates that it's value has changed.
170 // This might also come from CMYControl, YIQControl ...
171 case HS_RGB_CONTROL_INVOKED'RGIn':
172 // send message to each container
173 // message should contain the index of that color in color-set
174 // this should only be done if the color_container is in edit-mode
175 // and set the current color in the set for that color too
176 color_message = new BMessage(HS_COLOR_CHANGED'CoCH');
177 color_message->AddInt32("index",ColorSet::currentSet()->currentColorIndex());
178 ColorSet::currentSet()->setCurrentColor(color_slider->ValueAsColor());
179 ColorContainer::sendMessageToAllContainers(color_message);
180 SelectedColorsView::sendMessageToAll(color_message);
181
182 // also change the color for mousebutton that was used
183 message->FindInt32("buttons",&buttons);
184 if (buttons & B_PRIMARY_MOUSE_BUTTON)
185 ((PaintApplication*)be_app)->SetColor(color_slider->ValueAsColor(),TRUE1);
186 else
187 ((PaintApplication*)be_app)->SetColor(color_slider->ValueAsColor(),FALSE0);
188
189 InformClients(ColorSet::currentSet()->currentColor());
190 break;
191
192 // this comes from the menubar->"Set"->"New Palette"->"N" and indicates that a new
193 // palette-set should be created, the "colors"-parameter tells us how many colors the
194 // new set has
195 case HS_NEW_PALETTE_CREATED'NPaC':
196 new ColorSet(message->FindInt32("colors"));
197 // inform the color-containers about change
198 ColorContainer::sendMessageToAllContainers(new BMessage(HS_PALETTE_CHANGED'PaCh'));
199 // here change the name view to display sets name
200 if (ColorSet::numberOfSets() > 1) {
201 menu_bar->FindItem(HS_DELETE_PALETTE'DePa')->SetEnabled(TRUE1);
202 }
203 break;
204
205 // this comes from the menubar->"Set"->"Delete Current Set" and indicates that the current
206 // set should be deleted
207 case HS_DELETE_PALETTE'DePa':
208 // check if there are any more sets left
209 if (ColorSet::numberOfSets() >= 2) {
210 // first delete ourselves
211 delete ColorSet::currentSet();
212 // inform the color-containers about change
213 ColorContainer::sendMessageToAllContainers(new BMessage(HS_PALETTE_CHANGED'PaCh'));
214 // here change the name view to display sets name
215 if (ColorSet::numberOfSets() <= 1) {
216 menu_bar->FindItem(HS_DELETE_PALETTE'DePa')->SetEnabled(FALSE0);
217 }
218 }
219 else {
220 (new BAlert("", B_TRANSLATE("Cannot delete the only color set.")BLocaleRoster::Default()->GetCatalog()->GetString(("Cannot delete the only color set."
), "ColorPalette")
,
221 B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "ColorPalette")
))->Go();
222 }
223 break;
224
225 // this comes from a button that is named "next set button", the button is in this window
226 // the message indicates that we should change the colorcontainers to display next color set
227 case HS_NEXT_PALETTE'NxPl':
228 // change the entry in palette list
229 ColorSet::moveToNextSet();
230 // inform all color-containers about palette-change
231 ColorContainer::sendMessageToAllContainers(new BMessage(HS_PALETTE_CHANGED'PaCh'));
232 break;
233
234 // this comes from a button that is named "previous set button", the button is in this window
235 // the message indicates that we should change the colorcontainers to display previous color set
236 case HS_PREVIOUS_PALETTE'PrPl':
237 // change the entry in palette list
238 ColorSet::moveToPrevSet();
239 // inform all color-containers about palette-change
240 ColorContainer::sendMessageToAllContainers(new BMessage(HS_PALETTE_CHANGED'PaCh'));
241 break;
242
243 // this is sent from ColorContainer::MouseDown and it's purpose is to
244 // let us change the corresponding color to the color-controller also
245 case HS_PALETTE_SELECTION_CHANGED'PslC':
246 // update the color controller to display this new color
247 // only should do it if container is in edit mode
248 if (color_control != NULL__null)
249 color_control->SetValue(ColorSet::currentSet()->currentColor());
250 if (color_slider != NULL__null)
251 color_slider->SetValue(ColorSet::currentSet()->currentColor());
252 InformClients(ColorSet::currentSet()->currentColor());
253 break;
254
255 // this comes from the menubar->"Set"->"Open Set" and indicates that
256 // a file panel should be opened for the purpose of loading new set
257 case HS_SHOW_PALETTE_OPEN_PANEL'SpOp':
258 // here we must open the file-panel for loading
259 // here get the path for palette-files, should be made relative to apps directory
260 // or maybe remember the directory from last use
261
262 if (open_panel == NULL__null) {
263 // here we get the home directory of the application
264 PaintApplication::HomeDirectory(path);
265
266 // force normalization of the path to check validity
267 if (path.Append("Palette sets/",TRUE1) != B_OK((int)0)) {
268 PaintApplication::HomeDirectory(path);
269 }
270
271 entry_ref ref;
272 get_ref_for_path(path.Path(), &ref);
273
274 BMessenger target(this);
275 BMessage message(HS_PALETTE_OPEN_REFS'PaOr');
276 open_panel = new BFilePanel(B_OPEN_PANEL, &target, &ref,
277 B_FILE_NODE, true, &message);
278 }
279 open_panel->Window()->SetTitle(B_TRANSLATE("ArtPaint: Open color set" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("ArtPaint: Open color set"
"\xE2\x80\xA6"), "ColorPalette")
);
280 set_filepanel_strings(open_panel);
281 open_panel->Show();
282 break;
283
284 // this comes from the menubar->"Set"->"Save Set" and indicates that
285 // a file panel should be opened for the purpose of saving current set
286 case HS_SHOW_PALETTE_SAVE_PANEL'SpSp':
287 // here we must open the file-panel for saving
288 if (save_panel == NULL__null) {
289 // get the home directory of the app
290 PaintApplication::HomeDirectory(path);
291
292 // force normalization of the path to check validity
293 if (path.Append("Palette sets/",TRUE1) != B_OK((int)0)) {
294 PaintApplication::HomeDirectory(path);
295 }
296 // convert it to entry_ref
297 entry_ref ref;
298 get_ref_for_path(path.Path(), &ref);
299
300 BMessenger target(this);
301 BMessage message(HS_PALETTE_SAVE_REFS'PaSr');
302 save_panel = new BFilePanel(B_SAVE_PANEL, &target, &ref, 0, false,
303 &message);
304 }
305 save_panel->SetSaveText(ColorSet::currentSet()->getName());
306 save_panel->Window()->SetTitle(B_TRANSLATE("ArtPaint: Open color set" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("ArtPaint: Open color set"
"\xE2\x80\xA6"), "ColorPalette")
);
307 set_filepanel_strings(save_panel);
308 save_panel->Show();
309 break;
310
311 // this comes from the open_panel or the applocation-object and includes refs for
312 // the palette-files that should be loaded
313 case HS_PALETTE_OPEN_REFS'PaOr':
314 handlePaletteLoad(message);
315
316 // inform all color containers that palette has changed
317 ColorContainer::sendMessageToAllContainers(new BMessage(HS_PALETTE_CHANGED'PaCh'));
318 if (ColorSet::numberOfSets() > 1) {
319 menu_bar->FindItem(HS_DELETE_PALETTE'DePa')->SetEnabled(TRUE1);
320 }
321 break;
322
323 // this comes from the save_panel and indicates that current set should be saved
324 // to the file that the "refs" indicate
325 case HS_PALETTE_SAVE_REFS'PaSr':
326 handlePaletteSave(message);
327 break;
328
329 // this comes from the menubar->"Mode"->"RGB-Mode" and indicates that
330 // the color selector should be changed to a RGBControl, this is used
331 // also for other purposes than just a message-constant
332 case HS_RGB_COLOR_MODE:
333 if (selector_mode != HS_RGB_COLOR_MODE) {
334 deleteControlViews(selector_mode);
335 selector_mode = HS_RGB_COLOR_MODE;
336 openControlViews(HS_RGB_COLOR_MODE);
337 }
338 break;
339
340 // this comes from the menubar->"Mode"->"CMY-Mode" and indicates that
341 // the color selector should be changed to a RGBControl, this is used
342 // also for other purposes than just a message-constant
343 case HS_CMY_COLOR_MODE:
344 if (selector_mode != HS_CMY_COLOR_MODE) {
345 deleteControlViews(selector_mode);
346 selector_mode = HS_CMY_COLOR_MODE;
347 openControlViews(HS_CMY_COLOR_MODE);
348 }
349 break;
350
351 // this comes from the menubar->"Mode"->"YIQ-Mode" and indicates that
352 // the color selector should be changed to a RGBControl, this is used
353 // also for other purposes than just a message-constant
354 case HS_YIQ_COLOR_MODE:
355 if (selector_mode != HS_YIQ_COLOR_MODE) {
356 deleteControlViews(selector_mode);
357 selector_mode = HS_YIQ_COLOR_MODE;
358 openControlViews(HS_YIQ_COLOR_MODE);
359 }
360 break;
361
362 // this comes from the menubar->"Mode"->"YUV-Mode" and indicates that
363 // the color selector should be changed to a RGBControl, this is used
364 // also for other purposes than just a message-constant
365 case HS_YUV_COLOR_MODE:
366 if (selector_mode != HS_YUV_COLOR_MODE) {
367 deleteControlViews(selector_mode);
368 selector_mode = HS_YUV_COLOR_MODE;
369 openControlViews(HS_YUV_COLOR_MODE);
370 }
371 break;
372
373 case HS_HSV_COLOR_MODE:
374 if (selector_mode != HS_HSV_COLOR_MODE) {
375 deleteControlViews(selector_mode);
376 selector_mode = HS_HSV_COLOR_MODE;
377 openControlViews(HS_HSV_COLOR_MODE);
378 }
379 break;
380
381
382 // this comes from the menubar->"Mode"->"Simple-Mode" and indicates that
383 // the color selector should be changed to a HSColorControl, this is used
384 // also for other purposes than just a message-constant
385 case HS_SIMPLE_COLOR_MODE:
386 if (selector_mode != HS_SIMPLE_COLOR_MODE) {
387 deleteControlViews(selector_mode);
388 selector_mode = HS_SIMPLE_COLOR_MODE;
389 openControlViews(HS_SIMPLE_COLOR_MODE);
390 }
391 break;
392
393 default:
394 BWindow::MessageReceived(message);
395 break;
396 }
397}
398
399bool ColorPaletteWindow::QuitRequested()
400{
401 // We might do something useful here.
402 return TRUE1;
403}
404
405bool ColorPaletteWindow::openControlViews(int32 mode)
406{
407 // first we open the views that are common to all modes of color palette
408 // at least the menubar and the color-set container and controls that can change
409 // the color-set or its name
410
411 // these variables are used to position the views correctly
412 float top , left;
413
414 // update the top to be under menu_bar
415 top = menu_bar->Frame().Height() + 1;
416
417 box1 = new BBox(BRect(0,top,0,top));
418 box1->SetBorder(B_PLAIN_BORDER);
419 // here open the color_container
420 color_container = new ColorContainer(BRect(0,3,63,66),ColorSet::currentSet()->sizeOfSet());
421 color_container->SetDraggingEnabled(TRUE1);
422 box1->AddChild(color_container);
423
424 // update the top to be under container in the box1 coordinates that is
425 top = color_container->Frame().bottom + 4;
426
427 // Here add the buttons that control the color-set.
428 ResourceServer* server = ResourceServer::Instance();
429 if (server) {
430 BPicture arrow_pushed;
431 BPicture arrow_not_pushed;
432
433 server->GetPicture(LEFT_ARROW, &arrow_not_pushed);
434 server->GetPicture(LEFT_ARROW_PUSHED, &arrow_pushed);
435
436 previous_set = new BPictureButton(BRect(3, top, 11, top + 12),
437 "left_arrow", &arrow_not_pushed, &arrow_pushed,
438 new BMessage(HS_PREVIOUS_PALETTE'PrPl'));
439 box1->AddChild(previous_set);
440 previous_set->SetTarget(this);
441 previous_set->ResizeToPreferred();
442
443 server->GetPicture(RIGHT_ARROW, &arrow_not_pushed);
444 server->GetPicture(RIGHT_ARROW_PUSHED, &arrow_pushed);
445
446 next_set = new BPictureButton(previous_set->Frame(), "right arrow",
447 &arrow_not_pushed, &arrow_pushed, new BMessage(HS_NEXT_PALETTE'NxPl'));
448 box1->AddChild(next_set);
449 next_set->SetTarget(this);
450 next_set->ResizeToPreferred();
451 next_set->MoveBy(next_set->Frame().Width() + 3,0);
452 }
453
454 // here resize the box1 to appropriate size
455 box1->ResizeTo(max_c(next_set->Frame().right + 20,color_container->Frame().Width()+6)((next_set->Frame().right + 20)>(color_container->Frame
().Width()+6)?(next_set->Frame().right + 20):(color_container
->Frame().Width()+6))
,next_set->Frame().bottom+3);
456
457 // here center the views horizontally
458 color_container->MoveBy((box1->Frame().Width() - color_container->Frame().Width())/2,0);
459
460 AddChild(box1);
461 left = box1->Frame().right + 1;
462 top = menu_bar->Frame().Height() + 1;
463
464 // this will be assigned to RGBControl or similar object
465 BMessage *invocation_message;
466 // here we open the views that show color controls e.g. RGB- or HSV-controls
467 switch (mode) {
468
469 // in this case just open a HSColorControl and color-set container
470 case HS_SIMPLE_COLOR_MODE:
471 box2 = new BBox(BRect(box1->Frame().right+1,top,box1->Frame().right+10,box1->Frame().bottom));
472 color_control = new HSColorControl(BPoint(5,0),B_CELLS_32x8,8,"");
473 color_control->SetTarget(this);
474 box2->ResizeTo(color_control->Frame().Width()+10,box2->Frame().Height());
475
476 ResizeTo(box2->Frame().right,max_c(box1->Frame().Height() + top-1,color_control->Frame().Height() + top)((box1->Frame().Height() + top-1)>(color_control->Frame
().Height() + top)?(box1->Frame().Height() + top-1):(color_control
->Frame().Height() + top))
);
477 box2->AddChild(color_control);
478 AddChild(box2);
479 // here center the color control vertically
480 color_control->MoveBy(0,(box2->Frame().Height() - color_control->Frame().Height())/2);
481 break;
482
483 // in this case open an RGBControl
484 case HS_RGB_COLOR_MODE: case HS_CMY_COLOR_MODE: case HS_YIQ_COLOR_MODE: case HS_YUV_COLOR_MODE:
485 case HS_HSV_COLOR_MODE:
486 box2 = new BBox(BRect(box1->Frame().right+1,top,box1->Frame().right+10,box1->Frame().bottom));
487
488 if (mode == HS_RGB_COLOR_MODE) {
489 rgb_color c = {0,0,0,255};
490 color_slider = new RGBControl(BPoint(5,0),c);
491 }
492 else if (mode == HS_CMY_COLOR_MODE) {
493 rgb_color c = {255,255,255,255};
494 color_slider = new CMYControl(BPoint(5,0),c);
495 }
496 else if (mode == HS_YIQ_COLOR_MODE) {
497 rgb_color c = {255,255,255,255};
498 color_slider = new YIQControl(BPoint(5,0),c);
499 }
500 else if (mode == HS_YUV_COLOR_MODE) {
501 rgb_color c = {255,255,255,255};
502 color_slider = new YUVControl(BPoint(5,0),c);
503 }
504 else if (mode == HS_HSV_COLOR_MODE) {
505 rgb_color c = {255,255,255,255};
506 color_slider = new HSVControl(BPoint(5,0),c);
507 }
508 box2->AddChild(color_slider);
509 AddChild(box2);
510
511 color_slider->SetTarget(this);
512 box2->ResizeTo(color_slider->Frame().Width()+10,box2->Frame().Height());
513 ResizeTo(box2->Frame().right,max_c(box1->Frame().Height() +((box1->Frame().Height() + top-1)>(color_slider->Frame
().Height() + top)?(box1->Frame().Height() + top-1):(color_slider
->Frame().Height() + top))
514 top-1,color_slider->Frame().Height() + top)((box1->Frame().Height() + top-1)>(color_slider->Frame
().Height() + top)?(box1->Frame().Height() + top-1):(color_slider
->Frame().Height() + top))
);
515
516 // here center the color control vertically
517 color_slider->MoveBy(0,(box2->Frame().Height() -
518 color_slider->Frame().Height())/2);
519 invocation_message = new BMessage(HS_RGB_CONTROL_INVOKED'RGIn');
520 invocation_message->AddInt32("buttons",0);
521 color_slider->SetMessage(invocation_message);
522 break;
523
524 default:
525 return TRUE1;
526 }
527 box2->SetBorder(B_PLAIN_BORDER);
528
529 // Update the color-controllers and slider's values
530 if (color_control != NULL__null)
531 color_control->SetValue(ColorSet::currentSet()->currentColor());
532 if (color_slider != NULL__null)
533 color_slider->SetValue(ColorSet::currentSet()->currentColor());
534
535 return TRUE1;
536}
537
538
539
540void ColorPaletteWindow::deleteControlViews(int32)
541{
542 // here we delete all views that are not NULL
543 box1->RemoveSelf();
544 delete box1;
545
546 box2->RemoveSelf();
547 delete box2;
548
549// NULL all the controls
550 color_control = NULL__null;
551 color_slider = NULL__null;
552}
553
554
555void ColorPaletteWindow::openMenuBar()
556{
557 BMenu *menu;
558 BMenu *sub_menu;
559 BMenuItem *menu_item;
560
561 menu_bar = new BMenuBar(BRect(0,0,0,0),"menu bar");
562 menu = new BMenu(B_TRANSLATE("Color set")BLocaleRoster::Default()->GetCatalog()->GetString(("Color set"
), "ColorPalette")
);
563 menu_bar->AddItem(menu);
564
565 sub_menu = new BMenu(B_TRANSLATE("New color set")BLocaleRoster::Default()->GetCatalog()->GetString(("New color set"
), "ColorPalette")
);
566
567 // in this loop we add possible palette sizes to menu
568 BMessage *msg;
569 char item_title[20] = "";
570 for (int32 i = 3; i <= 6; i++) {
571 sprintf(item_title, "%ld %s",((int32)pow(2, i)),
572 B_TRANSLATE("Colors")BLocaleRoster::Default()->GetCatalog()->GetString(("Colors"
), "ColorPalette")
);
573 msg = new BMessage(HS_NEW_PALETTE_CREATED'NPaC');
574 msg->AddInt32("colors", ((int32)pow(2, i)));
575 menu_item = new BMenuItem(item_title, msg);
576 sub_menu->AddItem(menu_item);
577 }
578 // the palette window will handle all things that concern making
579 // or loading new palette
580 sub_menu->SetTargetForItems(this);
581 menu->AddItem(sub_menu);
582
583 menu_item = new BMenuItem(B_TRANSLATE("Delete current set")BLocaleRoster::Default()->GetCatalog()->GetString(("Delete current set"
), "ColorPalette")
,
584 new BMessage(HS_DELETE_PALETTE'DePa'));
585 menu_item->SetTarget(this);
586 menu->AddItem(menu_item);
587 if (ColorSet::numberOfSets() <= 1) {
588 menu_item->SetEnabled(FALSE0);
589 }
590
591 menu->AddItem(new BSeparatorItem());
592 menu_item = new BMenuItem(B_TRANSLATE("Open color set" B_UTF8_ELLIPSIS)BLocaleRoster::Default()->GetCatalog()->GetString(("Open color set"
"\xE2\x80\xA6"), "ColorPalette")
,
593 new BMessage(HS_SHOW_PALETTE_OPEN_PANEL'SpOp'));
594 menu_item->SetTarget(this);
595 menu->AddItem(menu_item);
596 menu_item = new BMenuItem(B_TRANSLATE("Save color set")BLocaleRoster::Default()->GetCatalog()->GetString(("Save color set"
), "ColorPalette")
,
597 new BMessage(HS_SHOW_PALETTE_SAVE_PANEL'SpSp'));
598 menu_item->SetTarget(this);
599 menu->AddItem(menu_item);
600
601 menu = new BMenu(B_TRANSLATE("Color model")BLocaleRoster::Default()->GetCatalog()->GetString(("Color model"
), "ColorPalette")
);
602 menu_bar->AddItem(menu);
603
604 char string[256];
605 sprintf(string,"RGB");
606 menu_item = new BMenuItem(string,new BMessage(HS_RGB_COLOR_MODE));
607 menu_item->SetTarget(this);
608 menu->AddItem(menu_item);
609 sprintf(string,"CMY");
610 menu_item = new BMenuItem(string,new BMessage(HS_CMY_COLOR_MODE));
611 menu_item->SetTarget(this);
612 menu->AddItem(menu_item);
613 sprintf(string,"HSV");
614 menu_item = new BMenuItem(string,new BMessage(HS_HSV_COLOR_MODE));
615 menu_item->SetTarget(this);
616 menu->AddItem(menu_item);
617 sprintf(string,"YIQ");
618 menu_item = new BMenuItem(string,new BMessage(HS_YIQ_COLOR_MODE));
619 menu_item->SetTarget(this);
620 menu->AddItem(menu_item);
621 sprintf(string,"YUV");
622 menu_item = new BMenuItem(string,new BMessage(HS_YUV_COLOR_MODE));
623 menu_item->SetTarget(this);
624 menu->AddItem(menu_item);
625 sprintf(string,"BeOS");
626 menu_item = new BMenuItem(string,new BMessage(HS_SIMPLE_COLOR_MODE));
627 menu_item->SetTarget(this);
628 menu->AddItem(menu_item);
629 menu->SetRadioMode(TRUE1);
630 menu->FindItem(selector_mode)->SetMarked(TRUE1);
631
632 AddChild(menu_bar);
633}
634
635void ColorPaletteWindow::handlePaletteLoad(BMessage *message)
636{
637 // here check for file type and possibly load it to memory
638 uint32 type;
639 int32 count;
640 entry_ref ref;
641
642 // this holds the bytes that were read
643 ssize_t bytes_read;
644
645 // this will hold the identification string, they are not longer than 256 chars
646 char file_type[256];
647
648
649 // we can probably assume that the ref is actually a file
650 message->GetInfo("refs", &type, &count);
651 if ( type != B_REF_TYPE )
652 return;
653
654 for ( long i = --count; i >= 0; i-- ) {
655 if ( message->FindRef("refs", i, &ref) == B_OK((int)0) ) {
656 BFile file;
657 if ( file.SetTo(&ref, B_READ_ONLY0x0000) == B_OK((int)0) ) {
658 // the file was succesfully opened
659 // here we check that it is actually a palette file
660 // and read it if it is and also generate a new palette to
661 // list of palettes
662 if ((bytes_read = file.Read(file_type,strlen(HS_PALETTE_ID_STRING"ArtPaint color set"))) < 0) {
663 // here some error reading file has happened
664 (new BAlert("",B_TRANSLATE("Error reading file")BLocaleRoster::Default()->GetCatalog()->GetString(("Error reading file"
), "ColorPalette")
,B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "ColorPalette")
))->Go();
665 }
666 else {
667 // the read was succesfull, terminate the id string and compare
668 file_type[bytes_read] = '\0';
669 if (strcmp(file_type,HS_PALETTE_ID_STRING"ArtPaint color set") != 0) {
670 // this was not a palette file
671 (new BAlert("",B_TRANSLATE("Not a color set file")BLocaleRoster::Default()->GetCatalog()->GetString(("Not a color set file"
), "ColorPalette")
,B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "ColorPalette")
))->Go();
672 }
673 else {
674 // this was palette file, read the rest of it
675 int32 palette_size;
676 if ((bytes_read = file.Read(&palette_size,sizeof(int32))) != sizeof(int32)) {
Although the value stored to 'bytes_read' is used in the enclosing expression, the value is never actually read from 'bytes_read'
677 // here some error reading file has happened
678 (new BAlert("",B_TRANSLATE("File structure corrupted")BLocaleRoster::Default()->GetCatalog()->GetString(("File structure corrupted"
), "ColorPalette")
,
679 B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "ColorPalette")
))->Go();
680 }
681 else {
682 // create the palette and read the palette colors
683 ColorSet *loaded_set = new ColorSet(palette_size);
684 rgb_color loaded_color;
685
686 // here is the loop that reads palette entries from file
687 for (int32 i = 0; i < palette_size; i++) {
688 file.Read(&loaded_color,sizeof(rgb_color));
689 loaded_set->setColor(i,loaded_color);
690 }
691 // this array holds the palette-name
692 char palette_name[256];
693 // read as many bytes as there is left to be the palette name
694 bytes_read = file.Read(palette_name,255);
695 palette_name[bytes_read] = '\0';
696 loaded_set->setName(palette_name);
697 }
698
699 }
700 }
701 }
702 }
703 }
704}
705
706
707void ColorPaletteWindow::handlePaletteSave(BMessage *message)
708{
709 uint32 type;
710 int32 count;
711 entry_ref ref;
712
713 // we can probably assume that the ref is actually a file
714 message->GetInfo("directory", &type, &count);
715 if ( type != B_REF_TYPE ) {
716 return;
717 }
718 // here take a pointer to current color-set, so that if current set is changed
719 // this will still save the same set
720 ColorSet *color_set = ColorSet::currentSet();
721
722 for ( long i = --count; i >= 0; i-- ) {
723 if ( message->FindRef("directory", i, &ref) == B_OK((int)0) ) {
724 BFile file;
725 BDirectory directory = BDirectory(&ref);
726 if ( file.SetTo(&directory,message->FindString("name",i),
727 B_READ_WRITE0x0002 | B_CREATE_FILE0x0200 | B_ERASE_FILE0x0400) == B_OK((int)0) ) {
728 // here we write the current color-set to file
729 // first set the file's type and other metadata
730 // get the applications signature
731 app_info info;
732 be_app->GetAppInfo(&info);
733
734 BNodeInfo node(&file);
735 node.SetType(HS_PALETTE_MIME_STRING"application/x-vnd.artpaint-palette-file");
736 node.SetPreferredApp(info.signature);
737
738 if (file.Write(HS_PALETTE_ID_STRING"ArtPaint color set",strlen(HS_PALETTE_ID_STRING"ArtPaint color set")) < 0) {
739 // error happened
740 (new BAlert("",B_TRANSLATE("Cannot write to file")BLocaleRoster::Default()->GetCatalog()->GetString(("Cannot write to file"
), "ColorPalette")
,B_TRANSLATE("OK")BLocaleRoster::Default()->GetCatalog()->GetString(("OK"
), "ColorPalette")
))->Go();
741 }
742 else {
743 // write the rest of the file
744 int32 size = color_set->sizeOfSet();
745 file.Write(&size,sizeof(int32));
746
747 // this loop writes the color entries
748 for (int32 i=0;i<size;i++) {
749 rgb_color c = color_set->colorAt(i);
750 file.Write(&c,sizeof(rgb_color));
751 }
752
753 // finally write the name of set
754 file.Write(color_set->getName(),strlen(color_set->getName()));
755 }
756 }
757 }
758 }
759}
760
761
762void
763ColorPaletteWindow::showPaletteWindow(BMessage *msg)
764{
765 if (palette_window == NULL__null) {
766 BRect frame(300, 100, 400, 200);
767 color_window_modes mode = HS_RGB_COLOR_MODE;
768
769 if (SettingsServer* server = SettingsServer::Instance()) {
770 BMessage settings;
771 server->GetApplicationSettings(&settings);
772 settings.FindRect(skPaletteWindowFrame, &frame);
773 settings.FindInt32(skPaletteColorMode, (int32*)&mode);
774 }
775
776 ColorPaletteWindow* window = new ColorPaletteWindow(frame, mode);
777 for (int32 i = 0; i < master_window_list->CountItems(); ++i)
778 ((BWindow*)master_window_list->ItemAt(i))->AddToSubset(window);
779 } else {
780 if (palette_window->Lock()) {
781 palette_window->SetWorkspaces(B_CURRENT_WORKSPACE0);
782 if (palette_window->IsHidden())
783 palette_window->Show();
784
785 if (!palette_window->IsActive())
786 palette_window->Activate(TRUE1);
787
788 palette_window->Unlock();
789 }
790 }
791
792 if (palette_window->Lock()) {
793 BRect palette_window_frame = palette_window->Frame();
794 palette_window_frame = FitRectToScreen(palette_window_frame);
795 palette_window->MoveTo(palette_window_frame.LeftTop());
796 palette_window->Unlock();
797 }
798
799 // If we got a message we should try to use it for loading a palette.
800 if (msg)
801 palette_window->handlePaletteLoad(msg);
802}
803
804
805void
806ColorPaletteWindow::ChangePaletteColor(rgb_color& c)
807{
808 if (palette_window != NULL__null) {
809 palette_window->Lock();
810
811 if (palette_window->color_control != NULL__null)
812 palette_window->color_control->SetValue(c);
813 if (palette_window->color_slider != NULL__null)
814 palette_window->color_slider->SetValue(c);
815
816 palette_window->Unlock();
817 }
818}
819
820
821void
822ColorPaletteWindow::setFeel(window_feel feel)
823{
824 if (SettingsServer* server = SettingsServer::Instance()) {
825 server->SetValue(SettingsServer::Application, skPaletteWindowFeel,
826 int32(feel));
827 }
828
829 if (palette_window) {
830 window_look look = B_FLOATING_WINDOW_LOOK;
831 if (feel == B_NORMAL_WINDOW_FEEL)
832 look = B_TITLED_WINDOW_LOOK;
833
834 palette_window->SetFeel(feel);
835 palette_window->SetLook(look);
836 }
837}
838
839
840void
841ColorPaletteWindow::AddMasterWindow(BWindow *window)
842{
843 master_window_list->AddItem(window);
844 if (palette_window)
845 window->AddToSubset(palette_window);
846}
847
848
849void
850ColorPaletteWindow::RemoveMasterWindow(BWindow *window)
851{
852 master_window_list->RemoveItem(window);
853}
854
855
856
857void
858ColorPaletteWindow::AddPaletteWindowClient(PaletteWindowClient *client)
859{
860 if (!palette_window_clients->HasItem(client))
861 palette_window_clients->AddItem(client);
862}
863
864
865void
866ColorPaletteWindow::RemovePaletteWindowClient(PaletteWindowClient *client)
867{
868 palette_window_clients->RemoveItem(client);
869}
870
871
872void
873ColorPaletteWindow::InformClients(const rgb_color& c)
874{
875 for (int32 i = 0; i < palette_window_clients->CountItems(); ++i) {
876 PaletteWindowClient* client =
877 static_cast<PaletteWindowClient*>(palette_window_clients->ItemAt(i));
878 if (client)
879 client->PaletteColorChanged(c);
880 }
881}
882
883
884// here is the definition of HSColorControl-class
885HSColorControl::HSColorControl(BPoint location, color_control_layout matrix,
886 float cellSide, const char *name)
887 : BColorControl(location, matrix, cellSide, name)
888{
889 // Set the message here so that using the text boxes before the sliders will work
890 BMessage *message = new BMessage(HS_COLOR_CONTROL_INVOKED'CCIn');
891 message->AddInt32("buttons", B_PRIMARY_MOUSE_BUTTON);
892 SetMessage(message);
893}
894
895void HSColorControl::MouseDown(BPoint location)
896{
897 // here we take the button that was pressed
898 int32 buttons = 0;
899 Window()->CurrentMessage()->FindInt32("buttons", &buttons);
900
901 // set the invokers message to contain the mouse-button that was last pressed
902 BMessage *message = new BMessage(HS_COLOR_CONTROL_INVOKED'CCIn');
903 message->AddInt32("buttons",buttons);
904 SetMessage(message);
905
906 // call the inherited MouseDown-function
907 BColorControl::MouseDown(location);
908}
909
910
911
912
913// here starts the definitions for ColorContainer class
914
915// here define the variable that points to list of color containers
916BList* ColorContainer::container_list = new BList();
917
918
919ColorContainer::ColorContainer(BRect frame, int32 amount_of_colors, uint32 resizingMode, bool highlight,bool add_arrows)
920 : BView(frame,"color container",resizingMode,B_WILL_DRAW)
921{
922 // here initialize the important variables
923
924 highlight_selected = highlight;
925 left_arrow = NULL__null;
926 right_arrow = NULL__null;
927 contains_arrows = FALSE0;
928
929 setUpContainer(frame,amount_of_colors,add_arrows);
930
931 // add this container to the list
932 container_list->AddItem(this);
933
934 dragging_enabled = FALSE0;
935}
936
937
938
939ColorContainer::~ColorContainer()
940{
941 // here remove ourselves from container list
942 container_list->RemoveItem(this);
943}
944
945
946void ColorContainer::AttachedToWindow()
947{
948 BView::AttachedToWindow();
949 if (Parent() != NULL__null)
950 SetViewColor(Parent()->ViewColor());
951
952 if (left_arrow != NULL__null)
953 left_arrow->SetTarget(this);
954 if (right_arrow != NULL__null)
955 right_arrow->SetTarget(this);
956}
957
958void ColorContainer::Draw(BRect)
959{
960 // here we draw the colors with FillRect
961 // we get the colors from palette that is held somewhere
962 // every instance of this class should also draw whenever
963 // a palette entry changes, how should we achieve that ????
964
965 BRect rect;
966
967 for (int32 i=0;i<color_count;i++) {
968
969 rect = colorBounds(i);
970 SetHighAndLowColors(ColorSet::currentSet()->colorAt(i));
971 FillRect(rect,HS_2X2_BLOCKS);
972 }
973
974 if (highlight_selected) {
975 // also draw the rectangle around selected color if required
976 SetHighColor(255,255,255,255);
977 StrokeRect(colorBounds(ColorSet::currentSet()->currentColorIndex()));
978 }
979}
980
981
982
983void ColorContainer::MouseDown(BPoint point)
984{
985 // here we highlight the color that is under the cursor
986 // and when we have selected the color we inform some
987 // third parties about that
988 uint32 buttons = 0;
989 uint32 original_button;
990
991 GetMouse(&point, &buttons, true);
992 int32 index,prev_index = ColorSet::currentSet()->currentColorIndex();
993
994 // first draw the rectangle around the newly selected color
995 index = pointIndex(point);
996 if (index != -1) {
997 // only of course if some color was actually selected
998 SetHighColor(255,255,255);
999 StrokeRect(colorBounds(index));
1000 }
1001
1002 original_button = buttons;
1003
1004 if (dragging_enabled == FALSE0) {
1005 while ( buttons ) {
1006 index = pointIndex(point);
1007 if ((index != -1) && (index != prev_index)) {
1008 // point is over some new color-entry
1009 if (prev_index != -1) {
1010 // re-draw the previous rectangle
1011 SetHighAndLowColors(ColorSet::currentSet()->colorAt(prev_index));
1012 FillRect(colorBounds(prev_index),HS_2X2_BLOCKS);
1013 }
1014 // then draw rect around new color
1015 SetHighColor(255,255,255);
1016 StrokeRect(colorBounds(index));
1017 }
1018 else if ((index == -1) && (prev_index != -1)) {
1019 // we fill the previous rectangle
1020 SetHighColor(ColorSet::currentSet()->colorAt(prev_index));
1021 FillRect(colorBounds(prev_index));
1022 }
1023
1024 prev_index = index;
1025 snooze(20 * 1000);
1026 GetMouse(&point, &buttons, true);
1027 }
1028 }
1029 else if (index >= 0) {
1030 float distance = 0;
1031 BPoint original_point = point;
1032 while ((distance < 6) && (buttons)) {
1033 GetMouse(&point,&buttons);
1034 snooze(20 * 1000);
1035 distance = fabs(original_point.x-point.x) + fabs(original_point.y-point.y);
1036 }
1037
1038 if ((distance >= 6) && buttons) {
1039 // Start a drag'n'drop session.
1040 BBitmap *dragged_map = new BBitmap(BRect(0,0,15,15),B_RGB32,TRUE1);
1041 BView *dragger_view = new BView(BRect(0,0,15,15),"dragger_view",B_FOLLOW_NONE0,B_WILL_DRAW);
1042 rgb_color c = ColorSet::currentSet()->colorAt(index);
1043 dragged_map->AddChild(dragger_view);
1044 dragged_map->Lock();
1045 float alpha = c.alpha;
1046 c.alpha = 127;
1047 dragger_view->SetHighColor(c);
1048 c.alpha = (uint8)alpha;
1049 dragger_view->FillRect(dragger_view->Bounds());
1050 dragger_view->Sync();
1051 dragged_map->Unlock();
1052 BMessage dragger_message(B_PASTE);
1053 dragger_message.AddData("RGBColor",B_RGB_COLOR_TYPE,&c,sizeof(rgb_color));
1054 DragMessage(&dragger_message,dragged_map,B_OP_ALPHA,BPoint(7,7));
1055// dragged = TRUE;
1056 index = ColorSet::currentSet()->currentColorIndex(); // The active color did not change.
1057 }
1058 }
1059
1060 if (index != -1) {
1061 // here we should make the current_color_index in active set to be index
1062 ColorSet::currentSet()->setCurrentColorIndex(index);
1063
1064 // here we should inform the app that a color has been changed
1065 if (original_button & B_PRIMARY_MOUSE_BUTTON)
1066 ((PaintApplication*)be_app)->SetColor(ColorSet::currentSet()->currentColor(),TRUE1);
1067 else
1068 ((PaintApplication*)be_app)->SetColor(ColorSet::currentSet()->currentColor(),FALSE0);
1069
1070 // we must also inform all other containers that the selection changed
1071 // so that they can highlight the proper rectangle, this will be done
1072 // with messages
1073 sendMessageToAllContainers(new BMessage(HS_PALETTE_SELECTION_CHANGED'PslC'));
1074
1075 // also inform the selected colors' views
1076 SelectedColorsView::sendMessageToAll(new BMessage(HS_COLOR_CHANGED'CoCH'));
1077
1078
1079
1080 // give the window the information that selection has changed
1081 rgb_color c = ColorSet::currentSet()->currentColor();
1082 ColorPaletteWindow::ChangePaletteColor(c);
1083 Window()->PostMessage(HS_PALETTE_SELECTION_CHANGED'PslC',Window());
1084 }
1085 else {
1086 SetHighColor(255,255,255);
1087 StrokeRect(colorBounds(ColorSet::currentSet()->currentColorIndex()));
1088 }
1089
1090 if (!highlight_selected) {
1091 // clear the highlight from selected color
1092 SetHighAndLowColors(ColorSet::currentSet()->currentColor());
1093 FillRect(colorBounds(ColorSet::currentSet()->currentColorIndex()),
1094 HS_2X2_BLOCKS);
1095 }
1096
1097}
1098
1099
1100void ColorContainer::MouseMoved(BPoint,uint32 transit,const BMessage*)
1101{
1102 // These are posted to the window in case that the window contains
1103 // a help view.
1104 if ((transit == B_ENTERED_VIEW) && (Window()->IsActive())) {
1105 BMessage *help_message = new BMessage(HS_TEMPORARY_HELP_MESSAGE'ThlM');
1106 help_message->AddString("message",
1107 B_TRANSLATE("Click to select a painting color.")BLocaleRoster::Default()->GetCatalog()->GetString(("Click to select a painting color."
), "ColorPalette")
);
1108 Window()->PostMessage(help_message);
1109 delete help_message;
1110 }
1111 if (transit == B_EXITED_VIEW) {
1112 Window()->PostMessage(HS_TOOL_HELP_MESSAGE'TolM');
1113 }
1114}
1115
1116
1117void ColorContainer::MessageReceived(BMessage *message)
1118{
1119 switch (message->what) {
1120
1121 // this message comes from ColorContainer::sendMessageToAllContainers and that function
1122 // is called in ColorWindow's MessageReceived, it's purpose is to inform
1123 case HS_PALETTE_CHANGED'PaCh':
1124 // here call the function that fits the view to
1125 // accommodate the new palette. 0 colors instructs the function
1126 // to look the amount from ColorSet.
1127 setUpContainer(Bounds(),0,FALSE0);
1128 Draw(Bounds());
1129 break;
1130
1131 case HS_NEXT_PALETTE'NxPl': {
1132 ColorSet::moveToNextSet();
1133 BMessage paletteChanged(HS_PALETTE_CHANGED'PaCh');
1134 ColorContainer::sendMessageToAllContainers(&paletteChanged);
1135 } break;
1136 case HS_PREVIOUS_PALETTE'PrPl': {
1137 ColorSet::moveToPrevSet();
1138 BMessage paletteChanged(HS_PALETTE_CHANGED'PaCh');
1139 ColorContainer::sendMessageToAllContainers(&paletteChanged);
1140 } break;
1141
1142 // this message comes from ColorContainer::sendMessageToAllContainers and that function
1143 // is called in ColorWindow's MessageReceived, it informs us that one of the colors in the
1144 // set has been changed, this constant is used for the same purpose in a slight different context
1145 // the changed color is at "index" int32 data member in the message
1146 case HS_COLOR_CHANGED'CoCH': {
1147 // the colorset has been updated, we will draw using colorChanged-function
1148 colorChanged(message->FindInt32("index"));
1149 } break;
1150
1151 case B_PASTE: {
1152 if (message->WasDropped()) {
1153 // Here we see on to which button it was dropped and then
1154 // try to extract a color from the message
1155 rgb_color *color;
1156 ssize_t color_size;
1157 if (message->FindData("RGBColor",B_RGB_COLOR_TYPE,(const void**)&color,&color_size) == B_OK((int)0)) {
1158 BPoint drop_point = message->DropPoint();
1159 drop_point = ConvertFromScreen(drop_point);
1160 int32 index = pointIndex(drop_point);
1161 if (index >= 0) {
1162 ColorSet::currentSet()->setCurrentColorIndex(index);
1163 ColorSet::currentSet()->setCurrentColor(*color);
1164 BMessage a_message(HS_COLOR_CHANGED'CoCH');
1165 a_message.AddInt32("index",index);
1166 ColorContainer::sendMessageToAllContainers(&a_message);
1167 a_message.what = HS_PALETTE_SELECTION_CHANGED'PslC';
1168 ColorContainer::sendMessageToAllContainers(&a_message);
1169 Window()->PostMessage(HS_PALETTE_SELECTION_CHANGED'PslC',Window());
1170 }
1171 }
1172 }
1173 } break;
1174 // this message comes from ColorContainer::sendMessageToAllContainers and that function
1175 // is called in ColorContainer::MouseDown, it informs us that the selected color in the
1176 // set has changed
1177 case HS_PALETTE_SELECTION_CHANGED'PslC': {
1178 // the selected color of palette has changed
1179 // if we highlight it then draw completely
1180 // because we don't know what was the previous color
1181 if (highlight_selected)
1182 Draw(Bounds());
1183 } break;
1184 default:
1185 BView::MessageReceived(message);
1186 break;
1187 }
1188}
1189
1190void ColorContainer::setUpContainer(BRect frame, int32 number_of_colors,bool add_arrows)
1191{
1192 // This gets stuck in an infinite loop if the height of the frame
1193 // is negative.
1194 horiz_c_size = 3;
1195 vert_c_size = 3;
1196 horiz_gutter = 1;
1197 vert_gutter = 1;
1198 color_count = number_of_colors;
1199 row_count = 1;
1200
1201 if (color_count == 0) {
1202 // here we take the new color-count from current color-set
1203 color_count = ColorSet::currentSet()->sizeOfSet();
1204 }
1205
1206 // first count how many rows are to be used
1207 while ((row_count<=color_count/row_count) && (row_count*vert_c_size<=frame.Height()))
1208 row_count *= 2;
1209 row_count /= 2;
1210
1211 if (row_count < 1)
1212 row_count = 1;
1213
1214 // then increase the row height to maximum
1215 while ((row_count*(vert_c_size + vert_gutter) - vert_gutter)<=frame.Height())
1216 vert_c_size++;
1217 vert_c_size--;
1218
1219 // then increase the width to maximum
1220 float maximum_width = frame.Width();
1221 if (left_arrow != NULL__null) {
1222 maximum_width -= (left_arrow->Frame().right + 2);
1223 }
1224 while ((color_count/row_count*(horiz_c_size+horiz_gutter) - horiz_gutter) <= maximum_width)
1225 horiz_c_size++;
1226 horiz_c_size--;
1227
1228 ResourceServer* server = ResourceServer::Instance();
1229 if (add_arrows && server) {
1230 BPicture arrow_pushed;
1231 BPicture arrow_not_pushed;
1232
1233 server->GetPicture(LEFT_ARROW, &arrow_not_pushed);
1234 server->GetPicture(LEFT_ARROW_PUSHED, &arrow_pushed);
1235
1236 left_arrow = new BPictureButton(BRect(0, 0, 8, 12), "left_arrow",
1237 &arrow_not_pushed, &arrow_pushed, new BMessage(HS_PREVIOUS_PALETTE'PrPl'));
1238 AddChild(left_arrow);
1239 left_arrow->ResizeToPreferred();
1240 left_arrow->MoveTo(BPoint(2, 2));
1241
1242 server->GetPicture(RIGHT_ARROW, &arrow_not_pushed);
1243 server->GetPicture(RIGHT_ARROW_PUSHED, &arrow_pushed);
1244
1245 right_arrow = new BPictureButton(BRect(0, 0, 8, 12), "right_arrow",
1246 &arrow_not_pushed, &arrow_pushed, new BMessage(HS_NEXT_PALETTE'NxPl'));
1247 AddChild(right_arrow);
1248 right_arrow->ResizeToPreferred();
1249 right_arrow->MoveTo(BPoint(2, left_arrow->Frame().bottom + 3));
1250
1251 contains_arrows = true;
1252 }
1253
1254 // here resize the view to just fit the colors
1255 ResizeTo((color_count/row_count*(horiz_c_size+horiz_gutter) - horiz_gutter),(row_count*(vert_c_size + vert_gutter) - vert_gutter));
1256
1257 if (contains_arrows) {
1258 ResizeBy(left_arrow->Frame().right+2,0);
1259 }
1260}
1261
1262
1263void ColorContainer::SetHighAndLowColors(const rgb_color &c)
1264{
1265 rgb_color low = c;
1266 rgb_color high = c;
1267
1268 float coeff = c.alpha / 255.0;
1269 low.red = (uint8)(coeff*c.red);
1270 low.green = (uint8)(coeff*c.green);
1271 low.blue = (uint8)(coeff*c.blue);
1272 low.alpha = 255;
1273
1274 high.red = (uint8)(coeff*c.red + (1-coeff)*255);
1275 high.green = (uint8)(coeff*c.green + (1-coeff)*255);
1276 high.blue = (uint8)(coeff*c.blue + (1-coeff)*255);
1277 high.alpha = 255;
1278
1279 SetHighColor(high);
1280 SetLowColor(low);
1281}
1282
1283BRect ColorContainer::colorBounds(int32 index)
1284{
1285 // this function calculates the rectangle for the
1286 // palette entry at index that is to be drawn on screen
1287 BRect rect;
1288 int32 row=1,column=1;
1289 for (int32 i=0;i<index;i++) {
1290 if (column >= color_count/row_count) {
1291 column = 1;
1292 row++;
1293 }
1294 else
1295 column++;
1296 }
1297 rect = BRect((column-1)*(horiz_c_size + horiz_gutter),(row-1)*(vert_c_size + vert_gutter),column*(horiz_c_size + horiz_gutter) - horiz_gutter,row*(vert_c_size + vert_gutter) - vert_gutter);
1298 if ((contains_arrows == TRUE1) && (left_arrow != NULL__null)) {
1299 rect.OffsetBy(left_arrow->Frame().right + 2,0);
1300 }
1301 return rect;
1302}
1303
1304
1305int32 ColorContainer::pointIndex(BPoint point)
1306{
1307 // this function returns which palette entry is at point in the view
1308 // or -1 if no entry is to found there
1309 // at the moment just calculate usin rect Contains-function
1310 // later should be implemented more elegantly
1311
1312 for (int32 i=0;i<color_count;i++) {
1313 if (colorBounds(i).Contains(point))
1314 return i;
1315 }
1316
1317 // none of the rectangles contained point
1318 return -1;
1319}
1320
1321void ColorContainer::colorChanged(int32 color_index)
1322{
1323 // draw the new color
1324 rgb_color c = ColorSet::currentSet()->colorAt(color_index);
1325 rgb_color low = c;
1326 float coeff = c.alpha / 255.0;
1327 low.red = (uint8)(c.red*coeff);
1328 low.green = (uint8)(c.green*coeff);
1329 low.blue = (uint8)(c.blue*coeff);
1330 low.alpha = 255;
1331
1332 c.red = (uint8)(c.red * coeff + (1-coeff)*255);
1333 c.green = (uint8)(c.green * coeff + (1-coeff)*255);
1334 c.blue = (uint8)(c.blue * coeff + (1-coeff)*255);
1335 c.alpha = 255;
1336
1337 SetHighColor(c);
1338 SetLowColor(low);
1339 FillRect(colorBounds(color_index),HS_2X2_BLOCKS);
1340
1341 // also draw the white rect around the color that is currently selected
1342 // could be some other that was changed
1343 if (highlight_selected) {
1344 SetHighColor(255,255,255);
1345 StrokeRect(colorBounds(ColorSet::currentSet()->currentColorIndex()));
1346 }
1347 // and we will Sync()
1348 Sync();
1349}
1350
1351
1352void ColorContainer::sendMessageToAllContainers(BMessage *message)
1353{
1354 // here go through the list of color containers
1355 // and post message to each of them
1356
1357 for (int32 i=0;i<container_list->CountItems();i++) {
1358 ((ColorContainer*)container_list->ItemAt(i))->Window()->PostMessage(message,(ColorContainer*)container_list->ItemAt(i));
1359 }
1360}
1361
1362
1363// here begins the definition of ColorSet-class
1364// first initialize the static variables
1365BList* ColorSet::color_set_list = new BList();
1366int32 ColorSet::current_set_index = 0;
1367
1368
1369ColorSet::ColorSet(int32 amount_of_colors, ColorSet *copy_this_palette)
1370{
1371 // first check that the amount of colors is reasonable
1372 amount_of_colors = min_c(amount_of_colors,256)((amount_of_colors)>(256)?(256):(amount_of_colors));
1373 amount_of_colors = max_c(amount_of_colors,1)((amount_of_colors)>(1)?(amount_of_colors):(1));
1374
1375 // first allocate memory for the new palette
1376 palette = new rgb_color[amount_of_colors];
1377
1378 // allocate memory for name, 100 chars should be long enough
1379 name = new char[100];
1380
1381 if (copy_this_palette == NULL__null) {
1382 // if no palette was given to copy from make a default palette
1383 for (int32 i=0;i<amount_of_colors;i++) {
1384 palette[i].red = i*256/amount_of_colors;
1385 palette[i].green = i*256/amount_of_colors;
1386 palette[i].blue = i*256/amount_of_colors;
1387 palette[i].alpha = 255;
1388 }
1389 }
1390 else {
1391 // here we copy that palette
1392 int32 source_size = copy_this_palette->sizeOfSet();
1393 for (int i=0;i<amount_of_colors;i++) {
1394 palette[i] = copy_this_palette->colorAt(i % source_size);
1395 }
1396 }
1397 // store the color count
1398 color_count = amount_of_colors;
1399
1400 // create a default name
1401 strcpy(name,"default palette");
1402
1403 // put the current color to 0
1404 current_color_index = 0;
1405
1406 color_set_list->AddItem(this);
1407}
1408
1409ColorSet::~ColorSet()
1410{
1411 // remove ourselves from the color_set_list
1412 color_set_list->RemoveItem(this);
1413 current_set_index = min_c(current_set_index,color_set_list->CountItems()-1)((current_set_index)>(color_set_list->CountItems()-1)?(
color_set_list->CountItems()-1):(current_set_index))
;
1414}
1415
1416
1417rgb_color ColorSet::colorAt(int32 index)
1418{
1419 // check that the index is correct
1420 if ((index>=0)&&(index<color_count)) {
1421 return palette[index];
1422 }
1423 else {
1424 // otherwise return the first color
1425 return palette[0];
1426 }
1427}
1428
1429
1430void ColorSet::setColor(int32 index, rgb_color color)
1431{
1432 // check that the index is correct
1433 if ((index>=0)&&(index<color_count)) {
1434 palette[index] = color;
1435 }
1436
1437}
1438
1439
1440void ColorSet::setName(const char *set_name)
1441{
1442 strcpy(name,set_name);
1443}
1444
1445
1446char* ColorSet::getName()
1447{
1448 return name;
1449}
1450
1451
1452status_t ColorSet::readSets(BFile &file)
1453{
1454 int32 number_of_sets;
1455
1456 if (file.Read(&number_of_sets,sizeof(int32)) != sizeof(int32))
1457 return B_ERROR(-1);
1458
1459 for (int32 i=0;i<number_of_sets;i++) {
1460 int32 size_of_set;
1461 if (file.Read(&size_of_set,sizeof(int32)) != sizeof(int32))
1462 return B_ERROR(-1);
1463
1464 ColorSet *new_set = new ColorSet(size_of_set);
1465
1466 int32 name_length;
1467 char name[255];
1468 file.Read(&name_length,sizeof(int32));
1469 file.Read(name,name_length);
1470 name[name_length] = '\0';
1471
1472 new_set->setName(name);
1473
1474 for (int32 b=0;b<size_of_set;b++) {
1475 rgb_color c;
1476 if (file.Read(&c,sizeof(rgb_color)) != sizeof(rgb_color))
1477 return B_ERROR(-1);
1478
1479 new_set->palette[b] = c;
1480 }
1481 }
1482
1483 return B_OK((int)0);
1484}
1485
1486
1487status_t ColorSet::writeSets(BFile &file)
1488{
1489 int32 written_value = color_set_list->CountItems();
1490
1491 if (file.Write(&written_value,sizeof(int32)) != sizeof(int32))
1492 return B_ERROR(-1);
1493
1494 for (int32 i=0;i<color_set_list->CountItems();i++) {
1495 written_value = ((ColorSet*)color_set_list->ItemAt(i))->sizeOfSet();
1496 if (file.Write(&written_value,sizeof(int32)) != sizeof(int32))
1497 return B_ERROR(-1);
1498
1499 written_value = strlen(((ColorSet*)color_set_list->ItemAt(i))->getName());
1500 if (file.Write(&written_value,sizeof(int32)) != sizeof(int32))
1501 return B_ERROR(-1);
1502
1503 written_value = file.Write(((ColorSet*)color_set_list->ItemAt(i))->getName(),
1504 strlen(((ColorSet*)color_set_list->ItemAt(i))->getName()));
1505 if (uint32(written_value) != strlen(((ColorSet*)color_set_list->ItemAt(i))->getName()))
1506 return B_ERROR(-1);
1507
1508 // here write the palette entries
1509 for (int32 b=0;b<((ColorSet*)color_set_list->ItemAt(i))->sizeOfSet();b++) {
1510 rgb_color c = ((ColorSet*)color_set_list->ItemAt(i))->palette[b];
1511 if (file.Write(&c,sizeof(rgb_color)) != sizeof(rgb_color))
1512 return B_ERROR(-1);
1513 }
1514 }
1515
1516
1517 return B_OK((int)0);
1518}