Terminal: graphical settings for configuring themes.

Implements #16835: Make colour schemes modular.
Implements #15936: Terminal settings should allow to drop a colour.

Change-Id: I1071c9285ba887e734af47b724f9de7f6c660581
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5950
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Jessica Hamilton
2023-01-10 11:09:22 +00:00
parent 7a772a5586
commit 1b370545d7
15 changed files with 1444 additions and 239 deletions
-219
View File
@@ -46,34 +46,6 @@ AppearancePrefView::AppearancePrefView(const char* name,
BGroupView(name, B_VERTICAL, 5),
fTerminalMessenger(messenger)
{
const char* kColorTable[] = {
B_TRANSLATE_MARK("Text"),
B_TRANSLATE_MARK("Background"),
B_TRANSLATE_MARK("Cursor"),
B_TRANSLATE_MARK("Text under cursor"),
B_TRANSLATE_MARK("Selected text"),
B_TRANSLATE_MARK("Selected background"),
"",
B_TRANSLATE_MARK("ANSI black color"),
B_TRANSLATE_MARK("ANSI red color"),
B_TRANSLATE_MARK("ANSI green color"),
B_TRANSLATE_MARK("ANSI yellow color"),
B_TRANSLATE_MARK("ANSI blue color"),
B_TRANSLATE_MARK("ANSI magenta color"),
B_TRANSLATE_MARK("ANSI cyan color"),
B_TRANSLATE_MARK("ANSI white color"),
"",
B_TRANSLATE_MARK("ANSI bright black color"),
B_TRANSLATE_MARK("ANSI bright red color"),
B_TRANSLATE_MARK("ANSI bright green color"),
B_TRANSLATE_MARK("ANSI bright yellow color"),
B_TRANSLATE_MARK("ANSI bright blue color"),
B_TRANSLATE_MARK("ANSI bright magenta color"),
B_TRANSLATE_MARK("ANSI bright cyan color"),
B_TRANSLATE_MARK("ANSI bright white color"),
NULL
};
fBlinkCursor = new BCheckBox(
B_TRANSLATE("Blinking cursor"),
new BMessage(MSG_BLINK_CURSOR_CHANGED));
@@ -110,16 +82,6 @@ AppearancePrefView::AppearancePrefView(const char* name,
}
fEncodingField = new BMenuField(B_TRANSLATE("Encoding:"), encodingMenu);
BPopUpMenu* schemesPopUp = _MakeColorSchemeMenu(MSG_COLOR_SCHEME_CHANGED,
gColorSchemes);
fColorSchemeField = new BMenuField(B_TRANSLATE("Color scheme:"),
schemesPopUp);
BPopUpMenu* colorsPopUp = _MakeMenu(MSG_COLOR_FIELD_CHANGED, kColorTable,
kColorTable[0]);
fColorField = new BMenuField(B_TRANSLATE("Color:"), colorsPopUp);
fTabTitle = new BTextControl("tabTitle", B_TRANSLATE("Tab title:"), "",
NULL);
fTabTitle->SetModificationMessage(
@@ -151,14 +113,8 @@ AppearancePrefView::AppearancePrefView(const char* name,
.Add(fFontField->CreateMenuBarLayoutItem(), 1, 3)
.Add(fEncodingField->CreateLabelLayoutItem(), 0, 4)
.Add(fEncodingField->CreateMenuBarLayoutItem(), 1, 4)
.Add(fColorSchemeField->CreateLabelLayoutItem(), 0, 5)
.Add(fColorSchemeField->CreateMenuBarLayoutItem(), 1, 5)
.Add(fColorField->CreateLabelLayoutItem(), 0, 6)
.Add(fColorField->CreateMenuBarLayoutItem(), 1, 6)
.End()
.AddGlue()
.Add(fColorControl = new BColorControl(BPoint(10, 10),
B_CELLS_32x8, 8.0, "", new BMessage(MSG_COLOR_CHANGED)))
.Add(fBlinkCursor)
.Add(fAllowBold)
.Add(fUseOptionAsMetaKey)
@@ -169,18 +125,8 @@ AppearancePrefView::AppearancePrefView(const char* name,
fFontField->SetAlignment(B_ALIGN_RIGHT);
fWindowSizeField->SetAlignment(B_ALIGN_RIGHT);
fEncodingField->SetAlignment(B_ALIGN_RIGHT);
fColorField->SetAlignment(B_ALIGN_RIGHT);
fColorSchemeField->SetAlignment(B_ALIGN_RIGHT);
Revert();
BTextControl* redInput = (BTextControl*)fColorControl->ChildAt(0);
BTextControl* greenInput = (BTextControl*)fColorControl->ChildAt(1);
BTextControl* blueInput = (BTextControl*)fColorControl->ChildAt(2);
redInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
greenInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
blueInput->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
}
@@ -197,10 +143,8 @@ AppearancePrefView::Revert()
fUseOptionAsMetaKey->SetValue(pref->getBool(PREF_USE_OPTION_AS_META));
fWarnOnExit->SetValue(pref->getBool(PREF_WARN_ON_EXIT));
_SetCurrentColorScheme();
_SetEncoding(pref->getString(PREF_TEXT_ENCODING));
_SetWindowSize(pref->getInt32(PREF_ROWS), pref->getInt32(PREF_COLS));
fColorControl->SetValue(pref->getRGB(PREF_TEXT_FORE_COLOR));
const char* family = pref->getString(PREF_HALF_FONT_FAMILY);
const char* style = pref->getString(PREF_HALF_FONT_STYLE);
@@ -229,13 +173,8 @@ AppearancePrefView::AttachedToWindow()
fontSizeMenu->SetTargetForItems(this);
}
fColorControl->SetTarget(this);
fColorField->Menu()->SetTargetForItems(this);
fColorSchemeField->Menu()->SetTargetForItems(this);
fWindowSizeField->Menu()->SetTargetForItems(this);
fEncodingField->Menu()->SetTargetForItems(this);
_SetCurrentColorScheme();
}
@@ -277,55 +216,6 @@ AppearancePrefView::MessageReceived(BMessage* msg)
break;
}
case MSG_COLOR_CHANGED:
{
const BMessage* itemMessage
= fColorField->Menu()->FindMarked()->Message();
const char* label = NULL;
if (itemMessage->FindString("label", &label) != B_OK)
break;
rgb_color oldColor = PrefHandler::Default()->getRGB(label);
if (oldColor != fColorControl->ValueAsColor()) {
BMenuItem* item = fColorSchemeField->Menu()->FindMarked();
if (strcmp(item->Label(), gCustomColorScheme.name) != 0) {
item->SetMarked(false);
item = fColorSchemeField->Menu()->FindItem(
gCustomColorScheme.name);
if (item)
item->SetMarked(true);
}
PrefHandler::Default()->setRGB(label,
fColorControl->ValueAsColor());
modified = true;
}
break;
}
case MSG_COLOR_SCHEME_CHANGED:
{
color_scheme* newScheme = NULL;
if (msg->FindPointer("color_scheme",
(void**)&newScheme) == B_OK) {
_ChangeColorScheme(newScheme);
const char* label = NULL;
if (fColorField->Menu()->FindMarked()->Message()->FindString(
"label", &label) == B_OK)
fColorControl->SetValue(
PrefHandler::Default()->getRGB(label));
modified = true;
}
break;
}
case MSG_COLOR_FIELD_CHANGED:
{
const char* label = NULL;
if (msg->FindString("label", &label) == B_OK)
fColorControl->SetValue(PrefHandler::Default()->getRGB(label));
break;
}
case MSG_COLS_CHANGED:
{
int rows = msg->FindInt32("rows");
@@ -417,70 +307,6 @@ AppearancePrefView::MessageReceived(BMessage* msg)
}
void
AppearancePrefView::_ChangeColorScheme(color_scheme* scheme)
{
PrefHandler* pref = PrefHandler::Default();
pref->setRGB(PREF_TEXT_FORE_COLOR, scheme->text_fore_color);
pref->setRGB(PREF_TEXT_BACK_COLOR, scheme->text_back_color);
pref->setRGB(PREF_SELECT_FORE_COLOR, scheme->select_fore_color);
pref->setRGB(PREF_SELECT_BACK_COLOR, scheme->select_back_color);
pref->setRGB(PREF_CURSOR_FORE_COLOR, scheme->cursor_fore_color);
pref->setRGB(PREF_CURSOR_BACK_COLOR, scheme->cursor_back_color);
pref->setRGB(PREF_ANSI_BLACK_COLOR, scheme->ansi_colors.black);
pref->setRGB(PREF_ANSI_RED_COLOR, scheme->ansi_colors.red);
pref->setRGB(PREF_ANSI_GREEN_COLOR, scheme->ansi_colors.green);
pref->setRGB(PREF_ANSI_YELLOW_COLOR, scheme->ansi_colors.yellow);
pref->setRGB(PREF_ANSI_BLUE_COLOR, scheme->ansi_colors.blue);
pref->setRGB(PREF_ANSI_MAGENTA_COLOR, scheme->ansi_colors.magenta);
pref->setRGB(PREF_ANSI_CYAN_COLOR, scheme->ansi_colors.cyan);
pref->setRGB(PREF_ANSI_WHITE_COLOR, scheme->ansi_colors.white);
pref->setRGB(PREF_ANSI_BLACK_HCOLOR, scheme->ansi_colors_h.black);
pref->setRGB(PREF_ANSI_RED_HCOLOR, scheme->ansi_colors_h.red);
pref->setRGB(PREF_ANSI_GREEN_HCOLOR, scheme->ansi_colors_h.green);
pref->setRGB(PREF_ANSI_YELLOW_HCOLOR, scheme->ansi_colors_h.yellow);
pref->setRGB(PREF_ANSI_BLUE_HCOLOR, scheme->ansi_colors_h.blue);
pref->setRGB(PREF_ANSI_MAGENTA_HCOLOR, scheme->ansi_colors_h.magenta);
pref->setRGB(PREF_ANSI_CYAN_HCOLOR, scheme->ansi_colors_h.cyan);
pref->setRGB(PREF_ANSI_WHITE_HCOLOR, scheme->ansi_colors_h.white);
}
void
AppearancePrefView::_SetCurrentColorScheme()
{
PrefHandler* pref = PrefHandler::Default();
pref->LoadColorScheme(&gCustomColorScheme);
const char* currentSchemeName = NULL;
int32 i = 0;
while (i < gColorSchemes->CountItems()) {
const color_scheme *item = gColorSchemes->ItemAt(i);
i++;
if (gCustomColorScheme == *item) {
currentSchemeName = item->name;
break;
}
}
// If the scheme is not one of the known ones, assume a custom one.
if (currentSchemeName == NULL)
currentSchemeName = "Custom";
for (int32 i = 0; i < fColorSchemeField->Menu()->CountItems(); i++) {
BMenuItem* item = fColorSchemeField->Menu()->ItemAt(i);
if (strcmp(item->Label(), currentSchemeName) == 0) {
item->SetMarked(true);
break;
}
}
}
void
AppearancePrefView::_SetEncoding(const char* name)
{
@@ -633,51 +459,6 @@ AppearancePrefView::_MakeMenu(uint32 msg, const char** items,
}
/*static*/ void
AppearancePrefView::_MakeColorSchemeMenuItem(uint32 msg, const color_scheme *item,
BPopUpMenu *menu)
{
if (item == NULL)
return;
BMessage* message = new BMessage(msg);
message->AddPointer("color_scheme", (const void*)item);
menu->AddItem(new BMenuItem(item->name, message));
}
/*static*/ BPopUpMenu*
AppearancePrefView::_MakeColorSchemeMenu(uint32 msg, BObjectList<const color_scheme> *items)
{
BPopUpMenu* menu = new BPopUpMenu("");
FindColorSchemeByName comparator("Default");
const color_scheme* defaultItem = items->FindIf(comparator);
_MakeColorSchemeMenuItem(msg, defaultItem, menu);
int32 i = 0;
while (i < items->CountItems()) {
const color_scheme *item = items->ItemAt(i);
i++;
if (strcmp(item->name, "") == 0)
menu->AddSeparatorItem();
else if (item == defaultItem)
continue;
else
_MakeColorSchemeMenuItem(msg, item, menu);
}
// Add the custom item at the very end
menu->AddSeparatorItem();
_MakeColorSchemeMenuItem(msg, &gCustomColorScheme, menu);
return menu;
}
void
AppearancePrefView::_MarkSelectedFont(const char* family, const char* style,
const char* size)
-14
View File
@@ -18,9 +18,7 @@ static const uint32 MSG_HALF_FONT_CHANGED = 'mchf';
static const uint32 MSG_HALF_SIZE_CHANGED = 'mchs';
static const uint32 MSG_FULL_FONT_CHANGED = 'mcff';
static const uint32 MSG_FULL_SIZE_CHANGED = 'mcfs';
static const uint32 MSG_COLOR_FIELD_CHANGED = 'mccf';
static const uint32 MSG_COLOR_CHANGED = 'mcbc';
static const uint32 MSG_COLOR_SCHEME_CHANGED = 'mccs';
static const uint32 MSG_TAB_TITLE_SETTING_CHANGED = 'mtts';
static const uint32 MSG_WINDOW_TITLE_SETTING_CHANGED = 'mwts';
@@ -54,8 +52,6 @@ public:
virtual void AttachedToWindow();
private:
void _ChangeColorScheme(color_scheme* scheme);
void _SetCurrentColorScheme();
void _SetEncoding(const char* encoding);
void _SetWindowSize(int rows, int cols);
@@ -71,12 +67,6 @@ private:
static BPopUpMenu* _MakeMenu(uint32 msg, const char** items,
const char* defaultItem);
static BPopUpMenu* _MakeColorSchemeMenu(uint32 msg,
BObjectList<const color_scheme> *items);
static void _MakeColorSchemeMenuItem(uint32 msg,
const color_scheme *item,
BPopUpMenu* menu);
void _MarkSelectedFont(const char* family,
const char* style, const char* size);
@@ -89,10 +79,6 @@ private:
BMenuField* fWindowSizeField;
BMenuField* fEncodingField;
BMenuField* fColorSchemeField;
BMenuField* fColorField;
BColorControl* fColorControl;
BTextControl* fTabTitle;
BTextControl* fWindowTitle;
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright 2016-2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#include "ColorListView.h"
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <Bitmap.h>
#include <String.h>
#include "ColorItem.h"
#include "ThemeView.h"
// golden ratio
#ifdef M_PHI
# undef M_PHI
#endif
#define M_PHI 1.61803398874989484820
// #pragma mark - ColorListView
ColorListView::ColorListView(const char* name,
list_view_type type, uint32 flags)
:
BListView(name, type, flags)
{
}
ColorListView::~ColorListView()
{
}
bool
ColorListView::InitiateDrag(BPoint where, int32 index, bool wasSelected)
{
ColorItem* colorItem
= dynamic_cast<ColorItem*>(ItemAt(index));
if (colorItem == NULL)
return false;
rgb_color color = colorItem->Color();
BString hexStr;
hexStr.SetToFormat("#%.2X%.2X%.2X", color.red, color.green, color.blue);
BMessage message(B_PASTE);
message.AddData("text/plain", B_MIME_TYPE, hexStr.String(),
hexStr.Length());
message.AddData(kRGBColor, B_RGB_COLOR_TYPE, &color, sizeof(color));
float itemHeight = colorItem->Height() - 5;
BRect rect(0.0f, 0.0f, roundf(itemHeight * M_PHI) - 1, itemHeight - 1);
BBitmap* bitmap = new BBitmap(rect, B_RGB32, true);
if (bitmap->Lock()) {
BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW);
bitmap->AddChild(view);
view->SetHighColor(B_TRANSPARENT_COLOR);
view->FillRect(view->Bounds());
++rect.top;
++rect.left;
view->SetHighColor(0, 0, 0, 100);
view->FillRect(rect);
rect.OffsetBy(-1.0f, -1.0f);
view->SetHighColor(std::min(255, (int)(1.2 * color.red + 40)),
std::min(255, (int)(1.2 * color.green + 40)),
std::min(255, (int)(1.2 * color.blue + 40)));
view->StrokeRect(rect);
++rect.left;
++rect.top;
view->SetHighColor((int32)(0.8 * color.red),
(int32)(0.8 * color.green),
(int32)(0.8 * color.blue));
view->StrokeRect(rect);
--rect.right;
--rect.bottom;
view->SetHighColor(color.red, color.green, color.blue);
view->FillRect(rect);
view->Sync();
bitmap->Unlock();
}
DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(14.0f, 14.0f));
return true;
}
void
ColorListView::MessageReceived(BMessage* message)
{
// if we received a dropped message, see if it contains color data
if (message->WasDropped()) {
BPoint dropPoint = message->DropPoint();
ConvertFromScreen(&dropPoint);
int32 index = IndexOf(dropPoint);
ColorItem* item = dynamic_cast<ColorItem*>(ItemAt(index));
rgb_color* color;
ssize_t size;
if (item != NULL && message->FindData(kRGBColor, B_RGB_COLOR_TYPE,
(const void**)&color, &size) == B_OK) {
// build message to send to ThemeView
uint32 command = index == CurrentSelection()
? MSG_SET_CURRENT_COLOR : MSG_SET_COLOR;
BMessage setColorMessage = BMessage(command);
setColorMessage.AddData(kRGBColor, B_RGB_COLOR_TYPE, color, size);
// if setting different color, add which color to set
if (command == MSG_SET_COLOR)
setColorMessage.AddString(kName, item->Text());
// build messenger and send message
BMessenger messenger = BMessenger(Parent());
if (messenger.IsValid()) {
messenger.SendMessage(&setColorMessage);
if (command == MSG_SET_COLOR) {
// redraw item, MSG_SET_CURRENT_COLOR does this for us
item->SetColor(*color);
InvalidateItem(index);
}
}
}
}
BListView::MessageReceived(message);
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright 2016-2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* John Scipione, jscipione@gmail.com
*/
#ifndef COLORWHICH_LIST_VIEW_H
#define COLORWHICH_LIST_VIEW_H
#include <ListView.h>
class ColorListView : public BListView
{
public:
ColorListView(const char* name,
list_view_type type
= B_SINGLE_SELECTION_LIST,
uint32 flags = B_WILL_DRAW
| B_FRAME_EVENTS | B_NAVIGABLE);
virtual ~ColorListView();
virtual bool InitiateDrag(BPoint where, int32 index,
bool wasSelected);
virtual void MessageReceived(BMessage* message);
};
#endif // COLORWHICH_LIST_VIEW_H
+284
View File
@@ -0,0 +1,284 @@
/*
* Copyright 2002-2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm, darkwyrm@earthlink.net
* John Scipione, jscipione@gmail.com
*/
#include "ColorPreview.h"
#include <algorithm>
#include <stdio.h>
#include <Bitmap.h>
#include <Message.h>
#include <MessageRunner.h>
#include <String.h>
#include <View.h>
#include <Window.h>
#include "ThemeView.h"
#include "TermConst.h"
static const int32 kMsgMessageRunner = 'MsgR';
// #pragma mark - ColorPreview
ColorPreview::ColorPreview(BMessage* message, uint32 flags)
:
BControl("ColorPreview", "", message, flags | B_WILL_DRAW),
fColor(ui_color(B_PANEL_BACKGROUND_COLOR)),
fDisabledColor((rgb_color){ 128, 128, 128 }),
fMessageRunner(NULL),
fIsRectangle(true)
{
SetViewColor(B_TRANSPARENT_COLOR);
SetLowColor(0, 0, 0);
SetExplicitSize(BSize(StringWidth("M") * 8, StringWidth("M") * 7));
}
ColorPreview::~ColorPreview(void)
{
}
void
ColorPreview::Draw(BRect updateRect)
{
rgb_color color;
if (IsEnabled())
color = fColor;
else
color = fDisabledColor;
if (fIsRectangle) {
if (IsEnabled()) {
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
BRect bounds(Bounds());
BeginLineArray(4);
AddLine(BPoint(bounds.left, bounds.bottom),
BPoint(bounds.left, bounds.top), shadow);
AddLine(BPoint(bounds.left + 1.0, bounds.top),
BPoint(bounds.right, bounds.top), shadow);
AddLine(BPoint(bounds.right, bounds.top + 1.0),
BPoint(bounds.right, bounds.bottom), light);
AddLine(BPoint(bounds.right - 1.0, bounds.bottom),
BPoint(bounds.left + 1.0, bounds.bottom), light);
EndLineArray();
bounds.InsetBy(1.0, 1.0);
BeginLineArray(4);
AddLine(BPoint(bounds.left, bounds.bottom),
BPoint(bounds.left, bounds.top), darkShadow);
AddLine(BPoint(bounds.left + 1.0, bounds.top),
BPoint(bounds.right, bounds.top), darkShadow);
AddLine(BPoint(bounds.right, bounds.top + 1.0),
BPoint(bounds.right, bounds.bottom), background);
AddLine(BPoint(bounds.right - 1.0, bounds.bottom),
BPoint(bounds.left + 1.0, bounds.bottom), background);
EndLineArray();
bounds.InsetBy(1.0, 1.0);
SetHighColor(color);
FillRect(bounds);
} else {
SetHighColor(color);
FillRect(Bounds());
}
} else {
// fill background
SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
FillRect(updateRect);
SetHighColor(color);
FillEllipse(Bounds());
if (IsEnabled())
StrokeEllipse(Bounds(), B_SOLID_LOW);
}
}
void
ColorPreview::MessageReceived(BMessage* message)
{
// If we received a dropped message, see if it contains color data
if (message->WasDropped()) {
rgb_color* color;
ssize_t size;
if (message->FindData(kRGBColor, B_RGB_COLOR_TYPE,
(const void**)&color, &size) == B_OK) {
BMessage setColorMessage(MSG_SET_CURRENT_COLOR);
setColorMessage.AddData(kRGBColor, B_RGB_COLOR_TYPE, color,
sizeof(rgb_color));
Invoke(&setColorMessage);
}
} else if ((int32)message->what == kMsgMessageRunner) {
BPoint where;
uint32 buttons;
GetMouse(&where, &buttons);
_DragColor(where);
}
BControl::MessageReceived(message);
}
void
ColorPreview::MouseDown(BPoint where)
{
BWindow* window = Window();
if (window != NULL)
window->Activate();
fMessageRunner = new BMessageRunner(this, new BMessage(kMsgMessageRunner),
300000, 1);
SetMouseEventMask(B_POINTER_EVENTS,
B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS);
BRect rect = Bounds().InsetByCopy(2.0f, 2.0f);
rect.top = roundf(rect.bottom / 2.0f + 1);
if (rect.Contains(where)) {
Invalidate();
Invoke();
}
BControl::MouseDown(where);
}
void
ColorPreview::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
{
if (fMessageRunner != NULL)
_DragColor(where);
BControl::MouseMoved(where, transit, message);
}
void
ColorPreview::MouseUp(BPoint where)
{
delete fMessageRunner;
fMessageRunner = NULL;
BControl::MouseUp(where);
}
rgb_color
ColorPreview::Color(void) const
{
return fColor;
}
void
ColorPreview::SetColor(rgb_color color)
{
color.alpha = 255;
SetHighColor(color);
fColor = color;
Invalidate();
Invoke();
}
void
ColorPreview::SetColor(uint8 red, uint8 green, uint8 blue)
{
SetHighColor(red, green, blue);
fColor.red = red;
fColor.green = green;
fColor.blue = blue;
fColor.alpha = 255;
Invalidate();
Invoke();
}
void
ColorPreview::SetMode(bool rectangle)
{
fIsRectangle = rectangle;
}
// #pragma mark - ColorPreview private methods
void
ColorPreview::_DragColor(BPoint where)
{
BString hexStr;
hexStr.SetToFormat("#%.2X%.2X%.2X", fColor.red, fColor.green, fColor.blue);
BMessage message(B_PASTE);
message.AddData("text/plain", B_MIME_TYPE, hexStr.String(),
hexStr.Length());
message.AddData(kRGBColor, B_RGB_COLOR_TYPE, &fColor, sizeof(fColor));
BRect rect(0.0f, 0.0f, 20.0f, 20.0f);
BBitmap* bitmap = new BBitmap(rect, B_RGB32, true);
if (bitmap->Lock()) {
BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW);
bitmap->AddChild(view);
view->SetHighColor(B_TRANSPARENT_COLOR);
view->FillRect(view->Bounds());
++rect.top;
++rect.left;
view->SetHighColor(0, 0, 0, 100);
view->FillRect(rect);
rect.OffsetBy(-1.0f, -1.0f);
view->SetHighColor(std::min(255, (int)(1.2 * fColor.red + 40)),
std::min(255, (int)(1.2 * fColor.green + 40)),
std::min(255, (int)(1.2 * fColor.blue + 40)));
view->StrokeRect(rect);
++rect.left;
++rect.top;
view->SetHighColor((int32)(0.8 * fColor.red),
(int32)(0.8 * fColor.green),
(int32)(0.8 * fColor.blue));
view->StrokeRect(rect);
--rect.right;
--rect.bottom;
view->SetHighColor(fColor.red, fColor.green, fColor.blue);
view->FillRect(rect);
view->Sync();
bitmap->Unlock();
}
DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(14.0f, 14.0f));
MouseUp(where);
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright 2002-2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* DarkWyrm, darkwyrm@earthlink.net
* John Scipione, jscipione@gmail.com
*/
#ifndef COLOR_PREVIEW_H_
#define COLOR_PREVIEW_H_
#include <Control.h>
class BMessage;
class BMessageRunner;
class ColorPreview : public BControl
{
public:
ColorPreview(BMessage* message,
uint32 flags = B_WILL_DRAW);
~ColorPreview(void);
virtual void Draw(BRect updateRect);
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* message);
virtual void MouseUp(BPoint where);
rgb_color Color(void) const;
void SetColor(rgb_color color);
void SetColor(uint8 r, uint8 g, uint8 b);
void SetMode(bool rectangle);
private:
void _DragColor(BPoint where);
rgb_color fColor;
rgb_color fDisabledColor;
BMessageRunner* fMessageRunner;
bool fIsRectangle;
};
#endif // COLOR_PREVIEW_H_
+4
View File
@@ -11,6 +11,8 @@ Application Terminal :
Arguments.cpp
BasicTerminalBuffer.cpp
Colors.cpp
ColorListView.cpp
ColorPreview.cpp
FindWindow.cpp
Globals.cpp
HistoryBuffer.cpp
@@ -35,6 +37,8 @@ Application Terminal :
TermViewHighlight.cpp
TermViewStates.cpp
TermWindow.cpp
ThemeView.cpp
ThemeWindow.cpp
TitlePlaceholderMapper.cpp
VTKeyTbl.c
VTPrsTbl.c
+4 -4
View File
@@ -14,10 +14,10 @@
#include <Window.h>
// local messages
const ulong MSG_DEFAULTS_PRESSED = 'defl';
const ulong MSG_SAVEAS_PRESSED = 'canl';
const ulong MSG_REVERT_PRESSED = 'revt';
const ulong MSG_PREF_CLOSED = 'mspc';
const uint32 MSG_DEFAULTS_PRESSED = 'defl';
const uint32 MSG_SAVEAS_PRESSED = 'canl';
const uint32 MSG_REVERT_PRESSED = 'revt';
const uint32 MSG_PREF_CLOSED = 'mspc';
class BButton;
class BFilePanel;
+2
View File
@@ -16,6 +16,7 @@
// Application signature (Must same in Terminal.rdef)
#define TERM_SIGNATURE "application/x-vnd.Haiku-Terminal"
#define PREFFILE_MIMETYPE "text/x-terminal-pref"
#define THEMEFILE_MIMETYPE "text/x-terminal-theme"
// Signature of R5's Terminal. Needed for proper drop-in window count support
#define R5_TERM_SIGNATURE "application/x-vnd.Be-SHEL"
@@ -52,6 +53,7 @@ static const uint32 MENU_FIND_STRING = 'Mfpr';
static const uint32 MENU_FIND_NEXT = 'Mfnx';
static const uint32 MENU_FIND_PREVIOUS = 'Mfbw';
static const uint32 MENU_SHOW_COLOR = 'Mcol';
static const uint32 MENU_THEME_OPEN = 'Mthm';
static const uint32 M_GET_DEVICE_NUM = 'Mgdn';
+18 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2007-2015, Haiku, Inc. All rights reserved.
* Copyright 2007-2022, Haiku, Inc. All rights reserved.
* Copyright (c) 2004 Daniel Furrer <assimil8or@users.sourceforge.net>
* Copyright (c) 2003-2004 Kian Duffy <myob@users.sourceforge.net>
* Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
@@ -67,6 +67,8 @@
#include "ShellParameters.h"
#include "TermConst.h"
#include "TermScrollView.h"
#include "ThemeWindow.h"
#include "ThemeView.h"
#include "TitlePlaceholderMapper.h"
@@ -541,6 +543,7 @@ TermWindow::_SetupMenu()
.AddSeparator()
.AddItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS), MENU_PREF_OPEN,
',')
.AddItem(B_TRANSLATE("Theme settings" B_UTF8_ELLIPSIS), MENU_THEME_OPEN)
.End();
AddChild(fMenuBar);
@@ -768,6 +771,17 @@ TermWindow::MessageReceived(BMessage *message)
fPrefWindow = NULL;
break;
case MENU_THEME_OPEN:
if (!fThemeWindow)
fThemeWindow = new ThemeWindow(this);
else
fThemeWindow->Activate();
break;
case MSG_THEME_CLOSED:
fThemeWindow = NULL;
break;
case MSG_WINDOW_TITLE_SETTING_CHANGED:
case MSG_TAB_TITLE_SETTING_CHANGED:
_TitleSettingsChanged();
@@ -987,8 +1001,10 @@ TermWindow::MessageReceived(BMessage *message)
PostMessage(MSG_HALF_FONT_CHANGED);
break;
case MSG_COLOR_CHANGED:
case MSG_COLOR_SCHEME_CHANGED:
case MSG_SET_CURRENT_COLOR:
case MSG_SET_COLOR:
case MSG_UPDATE_COLOR:
{
for (int32 i = fTabView->CountTabs() - 1; i >= 0; i--) {
TermViewContainerView* container = _TermViewContainerViewAt(i);
+2
View File
@@ -51,6 +51,7 @@ class BMenuBar;
class FindWindow;
class PrefWindow;
class TermViewContainerView;
class ThemeWindow;
class TermWindow : public BWindow, private SmartTabView::Listener,
@@ -211,6 +212,7 @@ private:
BMessage* fPrintSettings;
PrefWindow* fPrefWindow;
ThemeWindow* fThemeWindow;
FindWindow* fFindPanel;
BRect fSavedFrame;
window_look fSavedLook;
+554
View File
@@ -0,0 +1,554 @@
/*
* Copyright 2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ThemeView.h"
#include <stdio.h>
#include <Alert.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Font.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <Messenger.h>
#include <Path.h>
#include <PopUpMenu.h>
#include <SpaceLayoutItem.h>
#include "ThemeWindow.h"
#include "Colors.h"
#include "ColorPreview.h"
#include "ColorListView.h"
#include "ColorItem.h"
#include "TermConst.h"
#include "PrefHandler.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal ThemeView"
#define COLOR_DROPPED 'cldp'
#define DECORATOR_CHANGED 'dcch'
/* static */ const char*
ThemeView::kColorTable[] = {
B_TRANSLATE_MARK("Text"),
B_TRANSLATE_MARK("Background"),
B_TRANSLATE_MARK("Cursor"),
B_TRANSLATE_MARK("Text under cursor"),
B_TRANSLATE_MARK("Selected text"),
B_TRANSLATE_MARK("Selected background"),
B_TRANSLATE_MARK("ANSI black color"),
B_TRANSLATE_MARK("ANSI red color"),
B_TRANSLATE_MARK("ANSI green color"),
B_TRANSLATE_MARK("ANSI yellow color"),
B_TRANSLATE_MARK("ANSI blue color"),
B_TRANSLATE_MARK("ANSI magenta color"),
B_TRANSLATE_MARK("ANSI cyan color"),
B_TRANSLATE_MARK("ANSI white color"),
B_TRANSLATE_MARK("ANSI bright black color"),
B_TRANSLATE_MARK("ANSI bright red color"),
B_TRANSLATE_MARK("ANSI bright green color"),
B_TRANSLATE_MARK("ANSI bright yellow color"),
B_TRANSLATE_MARK("ANSI bright blue color"),
B_TRANSLATE_MARK("ANSI bright magenta color"),
B_TRANSLATE_MARK("ANSI bright cyan color"),
B_TRANSLATE_MARK("ANSI bright white color"),
NULL
};
ThemeView::ThemeView(const char* name, const BMessenger& messenger)
:
BGroupView(name, B_VERTICAL, 5),
fTerminalMessenger(messenger)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
// Set up list of color attributes
fAttrList = new ColorListView("AttributeList");
fScrollView = new BScrollView("ScrollView", fAttrList, 0, false, true);
fScrollView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
PrefHandler* prefHandler = PrefHandler::Default();
for (const char** table = kColorTable; *table != NULL; ++table) {
fAttrList->AddItem(new ColorItem(B_TRANSLATE_NOCOLLECT(*table),
prefHandler->getRGB(*table)));
}
fColorSchemeMenu = new BPopUpMenu("");
fColorSchemeField = new BMenuField(B_TRANSLATE("Color scheme:"),
fColorSchemeMenu);
fColorPreview = new ColorPreview(new BMessage(COLOR_DROPPED), 0);
fColorPreview->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER,
B_ALIGN_VERTICAL_CENTER));
fPicker = new BColorControl(B_ORIGIN, B_CELLS_32x8, 8.0,
"picker", new BMessage(MSG_UPDATE_COLOR));
fPreview = new BTextView("preview");
BLayoutBuilder::Group<>(this)
.AddGrid()
.Add(fColorSchemeField->CreateLabelLayoutItem(), 0, 5)
.Add(fColorSchemeField->CreateMenuBarLayoutItem(), 1, 5)
.End()
.Add(fScrollView, 10.0)
.Add(fPreview)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.Add(fColorPreview)
.AddGlue()
.Add(fPicker);
fColorPreview->Parent()->SetExplicitMaxSize(
BSize(B_SIZE_UNSET, fPicker->Bounds().Height()));
fAttrList->SetSelectionMessage(new BMessage(MSG_COLOR_ATTRIBUTE_CHOSEN));
fScrollView->SetExplicitMinSize(BSize(B_SIZE_UNSET, 22 * 16));
fColorSchemeField->SetAlignment(B_ALIGN_RIGHT);
_MakeColorSchemeMenu();
_UpdateStyle();
InvalidateLayout(true);
}
ThemeView::~ThemeView()
{
}
void
ThemeView::_UpdateStyle()
{
PrefHandler* prefHandler = PrefHandler::Default();
const char* colours[] = {
B_TRANSLATE("black"),
B_TRANSLATE("red"),
B_TRANSLATE("green"),
B_TRANSLATE("yellow"),
B_TRANSLATE("blue"),
B_TRANSLATE("magenta"),
B_TRANSLATE("cyan"),
B_TRANSLATE("white"),
};
text_run_array *array = (text_run_array*)malloc(sizeof(text_run_array)
+ sizeof(text_run) * 16);
int offset = 1;
int index = 0;
array->count = 16;
array->runs[0].offset = offset;
array->runs[0].font = *be_fixed_font;
array->runs[0].color = prefHandler->getRGB(PREF_ANSI_BLACK_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[1].offset = offset;
array->runs[1].font = *be_fixed_font;
array->runs[1].color = prefHandler->getRGB(PREF_ANSI_RED_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[2].offset = offset;
array->runs[2].font = *be_fixed_font;
array->runs[2].color = prefHandler->getRGB(PREF_ANSI_GREEN_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[3].offset = offset;
array->runs[3].font = *be_fixed_font;
array->runs[3].color = prefHandler->getRGB(PREF_ANSI_YELLOW_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[4].offset = offset;
array->runs[4].font = *be_fixed_font;
array->runs[4].color = prefHandler->getRGB(PREF_ANSI_BLUE_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[5].offset = offset;
array->runs[5].font = *be_fixed_font;
array->runs[5].color = prefHandler->getRGB(PREF_ANSI_MAGENTA_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[6].offset = offset;
array->runs[6].font = *be_fixed_font;
array->runs[6].color = prefHandler->getRGB(PREF_ANSI_CYAN_COLOR);
offset += strlen(colours[index++]) + 1;
array->runs[7].offset = offset;
array->runs[7].font = *be_fixed_font;
array->runs[7].color = prefHandler->getRGB(PREF_ANSI_WHITE_COLOR);
offset += strlen(colours[index++]) + 1;
index = 0;
offset++;
array->runs[8].offset = offset;
array->runs[8].font = *be_fixed_font;
array->runs[8].color = prefHandler->getRGB(PREF_ANSI_BLACK_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[9].offset = offset;
array->runs[9].font = *be_fixed_font;
array->runs[9].color = prefHandler->getRGB(PREF_ANSI_RED_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[10].offset = offset;
array->runs[10].font = *be_fixed_font;
array->runs[10].color = prefHandler->getRGB(PREF_ANSI_GREEN_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[11].offset = offset;
array->runs[11].font = *be_fixed_font;
array->runs[11].color = prefHandler->getRGB(PREF_ANSI_YELLOW_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[12].offset = offset;
array->runs[12].font = *be_fixed_font;
array->runs[12].color = prefHandler->getRGB(PREF_ANSI_BLUE_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[13].offset = offset;
array->runs[13].font = *be_fixed_font;
array->runs[13].color = prefHandler->getRGB(PREF_ANSI_MAGENTA_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[14].offset = offset;
array->runs[14].font = *be_fixed_font;
array->runs[14].color = prefHandler->getRGB(PREF_ANSI_CYAN_HCOLOR);
offset += strlen(colours[index++]) + 1;
array->runs[15].offset = offset;
array->runs[15].font = *be_fixed_font;
array->runs[15].color = prefHandler->getRGB(PREF_ANSI_WHITE_HCOLOR);
fPreview->SetStylable(true);
fPreview->MakeEditable(false);
fPreview->MakeSelectable(false);
fPreview->SetViewColor(prefHandler->getRGB(PREF_TEXT_BACK_COLOR));
BString previewText;
previewText << '\n';
for (int ix = 0; ix < 8; ++ix)
{
previewText << ' ' << colours[ix];
}
previewText << '\n';
for (int ix = 0; ix < 8; ++ix)
{
previewText << ' ' << colours[ix];
}
previewText << '\n';
fPreview->SetAlignment(B_ALIGN_CENTER);
fPreview->SetText(previewText.String(), array);
font_height height;
be_fixed_font->GetHeight(&height);
fPreview->SetExplicitMinSize(BSize(B_SIZE_UNSET, (height.ascent + height.descent) * 5));
}
void
ThemeView::AttachedToWindow()
{
fPicker->SetTarget(this);
fAttrList->SetTarget(this);
fColorPreview->SetTarget(this);
fColorSchemeField->Menu()->SetTargetForItems(this);
fAttrList->Select(0);
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
_SetCurrentColorScheme();
}
void
ThemeView::WindowActivated(bool active)
{
if (!active)
return;
UpdateMenu();
}
void
ThemeView::UpdateMenu()
{
PrefHandler::Default()->LoadThemes();
_MakeColorSchemeMenu();
_SetCurrentColorScheme();
fColorSchemeField->Menu()->SetTargetForItems(this);
}
void
ThemeView::MessageReceived(BMessage *msg)
{
bool modified = false;
switch (msg->what) {
case MSG_COLOR_SCHEME_CHANGED:
{
color_scheme* newScheme = NULL;
if (msg->FindPointer("color_scheme",
(void**)&newScheme) == B_OK) {
_ChangeColorScheme(newScheme);
modified = true;
}
break;
}
case MSG_SET_COLOR:
{
rgb_color* color;
ssize_t size;
const char* name;
if (msg->FindData(kRGBColor, B_RGB_COLOR_TYPE,
(const void**)&color, &size) == B_OK
&& msg->FindString(kName, &name) == B_OK) {
_SetColor(name, *color);
modified = true;
}
break;
}
case MSG_SET_CURRENT_COLOR:
{
rgb_color* color;
ssize_t size;
if (msg->FindData(kRGBColor, B_RGB_COLOR_TYPE,
(const void**)&color, &size) == B_OK) {
_SetCurrentColor(*color);
modified = true;
}
break;
}
case MSG_UPDATE_COLOR:
{
// Received from the color fPicker when its color changes
rgb_color color = fPicker->ValueAsColor();
_SetCurrentColor(color);
modified = true;
break;
}
case MSG_COLOR_ATTRIBUTE_CHOSEN:
{
// Received when the user chooses a GUI fAttribute from the list
ColorItem* item = (ColorItem*)
fAttrList->ItemAt(fAttrList->CurrentSelection());
if (item == NULL)
break;
const char* label = item->Text();
rgb_color color = PrefHandler::Default()->getRGB(label);
_SetCurrentColor(color);
break;
}
case MSG_THEME_MODIFIED:
_SetCurrentColorScheme();
BView::MessageReceived(msg);
return;
default:
BView::MessageReceived(msg);
break;
}
if (modified) {
_UpdateStyle();
fTerminalMessenger.SendMessage(msg);
BMessenger messenger(this);
messenger.SendMessage(MSG_THEME_MODIFIED);
}
}
void
ThemeView::SetDefaults()
{
PrefHandler* prefHandler = PrefHandler::Default();
int32 count = fAttrList->CountItems();
for (int32 index = 0; index < count; ++index) {
ColorItem* item = (ColorItem*)fAttrList->ItemAt(index);
item->SetColor(prefHandler->getRGB(item->Text()));
fAttrList->InvalidateItem(index);
}
int32 currentIndex = fAttrList->CurrentSelection();
ColorItem* item = (ColorItem*)fAttrList->ItemAt(currentIndex);
if (item != NULL) {
rgb_color color = item->Color();
fPicker->SetValue(color);
fColorPreview->SetColor(color);
fColorPreview->Invalidate();
}
_UpdateStyle();
BMessage message(MSG_COLOR_SCHEME_CHANGED);
fTerminalMessenger.SendMessage(&message);
}
void
ThemeView::Revert()
{
_SetCurrentColorScheme();
SetDefaults();
}
void
ThemeView::_ChangeColorScheme(color_scheme* scheme)
{
PrefHandler* pref = PrefHandler::Default();
pref->setRGB(PREF_TEXT_FORE_COLOR, scheme->text_fore_color);
pref->setRGB(PREF_TEXT_BACK_COLOR, scheme->text_back_color);
pref->setRGB(PREF_SELECT_FORE_COLOR, scheme->select_fore_color);
pref->setRGB(PREF_SELECT_BACK_COLOR, scheme->select_back_color);
pref->setRGB(PREF_CURSOR_FORE_COLOR, scheme->cursor_fore_color);
pref->setRGB(PREF_CURSOR_BACK_COLOR, scheme->cursor_back_color);
pref->setRGB(PREF_ANSI_BLACK_COLOR, scheme->ansi_colors.black);
pref->setRGB(PREF_ANSI_RED_COLOR, scheme->ansi_colors.red);
pref->setRGB(PREF_ANSI_GREEN_COLOR, scheme->ansi_colors.green);
pref->setRGB(PREF_ANSI_YELLOW_COLOR, scheme->ansi_colors.yellow);
pref->setRGB(PREF_ANSI_BLUE_COLOR, scheme->ansi_colors.blue);
pref->setRGB(PREF_ANSI_MAGENTA_COLOR, scheme->ansi_colors.magenta);
pref->setRGB(PREF_ANSI_CYAN_COLOR, scheme->ansi_colors.cyan);
pref->setRGB(PREF_ANSI_WHITE_COLOR, scheme->ansi_colors.white);
pref->setRGB(PREF_ANSI_BLACK_HCOLOR, scheme->ansi_colors_h.black);
pref->setRGB(PREF_ANSI_RED_HCOLOR, scheme->ansi_colors_h.red);
pref->setRGB(PREF_ANSI_GREEN_HCOLOR, scheme->ansi_colors_h.green);
pref->setRGB(PREF_ANSI_YELLOW_HCOLOR, scheme->ansi_colors_h.yellow);
pref->setRGB(PREF_ANSI_BLUE_HCOLOR, scheme->ansi_colors_h.blue);
pref->setRGB(PREF_ANSI_MAGENTA_HCOLOR, scheme->ansi_colors_h.magenta);
pref->setRGB(PREF_ANSI_CYAN_HCOLOR, scheme->ansi_colors_h.cyan);
pref->setRGB(PREF_ANSI_WHITE_HCOLOR, scheme->ansi_colors_h.white);
int32 count = fAttrList->CountItems();
for (int32 index = 0; index < count; ++index)
{
ColorItem* item = static_cast<ColorItem*>(fAttrList->ItemAt(index));
rgb_color color = pref->getRGB(item->Text());
item->SetColor(color);
if (item->IsSelected()) {
fPicker->SetValue(color);
fColorPreview->SetColor(color);
fColorPreview->Invalidate();
}
}
fAttrList->Invalidate();
}
void
ThemeView::_SetCurrentColorScheme()
{
PrefHandler* pref = PrefHandler::Default();
pref->LoadColorScheme(&gCustomColorScheme);
const char* currentSchemeName = NULL;
int32 i = 0;
while (i < gColorSchemes->CountItems()) {
const color_scheme *item = gColorSchemes->ItemAt(i);
i++;
if (gCustomColorScheme == *item) {
currentSchemeName = item->name;
break;
}
}
// If the scheme is not one of the known ones, assume a custom one.
if (currentSchemeName == NULL)
currentSchemeName = "Custom";
for (int32 i = 0; i < fColorSchemeField->Menu()->CountItems(); i++) {
BMenuItem* item = fColorSchemeField->Menu()->ItemAt(i);
if (strcmp(item->Label(), currentSchemeName) == 0) {
item->SetMarked(true);
break;
}
}
}
void
ThemeView::_MakeColorSchemeMenuItem(const color_scheme *item)
{
if (item == NULL)
return;
BMessage* message = new BMessage(MSG_COLOR_SCHEME_CHANGED);
message->AddPointer("color_scheme", (const void*)item);
fColorSchemeMenu->AddItem(new BMenuItem(item->name, message));
}
void
ThemeView::_MakeColorSchemeMenu()
{
while (fColorSchemeMenu->CountItems() > 0)
delete(fColorSchemeMenu->RemoveItem((int32)0));
FindColorSchemeByName comparator("Default");
const color_scheme* defaultItem = gColorSchemes->FindIf(comparator);
_MakeColorSchemeMenuItem(defaultItem);
int32 index = 0;
while (index < gColorSchemes->CountItems()) {
const color_scheme *item = gColorSchemes->ItemAt(index);
index++;
if (strcmp(item->name, "") == 0)
fColorSchemeMenu->AddSeparatorItem();
else if (item == defaultItem)
continue;
else
_MakeColorSchemeMenuItem(item);
}
// Add the custom item at the very end
fColorSchemeMenu->AddSeparatorItem();
_MakeColorSchemeMenuItem(&gCustomColorScheme);
}
void
ThemeView::_SetCurrentColor(rgb_color color)
{
int32 currentIndex = fAttrList->CurrentSelection();
ColorItem* item = (ColorItem*)fAttrList->ItemAt(currentIndex);
if (item != NULL) {
item->SetColor(color);
fAttrList->InvalidateItem(currentIndex);
PrefHandler::Default()->setRGB(item->Text(), color);
}
fPicker->SetValue(color);
fColorPreview->SetColor(color);
fColorPreview->Invalidate();
}
void
ThemeView::_SetColor(const char* name, rgb_color color)
{
PrefHandler::Default()->setRGB(name, color);
_UpdateStyle();
}
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright 2022, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef THEME_VIEW_H
#define THEME_VIEW_H
#include <Button.h>
#include <ColorControl.h>
#include <GroupView.h>
#include <ListItem.h>
#include <ListView.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Message.h>
#include <Messenger.h>
#include <ObjectList.h>
#include <ScrollBar.h>
#include <ScrollView.h>
#include <String.h>
#include <StringView.h>
#include <View.h>
#include "Colors.h"
static const uint32 MSG_COLOR_SCHEME_CHANGED = 'mccs';
static const uint32 MSG_SET_CURRENT_COLOR = 'sccl';
static const uint32 MSG_UPDATE_COLOR = 'upcl';
static const uint32 MSG_COLOR_ATTRIBUTE_CHOSEN = 'atch';
static const uint32 MSG_THEME_MODIFIED = 'tmdf';
static const uint32 MSG_SET_COLOR = 'sclr';
static const char* const kRGBColor = "RGBColor";
static const char* const kName = "name";
class ThemeWindow;
class ColorPreview;
class BMenu;
class BMenuField;
class BPopUpMenu;
class BTextView;
class ThemeView : public BGroupView {
public:
ThemeView(const char *name,
const BMessenger &messenger);
virtual ~ThemeView();
virtual void AttachedToWindow();
virtual void WindowActivated(bool active);
virtual void MessageReceived(BMessage *msg);
void SetDefaults();
void Revert();
void UpdateMenu();
private:
void _UpdateStyle();
void _ChangeColorScheme(color_scheme* scheme);
void _SetCurrentColorScheme();
void _SetCurrentColor(rgb_color color);
void _SetColor(const char* name, rgb_color color);
void _MakeColorSchemeMenu();
void _MakeColorSchemeMenuItem(const color_scheme *item);
private:
BColorControl* fPicker;
BListView* fAttrList;
const char* fName;
BScrollView* fScrollView;
ColorPreview* fColorPreview;
BMenuField* fColorSchemeField;
BPopUpMenu* fColorSchemeMenu;
BTextView* fPreview;
BMessage fPrevColors;
BMessage fDefaultColors;
BMessage fCurrentColors;
BMessenger fTerminalMessenger;
public:
static const char* kColorTable[];
};
#endif // THEME_VIEW_H
+205
View File
@@ -0,0 +1,205 @@
/*
* Copyright 2022, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "ThemeWindow.h"
#include <stdio.h>
#include <Button.h>
#include <Catalog.h>
#include <Directory.h>
#include <File.h>
#include <FilePanel.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <Messenger.h>
#include <Path.h>
#include <SeparatorView.h>
#include "PrefHandler.h"
#include "TermConst.h"
#include "ThemeView.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal ThemeWindow"
// local messages
const uint32 MSG_DEFAULTS_PRESSED = 'defl';
const uint32 MSG_SAVEAS_PRESSED = 'canl';
const uint32 MSG_REVERT_PRESSED = 'revt';
ThemeWindow::ThemeWindow(const BMessenger& messenger)
:
BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Theme settings"), B_TITLED_WINDOW,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
fPreviousPref(new PrefHandler(PrefHandler::Default())),
fSavePanel(NULL),
fDirty(false),
fTerminalMessenger(messenger)
{
fDefaultsButton = new BButton("defaults", B_TRANSLATE("Defaults"),
new BMessage(MSG_DEFAULTS_PRESSED), B_WILL_DRAW);
fRevertButton = new BButton("revert", B_TRANSLATE("Revert"),
new BMessage(MSG_REVERT_PRESSED), B_WILL_DRAW);
fSaveAsFileButton = new BButton("savebutton",
B_TRANSLATE("Save to file" B_UTF8_ELLIPSIS),
new BMessage(MSG_SAVEAS_PRESSED), B_WILL_DRAW);
fThemeView = new ThemeView(B_TRANSLATE("Theme"), fTerminalMessenger);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(B_USE_WINDOW_SPACING)
.Add(fThemeView)
.AddGroup(B_HORIZONTAL)
.Add(fDefaultsButton)
.Add(fRevertButton)
.AddGlue()
.Add(fSaveAsFileButton)
.SetInsets(0, B_USE_DEFAULT_SPACING, 0, 0);
fRevertButton->SetEnabled(fDirty);
AddShortcut('Q', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
CenterOnScreen();
Show();
}
void
ThemeWindow::Quit()
{
fTerminalMessenger.SendMessage(MSG_THEME_CLOSED);
delete fPreviousPref;
delete fSavePanel;
BWindow::Quit();
}
bool
ThemeWindow::QuitRequested()
{
if (fDirty)
_Save();
return true;
}
void
ThemeWindow::_SaveAs()
{
if (!fSavePanel) {
BMessenger messenger(this);
fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger);
}
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
path.Append("Terminal/Themes");
create_directory(path.Path(), 0755);
fSavePanel->SetPanelDirectory(path.Path());
}
fSavePanel->Show();
}
void
ThemeWindow::_SaveRequested(BMessage *msg)
{
entry_ref dirref;
const char* filename;
msg->FindRef("directory", &dirref);
msg->FindString("name", &filename);
BDirectory dir(&dirref);
BPath path(&dir, filename);
PrefHandler *prefHandler = PrefHandler::Default();
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
char buffer[512];
for (const char** table = ThemeView::kColorTable; *table != NULL; ++table) {
int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
*table, prefHandler->getString(*table));
file.Write(buffer, len);
}
// Name the theme after the filename
int len = snprintf(buffer, sizeof(buffer), "\"%s\" , \"%s\"\n",
PREF_THEME_NAME, filename);
file.Write(buffer, len);
fThemeView->UpdateMenu();
}
void
ThemeWindow::_Save()
{
delete fPreviousPref;
fPreviousPref = new PrefHandler(PrefHandler::Default());
PrefHandler::Default()->SaveDefaultAsText();
fDirty = false;
}
void
ThemeWindow::_Revert()
{
if (fDirty) {
PrefHandler::SetDefault(new PrefHandler(fPreviousPref));
fThemeView->Revert();
fDirty = false;
fRevertButton->SetEnabled(fDirty);
}
}
void
ThemeWindow::MessageReceived(BMessage *message)
{
switch (message->what) {
case MSG_SAVEAS_PRESSED:
_SaveAs();
break;
case MSG_REVERT_PRESSED:
_Revert();
break;
case MSG_DEFAULTS_PRESSED:
PrefHandler::SetDefault(new PrefHandler(false));
fThemeView->SetDefaults();
// fallthrough
case MSG_THEME_MODIFIED:
fDirty = true;
fRevertButton->SetEnabled(fDirty);
break;
case B_SAVE_REQUESTED:
_SaveRequested(message);
break;
default:
BWindow::MessageReceived(message);
break;
}
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2022, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef THEME_WINDOW_H
#define THEME_WINDOW_H
#include <Application.h>
#include <Button.h>
#include <Window.h>
#include <Message.h>
// local messages
const uint32 MSG_THEME_CLOSED = 'mstc';
class BFilePanel;
class PrefHandler;
class ThemeView;
class ThemeWindow : public BWindow {
public:
ThemeWindow(const BMessenger &messenger);
virtual ~ThemeWindow() {};
virtual void MessageReceived(BMessage *message);
virtual void Quit();
virtual bool QuitRequested();
private:
void _Save();
void _SaveAs();
void _Revert();
void _SaveRequested(BMessage *message);
PrefHandler* fPreviousPref;
BFilePanel* fSavePanel;
ThemeView* fThemeView;
BButton* fDefaultsButton;
BButton* fRevertButton;
BButton* fSaveAsFileButton;
bool fDirty;
BMessenger fTerminalMessenger;
};
#endif