Applied patch by Brian Luft to clean up the shortcuts GUI and bring it more

into HIG compliance. Resolves part of #5420. Thanks!



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42363 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Rene Gollent
2011-07-02 16:01:05 +00:00
parent f4e0b8d03a
commit ce59b51ce3
6 changed files with 199 additions and 151 deletions
-1
View File
@@ -6,7 +6,6 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons input_server filters shortc
Preference Shortcuts : Preference Shortcuts :
main.cpp main.cpp
MetaKeyStateMap.cpp MetaKeyStateMap.cpp
ResizableButton.cpp
ShortcutsApp.cpp ShortcutsApp.cpp
ShortcutsSpec.cpp ShortcutsSpec.cpp
ShortcutsWindow.cpp ShortcutsWindow.cpp
@@ -1,37 +0,0 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#include "ResizableButton.h"
ResizableButton::ResizableButton(BRect parentFrame, BRect frame,
const char* name, const char* label, BMessage* message)
:
BButton(frame, name, label, message, B_FOLLOW_BOTTOM)
{
float width = parentFrame.right - parentFrame.left;
float height = parentFrame.bottom - parentFrame.top;
fPercentages.left = frame.left / width;
fPercentages.top = frame.top / height;
fPercentages.right = frame.right / width;
fPercentages.bottom = frame.bottom / height;
}
void
ResizableButton::ChangeToNewSize(float newWidth, float newHeight)
{
float newX = fPercentages.left* newWidth;
float newW = (fPercentages.right* newWidth) - newX;
BRect b = Frame();
MoveBy(newX - b.left, 0);
ResizeTo(newW, b.bottom - b.top);
Invalidate();
}
@@ -1,28 +0,0 @@
/*
* Copyright 1999-2009 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Jeremy Friesner
*/
#ifndef ResizableButton_h
#define ResizableButton_h
#include <Button.h>
class ResizableButton : public BButton {
public:
ResizableButton(BRect parentFrame, BRect frame,
const char* name, const char* label,
BMessage* message);
virtual void ChangeToNewSize(float newWidth, float newHeight);
private:
BRect fPercentages;
};
#endif
@@ -360,6 +360,12 @@ ShortcutsSpec::DrawItemColumn(BView* owner, BRect item_column_rect,
if (text == NULL) if (text == NULL)
return; return;
_CacheViewFont(owner);
// Ensure that sViewFont is configured before using it to calculate
// widths. The lack of this call was causing the initial display of
// columns to be incorrect, with a "jump" as all the columns correct
// themselves upon the first column resize.
float textWidth = sViewFont.StringWidth(text); float textWidth = sViewFont.StringWidth(text);
BPoint point; BPoint point;
rgb_color lowColor = color; rgb_color lowColor = color;
+182 -75
View File
@@ -15,21 +15,27 @@
#include <Alert.h> #include <Alert.h>
#include <Application.h> #include <Application.h>
#include <Button.h>
#include <Catalog.h> #include <Catalog.h>
#include <Clipboard.h> #include <Clipboard.h>
#include <ControlLook.h>
#include <File.h> #include <File.h>
#include <FilePanel.h>
#include <FindDirectory.h> #include <FindDirectory.h>
#include <Input.h> #include <Input.h>
#include <Locale.h> #include <Locale.h>
#include <Message.h>
#include <Menu.h> #include <Menu.h>
#include <MenuBar.h> #include <MenuBar.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <MessageFilter.h> #include <MessageFilter.h>
#include <Path.h> #include <Path.h>
#include <PopUpMenu.h> #include <PopUpMenu.h>
#include <Screen.h>
#include <ScrollBar.h> #include <ScrollBar.h>
#include <ScrollView.h> #include <ScrollView.h>
#include <String.h> #include <String.h>
#include <SupportDefs.h>
#include "ColumnListView.h" #include "ColumnListView.h"
@@ -41,14 +47,17 @@
// Window sizing constraints // Window sizing constraints
#define MIN_WIDTH 600 #define MAX_WIDTH 10000
#define MIN_HEIGHT 130 #define MAX_HEIGHT 10000
#define MAX_WIDTH 65535 // SetSizeLimits does not provide a mechanism for specifying an
#define MAX_HEIGHT 65535 // unrestricted maximum. 10,000 seems to be the most common value used
// in other Haiku system applications.
// Default window position #define WINDOW_SETTINGS_FILE_NAME "Shortcuts_window_settings"
#define WINDOW_START_X 30 // Because the "shortcuts_settings" file (SHORTCUTS_SETTING_FILE_NAME) is
#define WINDOW_START_Y 100 // already used as a communications method between this configurator and
// the "shortcut_catcher" input_server filter, it should not be overloaded
// with window position information. Instead, a separate file is used.
#undef B_TRANSLATE_CONTEXT #undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "ShortcutsWindow" #define B_TRANSLATE_CONTEXT "ShortcutsWindow"
@@ -56,9 +65,6 @@
#define ERROR "Shortcuts error" #define ERROR "Shortcuts error"
#define WARNING "Shortcuts warning" #define WARNING "Shortcuts warning"
// Global constants for Shortcuts
#define V_SPACING 5 // vertical spacing between GUI components
// Creates a pop-up-menu that reflects the possible states of the specified // Creates a pop-up-menu that reflects the possible states of the specified
// meta-key. // meta-key.
@@ -94,9 +100,8 @@ CreateKeysPopUp()
ShortcutsWindow::ShortcutsWindow() ShortcutsWindow::ShortcutsWindow()
: :
BWindow(BRect(WINDOW_START_X, WINDOW_START_Y, WINDOW_START_X + MIN_WIDTH, BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Shortcuts"),
WINDOW_START_Y + MIN_HEIGHT * 2), B_TRANSLATE_SYSTEM_NAME("Shortcuts"), B_TITLED_WINDOW, 0L),
B_DOCUMENT_WINDOW, 0L),
fSavePanel(NULL), fSavePanel(NULL),
fOpenPanel(NULL), fOpenPanel(NULL),
fSelectPanel(NULL), fSelectPanel(NULL),
@@ -104,57 +109,66 @@ ShortcutsWindow::ShortcutsWindow()
fLastOpenWasAppend(false) fLastOpenWasAppend(false)
{ {
ShortcutsSpec::InitializeMetaMaps(); ShortcutsSpec::InitializeMetaMaps();
float spacing = be_control_look->DefaultItemSpacing();
BView* top = new BView(Bounds(), NULL, B_FOLLOW_ALL_SIDES, 0);
top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(top);
SetSizeLimits(MIN_WIDTH, MAX_WIDTH, MIN_HEIGHT, MAX_HEIGHT);
BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "Menu Bar"); BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "Menu Bar");
BMenu* fileMenu = new BMenu(B_TRANSLATE("File")); BMenu* fileMenu = new BMenu(B_TRANSLATE("File"));
fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Open KeySet" B_UTF8_ELLIPSIS), fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Open KeySet" B_UTF8_ELLIPSIS),
new BMessage(OPEN_KEYSET), 'O')); new BMessage(OPEN_KEYSET), 'O'));
fileMenu->AddItem(new BMenuItem( fileMenu->AddItem(new BMenuItem(
B_TRANSLATE("Append KeySet" B_UTF8_ELLIPSIS), B_TRANSLATE("Append KeySet" B_UTF8_ELLIPSIS),
new BMessage(APPEND_KEYSET), 'A')); new BMessage(APPEND_KEYSET), 'A'));
fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Revert to saved"), fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Revert to saved"),
new BMessage(REVERT_KEYSET), 'A')); new BMessage(REVERT_KEYSET), 'A'));
fileMenu->AddItem(new BSeparatorItem); fileMenu->AddItem(new BSeparatorItem);
fileMenu->AddItem(new BMenuItem( fileMenu->AddItem(new BMenuItem(
B_TRANSLATE("Save KeySet as" B_UTF8_ELLIPSIS), B_TRANSLATE("Save KeySet as" B_UTF8_ELLIPSIS),
new BMessage(SAVE_KEYSET_AS), 'S')); new BMessage(SAVE_KEYSET_AS), 'S'));
fileMenu->AddItem(new BSeparatorItem); fileMenu->AddItem(new BSeparatorItem);
fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"), fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
new BMessage(B_QUIT_REQUESTED), 'Q')); new BMessage(B_QUIT_REQUESTED), 'Q'));
menuBar->AddItem(fileMenu); menuBar->AddItem(fileMenu);
AddChild(menuBar); top->AddChild(menuBar);
font_height fh;
be_plain_font->GetHeight(&fh);
float vButtonHeight = ceil(fh.ascent) + ceil(fh.descent) + 5.0f;
BRect tableBounds = Bounds(); BRect tableBounds = Bounds();
tableBounds.top = menuBar->Bounds().bottom + 1; tableBounds.top = menuBar->Bounds().bottom + 1;
tableBounds.right -= B_V_SCROLL_BAR_WIDTH; tableBounds.right -= B_V_SCROLL_BAR_WIDTH;
tableBounds.bottom -= (B_H_SCROLL_BAR_HEIGHT + V_SPACING + vButtonHeight + tableBounds.bottom -= B_H_SCROLL_BAR_HEIGHT;
V_SPACING * 2);
BScrollView* containerView; BScrollView* containerView;
fColumnListView = new ColumnListView(tableBounds, &containerView, NULL, fColumnListView = new ColumnListView(tableBounds, &containerView, NULL,
B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE,
B_SINGLE_SELECTION_LIST, true, true, true, B_NO_BORDER); B_SINGLE_SELECTION_LIST, true, true, true, B_NO_BORDER);
fColumnListView->SetEditMessage(new BMessage(HOTKEY_ITEM_MODIFIED), fColumnListView->SetEditMessage(new BMessage(HOTKEY_ITEM_MODIFIED),
BMessenger(this)); BMessenger(this));
const float metaWidth = 50.0f; float minListWidth = 0;
// A running total is kept as the columns are created.
float cellWidth = be_plain_font->StringWidth("Either") + 20;
// ShortcutsSpec does not seem to translate the string "Either".
for (int i = 0; i < ShortcutsSpec::NUM_META_COLUMNS; i++) { for (int i = 0; i < ShortcutsSpec::NUM_META_COLUMNS; i++) {
const char* name = ShortcutsSpec::GetColumnName(i);
float headerWidth = be_plain_font->StringWidth(name) + 20;
float width = max_c(headerWidth, cellWidth);
minListWidth += width + 1;
fColumnListView->AddColumn( fColumnListView->AddColumn(
new CLVColumn(ShortcutsSpec::GetColumnName(i), CreateMetaPopUp(i), new CLVColumn(name, CreateMetaPopUp(i), width, CLV_SORT_KEYABLE));
metaWidth, CLV_SORT_KEYABLE));
} }
float keyCellWidth = be_plain_font->StringWidth("Caps Lock") + 20;
fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Key"), fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Key"),
CreateKeysPopUp(), 60, CLV_SORT_KEYABLE)); CreateKeysPopUp(), keyCellWidth, CLV_SORT_KEYABLE));
minListWidth += keyCellWidth + 1;
BPopUpMenu* popup = new BPopUpMenu(NULL, false); BPopUpMenu* popup = new BPopUpMenu(NULL, false);
popup->AddItem(new BMenuItem( popup->AddItem(new BMenuItem(
@@ -177,48 +191,77 @@ ShortcutsWindow::ShortcutsWindow()
popup->AddItem(new BMenuItem(B_TRANSLATE("*Beep"), NULL)); popup->AddItem(new BMenuItem(B_TRANSLATE("*Beep"), NULL));
fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Application"), popup, fColumnListView->AddColumn(new CLVColumn(B_TRANSLATE("Application"), popup,
323.0, CLV_SORT_KEYABLE)); 323.0, CLV_SORT_KEYABLE));
minListWidth += 323.0 + 1;
minListWidth += B_V_SCROLL_BAR_WIDTH;
fColumnListView->SetSortFunction(ShortcutsSpec::MyCompare); fColumnListView->SetSortFunction(ShortcutsSpec::MyCompare);
AddChild(containerView); top->AddChild(containerView);
fColumnListView->SetSelectionMessage(new BMessage(HOTKEY_ITEM_SELECTED)); fColumnListView->SetSelectionMessage(new BMessage(HOTKEY_ITEM_SELECTED));
fColumnListView->SetTarget(this); fColumnListView->SetTarget(this);
BRect buttonBounds = Bounds(); fAddButton = new BButton(BRect(0, 0, 0, 0), "add",
buttonBounds.left += V_SPACING; B_TRANSLATE("Add new shortcut"), new BMessage(ADD_HOTKEY_ITEM),
buttonBounds.right = ((buttonBounds.right - buttonBounds.left) / 2.0f) B_FOLLOW_BOTTOM);
+ buttonBounds.left; fAddButton->ResizeToPreferred();
buttonBounds.bottom -= V_SPACING * 2; fAddButton->MoveBy(spacing,
buttonBounds.top = buttonBounds.bottom - vButtonHeight; Bounds().bottom - fAddButton->Bounds().bottom - spacing);
buttonBounds.right -= B_V_SCROLL_BAR_WIDTH; top->AddChild(fAddButton);
float origRight = buttonBounds.right;
buttonBounds.right = (buttonBounds.left + origRight) * 0.40f - fRemoveButton = new BButton(BRect(0, 0, 0, 0), "remove",
(V_SPACING / 2); B_TRANSLATE("Remove selected shortcut"),
AddChild(fAddButton = new ResizableButton(Bounds(), buttonBounds, "add", new BMessage(REMOVE_HOTKEY_ITEM), B_FOLLOW_BOTTOM);
B_TRANSLATE("Add new shortcut"), new BMessage(ADD_HOTKEY_ITEM))); fRemoveButton->ResizeToPreferred();
buttonBounds.left = buttonBounds.right + V_SPACING; fRemoveButton->MoveBy(fAddButton->Frame().right + spacing,
buttonBounds.right = origRight; Bounds().bottom - fRemoveButton->Bounds().bottom - spacing);
AddChild(fRemoveButton = new ResizableButton(Bounds(), buttonBounds, top->AddChild(fRemoveButton);
"remove", B_TRANSLATE("Remove selected shortcut"),
new BMessage(REMOVE_HOTKEY_ITEM)));
fRemoveButton->SetEnabled(false); fRemoveButton->SetEnabled(false);
float offset = (buttonBounds.right - buttonBounds.left) / 2.0f; fSaveButton = new BButton(BRect(0, 0, 0, 0), "save",
BRect saveButtonBounds = buttonBounds; B_TRANSLATE("Save & apply"), new BMessage(SAVE_KEYSET),
saveButtonBounds.right = Bounds().right - B_V_SCROLL_BAR_WIDTH - offset; B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT);
saveButtonBounds.left = buttonBounds.right + V_SPACING + offset; fSaveButton->ResizeToPreferred();
AddChild(fSaveButton = new ResizableButton(Bounds(), saveButtonBounds, fSaveButton->MoveBy(Bounds().right - fSaveButton->Bounds().right - spacing,
"save", B_TRANSLATE("Save & apply"), new BMessage(SAVE_KEYSET))); Bounds().bottom - fSaveButton->Bounds().bottom - spacing);
top->AddChild(fSaveButton);
fSaveButton->SetEnabled(false); fSaveButton->SetEnabled(false);
entry_ref ref; containerView->ResizeBy(0,
if (_GetSettingsFile(&ref)) { -(fAddButton->Bounds().bottom + 2 * spacing + 2));
float minButtonBarWidth = fRemoveButton->Frame().right
+ fSaveButton->Bounds().right + 2 * spacing;
float minWidth = max_c(minListWidth, minButtonBarWidth);
float menuBarHeight = menuBar->Bounds().bottom;
float buttonBarHeight = Bounds().bottom - containerView->Frame().bottom;
float minHeight = menuBarHeight + 200 + buttonBarHeight;
SetSizeLimits(minWidth, MAX_WIDTH, minHeight, MAX_HEIGHT);
// SetSizeLimits() will resize the window to the minimum size.
CenterOnScreen();
entry_ref windowSettingsRef;
if (_GetWindowSettingsFile(&windowSettingsRef)) {
// The window settings file is not accepted via B_REFS_RECEIVED; this
// is a behind-the-scenes file that the user will never see or
// interact with.
BFile windowSettingsFile(&windowSettingsRef, B_READ_ONLY);
BMessage loadMsg;
if (loadMsg.Unflatten(&windowSettingsFile) == B_OK)
_LoadWindowSettings(loadMsg);
}
entry_ref keySetRef;
if (_GetSettingsFile(&keySetRef)) {
BMessage msg(B_REFS_RECEIVED); BMessage msg(B_REFS_RECEIVED);
msg.AddRef("refs", &ref); msg.AddRef("refs", &keySetRef);
msg.AddString("startupRef", "please"); msg.AddString("startupRef", "please");
PostMessage(&msg); // Tell ourself to load this file if it exists. PostMessage(&msg);
// Tell ourselves to load this file if it exists.
} }
Show(); Show();
} }
@@ -270,8 +313,17 @@ ShortcutsWindow::QuitRequested()
} }
} }
if (ret) if (ret) {
fColumnListView->DeselectAll(); fColumnListView->DeselectAll();
// Save the window position.
entry_ref ref;
if (_GetWindowSettingsFile(&ref)) {
BEntry entry(&ref);
_SaveWindowSettings(entry);
}
}
return ret; return ret;
} }
@@ -339,6 +391,70 @@ ShortcutsWindow::_LoadKeySet(const BMessage& loadMsg)
} }
// Gets the filesystem location of the "Shortcuts_window_settings" file.
bool
ShortcutsWindow::_GetWindowSettingsFile(entry_ref* eref)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
return false;
else
path.Append(WINDOW_SETTINGS_FILE_NAME);
return BEntry(path.Path(), true).GetRef(eref) == B_OK;
}
// Saves the application settings file to (saveEntry). Because this is a
// non-essential file, errors are ignored when writing the settings.
void
ShortcutsWindow::_SaveWindowSettings(BEntry& saveEntry)
{
BFile saveTo(&saveEntry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
if (saveTo.InitCheck() != B_OK)
return;
BMessage saveMsg;
saveMsg.AddRect("window frame", Frame());
for (int i = 0; i < fColumnListView->CountColumns(); i++) {
CLVColumn* column = fColumnListView->ColumnAt(i);
saveMsg.AddFloat("column width", column->Width());
}
saveMsg.Flatten(&saveTo);
}
// Loads the application settings file from (loadMsg) and resizes the interface
// to match the previously saved settings. Because this is a non-essential
// file, errors are ignored when loading the settings.
void
ShortcutsWindow::_LoadWindowSettings(const BMessage& loadMsg)
{
BRect frame;
if (loadMsg.FindRect("window frame", &frame) == B_OK) {
// Ensure the frame does not resize below the computed minimum.
float width = max_c(Bounds().right, frame.right - frame.left);
float height = max_c(Bounds().bottom, frame.bottom - frame.top);
ResizeTo(width, height);
// Ensure the frame is not placed outside of the screen.
BScreen screen(this);
float left = min_c(screen.Frame().right - width, frame.left);
float top = min_c(screen.Frame().bottom - height, frame.top);
MoveTo(left, top);
}
for (int i = 0; i < fColumnListView->CountColumns(); i++) {
CLVColumn* column = fColumnListView->ColumnAt(i);
float columnWidth;
if (loadMsg.FindFloat("column width", i, &columnWidth) == B_OK)
column->SetWidth(max_c(column->Width(), columnWidth));
}
}
// Creates a new entry and adds it to the GUI. (defaultCommand) will be the // Creates a new entry and adds it to the GUI. (defaultCommand) will be the
// text in the entry, or NULL if no text is desired. // text in the entry, or NULL if no text is desired.
void void
@@ -659,15 +775,6 @@ ShortcutsWindow::Quit()
} }
void
ShortcutsWindow::FrameResized(float w, float h)
{
fAddButton->ChangeToNewSize(w, h);
fRemoveButton->ChangeToNewSize(w, h);
fSaveButton->ChangeToNewSize(w, h);
}
void void
ShortcutsWindow::DispatchMessage(BMessage* msg, BHandler* handler) ShortcutsWindow::DispatchMessage(BMessage* msg, BHandler* handler)
{ {
+11 -10
View File
@@ -10,14 +10,13 @@
#include <Entry.h> #include <Entry.h>
#include <FilePanel.h>
#include <Message.h>
#include <Point.h>
#include <Window.h> #include <Window.h>
#include "ColumnListView.h" #include "ColumnListView.h"
#include "ResizableButton.h"
class BButton;
class BFilePanel;
class BMessage;
// This class defines our preferences/configuration window. // This class defines our preferences/configuration window.
class ShortcutsWindow : public BWindow { class ShortcutsWindow : public BWindow {
@@ -27,8 +26,7 @@ public:
virtual void DispatchMessage(BMessage* msg, BHandler* handler); virtual void DispatchMessage(BMessage* msg, BHandler* handler);
virtual void Quit(); virtual void Quit();
virtual void FrameResized(float w, float h); virtual void MessageReceived(BMessage* msg);
virtual void MessageReceived(BMessage * msg);
virtual bool QuitRequested(); virtual bool QuitRequested();
// BMessage 'what' codes, representing commands understood by this Window. // BMessage 'what' codes, representing commands understood by this Window.
@@ -57,12 +55,15 @@ private:
void _AddNewSpec(const char* defaultCommand); void _AddNewSpec(const char* defaultCommand);
void _MarkKeySetModified(); void _MarkKeySetModified();
bool _LoadKeySet(const BMessage& loadMsg); bool _LoadKeySet(const BMessage& loadMsg);
bool _SaveKeySet(BEntry & saveEntry); bool _SaveKeySet(BEntry& saveEntry);
bool _GetSettingsFile(entry_ref* ref); bool _GetSettingsFile(entry_ref* ref);
void _LoadWindowSettings(const BMessage& loadMsg);
void _SaveWindowSettings(BEntry& saveEntry);
bool _GetWindowSettingsFile(entry_ref* ref);
ResizableButton* fAddButton; BButton* fAddButton;
ResizableButton* fRemoveButton; BButton* fRemoveButton;
ResizableButton* fSaveButton; BButton* fSaveButton;
ColumnListView* fColumnListView; ColumnListView* fColumnListView;
BFilePanel* fSavePanel; // for saving settings BFilePanel* fSavePanel; // for saving settings
BFilePanel* fOpenPanel; // for loading settings BFilePanel* fOpenPanel; // for loading settings