So here it goes..
I hope I have fixed all parts that don't follow our guidelines. (that python script was good start) This are the app, I havn't change the file in clv those are from Santa gift bag git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33848 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -21,6 +21,7 @@ SubInclude HAIKU_TOP src preferences opengl ;
|
|||||||
SubInclude HAIKU_TOP src preferences print ;
|
SubInclude HAIKU_TOP src preferences print ;
|
||||||
SubInclude HAIKU_TOP src preferences screen ;
|
SubInclude HAIKU_TOP src preferences screen ;
|
||||||
SubInclude HAIKU_TOP src preferences screensaver ;
|
SubInclude HAIKU_TOP src preferences screensaver ;
|
||||||
|
SubInclude HAIKU_TOP src preferences shortcuts ;
|
||||||
SubInclude HAIKU_TOP src preferences sounds ;
|
SubInclude HAIKU_TOP src preferences sounds ;
|
||||||
SubInclude HAIKU_TOP src preferences time ;
|
SubInclude HAIKU_TOP src preferences time ;
|
||||||
SubInclude HAIKU_TOP src preferences touchpad ;
|
SubInclude HAIKU_TOP src preferences touchpad ;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
SubDir HAIKU_TOP src preferences shortcuts ;
|
||||||
|
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src preferences shortcuts clv ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons input_server filters shortcut_catcher ] ;
|
||||||
|
|
||||||
|
Preference Shortcuts :
|
||||||
|
main.cpp
|
||||||
|
MetaKeyStateMap.cpp
|
||||||
|
ResizableButton.cpp
|
||||||
|
ShortcutsApp.cpp
|
||||||
|
ShortcutsSpec.cpp
|
||||||
|
ShortcutsWindow.cpp
|
||||||
|
|
||||||
|
# clv files
|
||||||
|
CLVColumn.cpp
|
||||||
|
CLVColumnLabelView.cpp
|
||||||
|
CLVListItem.cpp
|
||||||
|
ColumnListView.cpp
|
||||||
|
MouseWatcher.cpp
|
||||||
|
PrefilledBitmap.cpp
|
||||||
|
ScrollViewCorner.cpp
|
||||||
|
|
||||||
|
: be tracker libshortcuts_shared.a $(TARGET_LIBSTDC++)
|
||||||
|
: Shortcuts.rsrc
|
||||||
|
;
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "MetaKeyStateMap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "BitFieldTesters.h"
|
||||||
|
|
||||||
|
|
||||||
|
MetaKeyStateMap::MetaKeyStateMap()
|
||||||
|
:
|
||||||
|
fKeyName(NULL)
|
||||||
|
{
|
||||||
|
// User MUST call SetInfo() before using!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MetaKeyStateMap::MetaKeyStateMap(const char* name)
|
||||||
|
{
|
||||||
|
SetInfo(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MetaKeyStateMap::SetInfo(const char* keyName)
|
||||||
|
{
|
||||||
|
fKeyName = new char[strlen(keyName) + 1];
|
||||||
|
strcpy(fKeyName, keyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MetaKeyStateMap::~MetaKeyStateMap()
|
||||||
|
{
|
||||||
|
delete [] fKeyName;
|
||||||
|
int nr = fStateDescs.CountItems();
|
||||||
|
for (int i = 0; i < nr; i++)
|
||||||
|
delete [] ((const char*) fStateDescs.ItemAt(i));
|
||||||
|
|
||||||
|
nr = fStateTesters.CountItems();
|
||||||
|
for (int j = 0; j < nr; j++)
|
||||||
|
delete ((BitFieldTester*) fStateTesters.ItemAt(j));
|
||||||
|
// _stateBits are stored in-line, no need to delete them
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MetaKeyStateMap::AddState(const char* d, const BitFieldTester* t)
|
||||||
|
{
|
||||||
|
char* copy = new char[strlen(d) + 1];
|
||||||
|
strcpy(copy, d);
|
||||||
|
fStateDescs.AddItem(copy);
|
||||||
|
fStateTesters.AddItem((void *)t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
MetaKeyStateMap::GetNumStates() const
|
||||||
|
{
|
||||||
|
return fStateTesters.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BitFieldTester*
|
||||||
|
MetaKeyStateMap::GetNthStateTester(int stateNum) const
|
||||||
|
{
|
||||||
|
return ((const BitFieldTester*) fStateTesters.ItemAt(stateNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
MetaKeyStateMap::GetNthStateDesc(int stateNum) const
|
||||||
|
{
|
||||||
|
return ((const char*) fStateDescs.ItemAt(stateNum));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
MetaKeyStateMap::GetName() const
|
||||||
|
{
|
||||||
|
return fKeyName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MetaKeyStateMap_h
|
||||||
|
#define MetaKeyStateMap_h
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
#include <List.h>
|
||||||
|
|
||||||
|
class BitFieldTester;
|
||||||
|
|
||||||
|
// This class defines a set of possible chording states (e.g. "Left only",
|
||||||
|
// "Right only", "Both", "Either") for a meta-key (e.g. Shift), and the
|
||||||
|
// description strings and qualifier bit-chords that go with them.
|
||||||
|
class MetaKeyStateMap {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Note: You MUST call SetInfo() directly after using this ctor!
|
||||||
|
MetaKeyStateMap();
|
||||||
|
|
||||||
|
// Creates a MetaKeyStateMap with the give name
|
||||||
|
// (e.g. "Shift" or "Ctrl")
|
||||||
|
MetaKeyStateMap(const char* keyName);
|
||||||
|
|
||||||
|
|
||||||
|
~MetaKeyStateMap();
|
||||||
|
|
||||||
|
// For when you have to use the default ctor
|
||||||
|
void SetInfo(const char* keyName);
|
||||||
|
|
||||||
|
// (tester) becomes property of this map!
|
||||||
|
void AddState(const char* desc, const BitFieldTester* tester);
|
||||||
|
|
||||||
|
// Returns the name of the meta-key (e.g. "Ctrl")
|
||||||
|
const char* GetName() const;
|
||||||
|
|
||||||
|
// Returns the number of possible states contained in this
|
||||||
|
// MetaKeyStateMap.
|
||||||
|
int GetNumStates() const;
|
||||||
|
|
||||||
|
// Returns a BitFieldTester that tests for the nth state's
|
||||||
|
// presence.
|
||||||
|
const BitFieldTester* GetNthStateTester(int stateNum) const;
|
||||||
|
|
||||||
|
// Returns a textual description of the nth state (e.g. "Left")
|
||||||
|
const char* GetNthStateDesc(int stateNum) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// e.g. "Alt" or "Ctrl"
|
||||||
|
char* fKeyName;
|
||||||
|
|
||||||
|
// list of strings e.g. "Left" or "Both"
|
||||||
|
BList fStateDescs;
|
||||||
|
|
||||||
|
// list of BitFieldTesters for testing bits of modifiers
|
||||||
|
// in state
|
||||||
|
BList fStateTesters;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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* msg)
|
||||||
|
:
|
||||||
|
BButton(frame, name, label, msg, 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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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 <Message.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
#include <View.h>
|
||||||
|
#include <Button.h>
|
||||||
|
|
||||||
|
//Just like a regular BButton, but with a handy resize method added
|
||||||
|
class ResizableButton : public BButton {
|
||||||
|
public:
|
||||||
|
ResizableButton(BRect parentFrame, BRect frame,
|
||||||
|
const char* name, const char* label,
|
||||||
|
BMessage* msg);
|
||||||
|
|
||||||
|
virtual void ChangeToNewSize(float newWidth, float newHeight);
|
||||||
|
private:
|
||||||
|
BRect fPercentages;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
* Fredrik Modéen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ShortcutsApp.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "Alert.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "ShortcutsWindow.h"
|
||||||
|
|
||||||
|
#define APPLICATION_SIGNATURE "application/x-vnd.ShortcutsKeys"
|
||||||
|
|
||||||
|
ShortcutsApp::ShortcutsApp()
|
||||||
|
:
|
||||||
|
BApplication(APPLICATION_SIGNATURE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsApp::ReadyToRun()
|
||||||
|
{
|
||||||
|
ShortcutsWindow* window = new ShortcutsWindow();
|
||||||
|
window->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsApp::~ShortcutsApp()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsApp::AboutRequested()
|
||||||
|
{
|
||||||
|
BAlert* alert = new BAlert("About Shortcuts",
|
||||||
|
"Shortcuts v1.28(SpicyKeys v1.28)\nby Jeremy Friesner"
|
||||||
|
, "Ok");
|
||||||
|
alert->Go();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
* Fredrik Modéen
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ShortcutsApp_h
|
||||||
|
#define ShortcutsApp_h
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
|
||||||
|
class ShortcutsApp : public BApplication {
|
||||||
|
public:
|
||||||
|
ShortcutsApp();
|
||||||
|
~ShortcutsApp();
|
||||||
|
virtual void ReadyToRun();
|
||||||
|
virtual void AboutRequested();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,838 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ShortcutsSpec.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Region.h>
|
||||||
|
#include <Window.h>
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <NodeInfo.h>
|
||||||
|
#include <Beep.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "Colors.h"
|
||||||
|
#include "MetaKeyStateMap.h"
|
||||||
|
#include "BitFieldTesters.h"
|
||||||
|
#include "CommandActuators.h"
|
||||||
|
#include "ParseCommandLine.h"
|
||||||
|
|
||||||
|
#define CLASS "ShortcutsSpec : "
|
||||||
|
|
||||||
|
const float _height = 20.0f;
|
||||||
|
|
||||||
|
static MetaKeyStateMap _metaMaps[ShortcutsSpec::NUM_META_COLUMNS];
|
||||||
|
static bool _metaMapsInitialized = false;
|
||||||
|
|
||||||
|
static bool _fontCached = false;
|
||||||
|
static BFont _viewFont;
|
||||||
|
static float _fontHeight;
|
||||||
|
static BBitmap * _actuatorBitmaps[2];
|
||||||
|
|
||||||
|
// These meta-keys are pretty standard
|
||||||
|
#define SHIFT_NAME "Shift"
|
||||||
|
#define CONTROL_NAME "Control"
|
||||||
|
|
||||||
|
// These meta-keys have different names on an Intel keyboard
|
||||||
|
#if __INTEL__
|
||||||
|
#define OPTION_NAME "Window"
|
||||||
|
#define COMMAND_NAME "Alt"
|
||||||
|
#else
|
||||||
|
#define OPTION_NAME "Option"
|
||||||
|
#define COMMAND_NAME "Command"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ICON_BITMAP_RECT BRect(0.0f, 0.0f, 15.0f, 15.0f)
|
||||||
|
#define ICON_BITMAP_SPACE B_COLOR_8_BIT
|
||||||
|
|
||||||
|
// Returns the (pos)'th char in the string, or '\0' if (pos) if off the end of
|
||||||
|
// the string
|
||||||
|
static char GetLetterAt(const char* str, int pos);
|
||||||
|
|
||||||
|
static char
|
||||||
|
GetLetterAt(const char* str, int pos)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pos; i++)
|
||||||
|
if (str[i] == '\0')
|
||||||
|
return '\0';
|
||||||
|
return str[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Setup the states in a standard manner for a pair of meta-keys.
|
||||||
|
static void
|
||||||
|
SetupStandardMap(MetaKeyStateMap& map, const char* name, uint32 both,
|
||||||
|
uint32 left, uint32 right)
|
||||||
|
{
|
||||||
|
map.SetInfo(name);
|
||||||
|
|
||||||
|
// In this state, neither key may be pressed.
|
||||||
|
map.AddState("(None)", new HasBitsFieldTester(0, both));
|
||||||
|
|
||||||
|
// Here, either may be pressed. (Remember both is NOT a 2-bit chord, it's
|
||||||
|
// another bit entirely)
|
||||||
|
map.AddState("Either", new HasBitsFieldTester(both));
|
||||||
|
|
||||||
|
// Here, only the left may be pressed
|
||||||
|
map.AddState("Left", new HasBitsFieldTester(left, right));
|
||||||
|
|
||||||
|
// Here, only the right may be pressed
|
||||||
|
map.AddState("Right", new HasBitsFieldTester(right, left));
|
||||||
|
|
||||||
|
// Here, both must be pressed.
|
||||||
|
map.AddState("Both", new HasBitsFieldTester(left | right));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MetaKeyStateMap & GetNthKeyMap(int which)
|
||||||
|
{
|
||||||
|
return _metaMaps[which];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BBitmap* MakeActuatorBitmap(bool lit);
|
||||||
|
static BBitmap*
|
||||||
|
MakeActuatorBitmap(bool lit)
|
||||||
|
{
|
||||||
|
BBitmap* map = new BBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE, true);
|
||||||
|
const rgb_color yellow = {255, 255, 0};
|
||||||
|
const rgb_color red = {200, 200, 200};
|
||||||
|
const rgb_color black = {0, 0, 0};
|
||||||
|
const BPoint points[10] = {
|
||||||
|
BPoint(8, 0), BPoint(9.8, 5.8), BPoint(16, 5.8),
|
||||||
|
BPoint(11, 9.0), BPoint(13, 16), BPoint(8, 11),
|
||||||
|
BPoint(3, 16), BPoint(5, 9.0), BPoint(0, 5.8),
|
||||||
|
BPoint(6.2, 5.8) };
|
||||||
|
|
||||||
|
BView* view = new BView(BRect(0, 0, 16, 16), NULL, B_FOLLOW_ALL_SIDES, 0L);
|
||||||
|
map->AddChild(view);
|
||||||
|
map->Lock();
|
||||||
|
view->SetHighColor(B_TRANSPARENT_32_BIT);
|
||||||
|
view->FillRect(ICON_BITMAP_RECT);
|
||||||
|
view->SetHighColor(lit ? yellow : red);
|
||||||
|
view->FillPolygon(points, 10);
|
||||||
|
view->SetHighColor(black);
|
||||||
|
view->StrokePolygon(points, 10);
|
||||||
|
map->Unlock();
|
||||||
|
map->RemoveChild(view);
|
||||||
|
delete view;
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InitializeMetaMaps()
|
||||||
|
{
|
||||||
|
_metaMapsInitialized = true;
|
||||||
|
SetupStandardMap(_metaMaps[ShortcutsSpec::SHIFT_COLUMN_INDEX], SHIFT_NAME,
|
||||||
|
B_SHIFT_KEY, B_LEFT_SHIFT_KEY, B_RIGHT_SHIFT_KEY);
|
||||||
|
|
||||||
|
SetupStandardMap(_metaMaps[ShortcutsSpec::CONTROL_COLUMN_INDEX],
|
||||||
|
CONTROL_NAME, B_CONTROL_KEY, B_LEFT_CONTROL_KEY, B_RIGHT_CONTROL_KEY);
|
||||||
|
|
||||||
|
SetupStandardMap(_metaMaps[ShortcutsSpec::COMMAND_COLUMN_INDEX],
|
||||||
|
COMMAND_NAME, B_COMMAND_KEY, B_LEFT_COMMAND_KEY, B_RIGHT_COMMAND_KEY);
|
||||||
|
|
||||||
|
SetupStandardMap(_metaMaps[ShortcutsSpec::OPTION_COLUMN_INDEX], OPTION_NAME
|
||||||
|
, B_OPTION_KEY, B_LEFT_OPTION_KEY, B_RIGHT_OPTION_KEY);
|
||||||
|
|
||||||
|
_actuatorBitmaps[0] = MakeActuatorBitmap(false);
|
||||||
|
_actuatorBitmaps[1] = MakeActuatorBitmap(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsSpec::ShortcutsSpec(const char* cmd)
|
||||||
|
:
|
||||||
|
CLVListItem(0, false, false, _height),
|
||||||
|
fCommand(NULL),
|
||||||
|
fTextOffset(0),
|
||||||
|
fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
|
||||||
|
fLastBitmapName(NULL),
|
||||||
|
fBitmapValid(false),
|
||||||
|
fKey(0),
|
||||||
|
fCursorPtsValid(false)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_META_COLUMNS; i++)
|
||||||
|
fMetaCellStateIndex[i] = 0;
|
||||||
|
SetCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsSpec::ShortcutsSpec(const ShortcutsSpec& from)
|
||||||
|
:
|
||||||
|
CLVListItem(0, false, false, _height),
|
||||||
|
fCommand(NULL),
|
||||||
|
fTextOffset(from.fTextOffset),
|
||||||
|
fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
|
||||||
|
fLastBitmapName(NULL),
|
||||||
|
fBitmapValid(false),
|
||||||
|
fKey(from.fKey),
|
||||||
|
fCursorPtsValid(false)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_META_COLUMNS; i++)
|
||||||
|
fMetaCellStateIndex[i] = from.fMetaCellStateIndex[i];
|
||||||
|
|
||||||
|
SetCommand(from.fCommand);
|
||||||
|
SetSelectedColumn(from.GetSelectedColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsSpec::ShortcutsSpec(BMessage* from)
|
||||||
|
:
|
||||||
|
CLVListItem(0, false, false, _height),
|
||||||
|
fCommand(NULL),
|
||||||
|
fTextOffset(0),
|
||||||
|
fBitmap(ICON_BITMAP_RECT, ICON_BITMAP_SPACE),
|
||||||
|
fLastBitmapName(NULL),
|
||||||
|
fBitmapValid(false),
|
||||||
|
fCursorPtsValid(false)
|
||||||
|
{
|
||||||
|
const char* temp;
|
||||||
|
if (from->FindString("command", &temp) != B_NO_ERROR) {
|
||||||
|
printf(CLASS " Error, no command string in archive BMessage!\n");
|
||||||
|
temp = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCommand(temp);
|
||||||
|
|
||||||
|
if (from->FindInt32("key", (int32*) &fKey) != B_NO_ERROR)
|
||||||
|
printf(CLASS " Error, no key int32 in archive BMessage!\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_META_COLUMNS; i++)
|
||||||
|
if (from->FindInt32("mcidx", i, (int32*)&fMetaCellStateIndex[i])
|
||||||
|
!= B_NO_ERROR)
|
||||||
|
printf(CLASS " Error, no modifiers int32 in archive BMessage!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::SetCommand(const char* command)
|
||||||
|
{
|
||||||
|
delete[] fCommand; // out with the old (if any)...
|
||||||
|
fCommandLen = strlen(command) + 1;
|
||||||
|
fCommandNul = fCommandLen - 1;
|
||||||
|
fCommand = new char[fCommandLen];
|
||||||
|
strcpy(fCommand, command);
|
||||||
|
_UpdateIconBitmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
ShortcutsSpec::GetColumnName(int i)
|
||||||
|
{
|
||||||
|
return _metaMaps[i].GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ShortcutsSpec::Archive(BMessage* into, bool deep) const
|
||||||
|
{
|
||||||
|
status_t ret = BArchivable::Archive(into, deep);
|
||||||
|
if (ret != B_NO_ERROR)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
into->AddString("class", "ShortcutsSpec");
|
||||||
|
|
||||||
|
// These fields are for our prefs panel's benefit only
|
||||||
|
into->AddString("command", fCommand);
|
||||||
|
into->AddInt32("key", fKey);
|
||||||
|
|
||||||
|
// Assemble a BitFieldTester for the input_server add-on to use...
|
||||||
|
MinMatchFieldTester test(NUM_META_COLUMNS, false);
|
||||||
|
for (int i = 0; i < NUM_META_COLUMNS; i++) {
|
||||||
|
// for easy parsing by prefs applet on load-in
|
||||||
|
into->AddInt32("mcidx", fMetaCellStateIndex[i]);
|
||||||
|
test.AddSlave(_metaMaps[i].GetNthStateTester(fMetaCellStateIndex[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
BMessage testerMsg;
|
||||||
|
ret = test.Archive(&testerMsg);
|
||||||
|
if (ret != B_NO_ERROR)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
into->AddMessage("modtester", &testerMsg);
|
||||||
|
|
||||||
|
// And also create a CommandActuator for the input_server add-on to execute
|
||||||
|
CommandActuator* act = CreateCommandActuator(fCommand);
|
||||||
|
BMessage actMsg;
|
||||||
|
ret = act->Archive(&actMsg);
|
||||||
|
if (ret != B_NO_ERROR)
|
||||||
|
return ret;
|
||||||
|
delete act;
|
||||||
|
|
||||||
|
into->AddMessage("act", &actMsg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool IsValidActuatorName(const char* c);
|
||||||
|
static bool
|
||||||
|
IsValidActuatorName(const char* c)
|
||||||
|
{
|
||||||
|
return ((strcmp(c, "InsertString") == 0) ||
|
||||||
|
(strcmp(c, "MoveMouse") == 0) ||
|
||||||
|
(strcmp(c, "MoveMouseTo") == 0) ||
|
||||||
|
(strcmp(c, "MouseButton") == 0) ||
|
||||||
|
(strcmp(c, "LaunchHandler") == 0) || // new for v1.21 --jaf
|
||||||
|
(strcmp(c, "Multi") == 0) || // new for v1.24 --jaf
|
||||||
|
(strcmp(c, "MouseDown") == 0) || // new for v1.24 --jaf
|
||||||
|
(strcmp(c, "MouseUp") == 0) || // new for v1.24 --jaf
|
||||||
|
(strcmp(c, "SendMessage") == 0) || // new for v1.25 --jaf
|
||||||
|
(strcmp(c, "Beep") == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BArchivable*
|
||||||
|
ShortcutsSpec::Instantiate(BMessage* from)
|
||||||
|
{
|
||||||
|
bool validateOK = false;
|
||||||
|
if (validate_instantiation(from, "ShortcutsSpec"))
|
||||||
|
validateOK = true;
|
||||||
|
else //test the old one.
|
||||||
|
if (validate_instantiation(from, "SpicyKeysSpec"))
|
||||||
|
validateOK = true;
|
||||||
|
|
||||||
|
if (!validateOK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return new ShortcutsSpec(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsSpec::~ShortcutsSpec()
|
||||||
|
{
|
||||||
|
delete[] fCommand;
|
||||||
|
delete[] fLastBitmapName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::_CacheViewFont(BView* owner)
|
||||||
|
{
|
||||||
|
if (_fontCached == false) {
|
||||||
|
_fontCached = true;
|
||||||
|
owner->GetFont(&_viewFont);
|
||||||
|
font_height fh;
|
||||||
|
_viewFont.GetHeight(&fh);
|
||||||
|
_fontHeight = fh.ascent - fh.descent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::DrawItemColumn(BView* owner, BRect item_column_rect,
|
||||||
|
int32 column_index, bool columnSelected, bool complete)
|
||||||
|
{
|
||||||
|
const float STRING_COLUMN_LEFT_MARGIN = 25.0f; // 16 for the icon,+9 empty
|
||||||
|
|
||||||
|
rgb_color color;
|
||||||
|
bool selected = IsSelected();
|
||||||
|
if (selected)
|
||||||
|
color = columnSelected ? BeBackgroundGrey : BeListSelectGrey;
|
||||||
|
else
|
||||||
|
color = BeInactiveControlGrey;
|
||||||
|
owner->SetLowColor(color);
|
||||||
|
owner->SetDrawingMode(B_OP_COPY);
|
||||||
|
owner->SetHighColor(color);
|
||||||
|
owner->FillRect(item_column_rect);
|
||||||
|
|
||||||
|
const char* text = GetCellText(column_index);
|
||||||
|
|
||||||
|
if (text == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float textWidth = _viewFont.StringWidth(text);
|
||||||
|
BPoint point;
|
||||||
|
rgb_color lowColor = color;
|
||||||
|
|
||||||
|
if (column_index == STRING_COLUMN_INDEX) {
|
||||||
|
// left justified
|
||||||
|
point.Set(item_column_rect.left + STRING_COLUMN_LEFT_MARGIN,
|
||||||
|
item_column_rect.top + fTextOffset);
|
||||||
|
|
||||||
|
item_column_rect.left = point.x;//keep text from drawing into icon area
|
||||||
|
|
||||||
|
// scroll if too wide
|
||||||
|
float rectWidth = item_column_rect.Width() - STRING_COLUMN_LEFT_MARGIN;
|
||||||
|
float extra = textWidth - rectWidth;
|
||||||
|
if (extra > 0.0f)
|
||||||
|
point.x -= extra;
|
||||||
|
} else {
|
||||||
|
if ((column_index < NUM_META_COLUMNS) && (text[0] == '('))
|
||||||
|
return; // don't draw for this ...
|
||||||
|
|
||||||
|
if ((column_index <= NUM_META_COLUMNS) && (text[0] == '\0'))
|
||||||
|
return; // don't draw for this ...
|
||||||
|
|
||||||
|
// centered
|
||||||
|
point.Set((item_column_rect.left + item_column_rect.right) / 2.0,
|
||||||
|
item_column_rect.top + fTextOffset);
|
||||||
|
_CacheViewFont(owner);
|
||||||
|
point.x -= textWidth / 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRegion Region;
|
||||||
|
Region.Include(item_column_rect);
|
||||||
|
owner->ConstrainClippingRegion(&Region);
|
||||||
|
if (column_index != STRING_COLUMN_INDEX) {
|
||||||
|
const float KEY_MARGIN = 3.0f;
|
||||||
|
const float CORNER_RADIUS = 3.0f;
|
||||||
|
_CacheViewFont(owner);
|
||||||
|
|
||||||
|
// How about I draw a nice "key" background for this one?
|
||||||
|
BRect textRect(point.x - KEY_MARGIN, (point.y-_fontHeight) - KEY_MARGIN
|
||||||
|
, point.x + textWidth + KEY_MARGIN - 2.0f, point.y + KEY_MARGIN);
|
||||||
|
|
||||||
|
if (column_index == KEY_COLUMN_INDEX)
|
||||||
|
lowColor = ReallyLightPurple;
|
||||||
|
else
|
||||||
|
lowColor = LightYellow;
|
||||||
|
|
||||||
|
owner->SetHighColor(lowColor);
|
||||||
|
owner->FillRoundRect(textRect, CORNER_RADIUS, CORNER_RADIUS);
|
||||||
|
owner->SetHighColor(Black);
|
||||||
|
owner->StrokeRoundRect(textRect, CORNER_RADIUS, CORNER_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
owner->SetHighColor(Black);
|
||||||
|
owner->SetLowColor(lowColor);
|
||||||
|
owner->DrawString(text, point);
|
||||||
|
// with a cursor at the end if highlighted
|
||||||
|
if (column_index == STRING_COLUMN_INDEX) {
|
||||||
|
// Draw cursor
|
||||||
|
if ((columnSelected) && (selected)) {
|
||||||
|
point.x += textWidth;
|
||||||
|
point.y += (fTextOffset / 4.0f);
|
||||||
|
|
||||||
|
BPoint pt2 = point;
|
||||||
|
pt2.y -= fTextOffset;
|
||||||
|
owner->StrokeLine(point, pt2);
|
||||||
|
|
||||||
|
fCursorPt1 = point;
|
||||||
|
fCursorPt2 = pt2;
|
||||||
|
fCursorPtsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRegion bitmapRegion;
|
||||||
|
item_column_rect.left -= (STRING_COLUMN_LEFT_MARGIN - 4.0f);
|
||||||
|
item_column_rect.right = item_column_rect.left + 16.0f;
|
||||||
|
item_column_rect.top += 3.0f;
|
||||||
|
item_column_rect.bottom = item_column_rect.top + 16.0f;
|
||||||
|
|
||||||
|
bitmapRegion.Include(item_column_rect);
|
||||||
|
owner->ConstrainClippingRegion(&bitmapRegion);
|
||||||
|
owner->SetDrawingMode(B_OP_OVER);
|
||||||
|
|
||||||
|
if ((fCommand != NULL) && (fCommand[0] == '*'))
|
||||||
|
owner->DrawBitmap(_actuatorBitmaps[fBitmapValid ? 1 : 0],
|
||||||
|
ICON_BITMAP_RECT, item_column_rect);
|
||||||
|
else
|
||||||
|
// Draw icon, if any
|
||||||
|
if (fBitmapValid)
|
||||||
|
owner->DrawBitmap(&fBitmap, ICON_BITMAP_RECT,
|
||||||
|
item_column_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
owner->SetDrawingMode(B_OP_COPY);
|
||||||
|
owner->ConstrainClippingRegion(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::Update(BView* owner, const BFont* font)
|
||||||
|
{
|
||||||
|
CLVListItem::Update(owner, font);
|
||||||
|
font_height FontAttributes;
|
||||||
|
be_plain_font->GetHeight(&FontAttributes);
|
||||||
|
float fontHeight = ceil(FontAttributes.ascent) +
|
||||||
|
ceil(FontAttributes.descent);
|
||||||
|
fTextOffset = ceil(FontAttributes.ascent) + (Height() - fontHeight) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
ShortcutsSpec::GetCellText(int whichColumn) const
|
||||||
|
{
|
||||||
|
const char* temp = ""; // default
|
||||||
|
switch(whichColumn)
|
||||||
|
{
|
||||||
|
case KEY_COLUMN_INDEX:
|
||||||
|
{
|
||||||
|
if ((fKey > 0) && (fKey <= 0xFF)) {
|
||||||
|
temp = GetKeyName(fKey);
|
||||||
|
if (temp == NULL)
|
||||||
|
temp = "";
|
||||||
|
} else if (fKey > 0xFF) {
|
||||||
|
sprintf(fScratch, "#%x", fKey);
|
||||||
|
return fScratch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_COLUMN_INDEX:
|
||||||
|
temp = fCommand;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS))
|
||||||
|
temp = _metaMaps[whichColumn].GetNthStateDesc(
|
||||||
|
fMetaCellStateIndex[whichColumn]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsSpec::ProcessColumnMouseClick(int whichColumn)
|
||||||
|
{
|
||||||
|
if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS)) {
|
||||||
|
// same as hitting space for these columns: cycle entry
|
||||||
|
const char temp = B_SPACE;
|
||||||
|
|
||||||
|
// 3rd arg isn't correct but it isn't read for this case anyway
|
||||||
|
return ProcessColumnKeyStroke(whichColumn, &temp, 0);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsSpec::ProcessColumnTextString(int whichColumn, const char* string)
|
||||||
|
{
|
||||||
|
switch(whichColumn) {
|
||||||
|
case STRING_COLUMN_INDEX:
|
||||||
|
SetCommand(string);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_COLUMN_INDEX:
|
||||||
|
{
|
||||||
|
fKey = FindKeyCode(string);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ProcessColumnKeyStroke(whichColumn, string, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsSpec::_AttemptTabCompletion()
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
int32 argc;
|
||||||
|
char** argv = ParseArgvFromString(fCommand, argc);
|
||||||
|
if (argc > 0) {
|
||||||
|
// Try to complete the path partially expressed in the last argument!
|
||||||
|
char* arg = argv[argc - 1];
|
||||||
|
char* fileFragment = strrchr(arg, '/');
|
||||||
|
if (fileFragment) {
|
||||||
|
const char* directoryName = (fileFragment == arg) ? "/" : arg;
|
||||||
|
*fileFragment = '\0';
|
||||||
|
fileFragment++;
|
||||||
|
int fragLen = strlen(fileFragment);
|
||||||
|
|
||||||
|
BDirectory dir(directoryName);
|
||||||
|
if (dir.InitCheck() == B_NO_ERROR) {
|
||||||
|
BEntry nextEnt;
|
||||||
|
BPath nextPath;
|
||||||
|
BList matchList;
|
||||||
|
int maxEntryLen = 0;
|
||||||
|
|
||||||
|
// Read in all the files in the directory whose names start
|
||||||
|
// with our fragment.
|
||||||
|
while (dir.GetNextEntry(&nextEnt) == B_NO_ERROR) {
|
||||||
|
if (nextEnt.GetPath(&nextPath) == B_NO_ERROR) {
|
||||||
|
char* filePath = strrchr(nextPath.Path(), '/') + 1;
|
||||||
|
if (strncmp(filePath, fileFragment, fragLen) == 0) {
|
||||||
|
int len = strlen(filePath);
|
||||||
|
if (len > maxEntryLen)
|
||||||
|
maxEntryLen = len;
|
||||||
|
char* newStr = new char[len + 1];
|
||||||
|
strcpy(newStr, filePath);
|
||||||
|
matchList.AddItem(newStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now slowly extend our keyword to its full length, counting
|
||||||
|
// numbers of matches at each step. If the match list length
|
||||||
|
// is 1, we can use that whole entry. If it's greater than one
|
||||||
|
// , we can use just the match length.
|
||||||
|
int matchLen = matchList.CountItems();
|
||||||
|
if (matchLen > 0) {
|
||||||
|
int i;
|
||||||
|
BString result(fileFragment);
|
||||||
|
for (i = fragLen; i < maxEntryLen; i++) {
|
||||||
|
// See if all the matching entries have the same letter
|
||||||
|
// in the next position... if so, we can go farther.
|
||||||
|
char commonLetter = '\0';
|
||||||
|
for (int j = 0; j < matchLen; j++) {
|
||||||
|
char nextLetter = GetLetterAt(
|
||||||
|
(char*)matchList.ItemAt(j), i);
|
||||||
|
if (commonLetter == '\0')
|
||||||
|
commonLetter = nextLetter;
|
||||||
|
|
||||||
|
if ((commonLetter != '\0')
|
||||||
|
&& (commonLetter != nextLetter)) {
|
||||||
|
commonLetter = '\0';// failed;
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (commonLetter == '\0')
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
result.Append(commonLetter, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free all the strings we allocated
|
||||||
|
for (int k = 0; k < matchLen; k++)
|
||||||
|
delete [] ((char*)matchList.ItemAt(k));
|
||||||
|
|
||||||
|
DoStandardEscapes(result);
|
||||||
|
|
||||||
|
BString wholeLine;
|
||||||
|
for (int l = 0; l < argc - 1; l++) {
|
||||||
|
wholeLine += argv[l];
|
||||||
|
wholeLine += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
BString file(directoryName);
|
||||||
|
DoStandardEscapes(file);
|
||||||
|
|
||||||
|
if (directoryName[strlen(directoryName) - 1] != '/')
|
||||||
|
file += "/";
|
||||||
|
|
||||||
|
file += result;
|
||||||
|
|
||||||
|
// Remove any trailing slash...
|
||||||
|
const char* fileStr = file.String();
|
||||||
|
if (fileStr[strlen(fileStr)-1] == '/')
|
||||||
|
file.RemoveLast("/");
|
||||||
|
|
||||||
|
// And re-append it iff the file is a dir.
|
||||||
|
BDirectory testFileAsDir(file.String());
|
||||||
|
if ((strcmp(file.String(), "/") != 0)
|
||||||
|
&& (testFileAsDir.InitCheck() == B_NO_ERROR))
|
||||||
|
file.Append("/");
|
||||||
|
|
||||||
|
wholeLine += file;
|
||||||
|
|
||||||
|
SetCommand(wholeLine.String());
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*(fileFragment - 1) = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FreeArgv(argv);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsSpec::ProcessColumnKeyStroke(int whichColumn, const char* bytes,
|
||||||
|
int32 key)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
switch(whichColumn) {
|
||||||
|
case KEY_COLUMN_INDEX:
|
||||||
|
if (key != -1) {
|
||||||
|
if (fKey != key) {
|
||||||
|
fKey = key;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_COLUMN_INDEX:
|
||||||
|
{
|
||||||
|
switch(bytes[0]) {
|
||||||
|
case B_BACKSPACE:
|
||||||
|
case B_DELETE:
|
||||||
|
if (fCommandNul > 0) {
|
||||||
|
//trim a char off the string
|
||||||
|
fCommand[fCommandNul - 1] = '\0';
|
||||||
|
fCommandNul--; // note new nul position
|
||||||
|
ret = true;
|
||||||
|
_UpdateIconBitmap();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_TAB:
|
||||||
|
if (_AttemptTabCompletion()) {
|
||||||
|
_UpdateIconBitmap();
|
||||||
|
ret = true;
|
||||||
|
} else
|
||||||
|
beep();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int newCharLen = strlen(bytes);
|
||||||
|
if ((newCharLen > 0) && (bytes[0] >= ' ')) {
|
||||||
|
bool reAllocString = false;
|
||||||
|
// Make sure we have enough room in our command string
|
||||||
|
// to add these chars...
|
||||||
|
while (fCommandLen - fCommandNul <= newCharLen) {
|
||||||
|
reAllocString = true;
|
||||||
|
// enough for a while...
|
||||||
|
fCommandLen = (fCommandLen + 10) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reAllocString) {
|
||||||
|
char* temp = new char[fCommandLen];
|
||||||
|
strcpy(temp, fCommand);
|
||||||
|
delete [] fCommand;
|
||||||
|
fCommand = temp;
|
||||||
|
// fCommandNul is still valid since it's an offset
|
||||||
|
// and the string length is the same for now
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we should be guaranteed enough room.
|
||||||
|
strncat(fCommand, bytes, fCommandLen);
|
||||||
|
fCommandNul += newCharLen;
|
||||||
|
ret = true;
|
||||||
|
_UpdateIconBitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ((whichColumn >= 0) && (whichColumn < NUM_META_COLUMNS)) {
|
||||||
|
MetaKeyStateMap * map = &_metaMaps[whichColumn];
|
||||||
|
int curState = fMetaCellStateIndex[whichColumn];
|
||||||
|
int origState = curState;
|
||||||
|
int numStates = map->GetNumStates();
|
||||||
|
|
||||||
|
switch(bytes[0])
|
||||||
|
{
|
||||||
|
case B_RETURN:
|
||||||
|
// cycle to the previous state
|
||||||
|
curState = (curState + numStates - 1) % numStates;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_SPACE:
|
||||||
|
// cycle to the next state
|
||||||
|
curState = (curState + 1) % numStates;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Go to the state starting with the given letter, if
|
||||||
|
// any
|
||||||
|
char letter = bytes[0];
|
||||||
|
if (islower(letter))
|
||||||
|
letter = toupper(letter); // convert to upper case
|
||||||
|
|
||||||
|
if ((letter == B_BACKSPACE) || (letter == B_DELETE))
|
||||||
|
letter = '(';//so space bar will blank out an entry
|
||||||
|
|
||||||
|
for (int i = 0; i < numStates; i++) {
|
||||||
|
const char* desc = map->GetNthStateDesc(i);
|
||||||
|
|
||||||
|
if (desc) {
|
||||||
|
if (desc[0] == letter) {
|
||||||
|
curState = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("Error, NULL state description?\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fMetaCellStateIndex[whichColumn] = curState;
|
||||||
|
|
||||||
|
if (curState != origState)
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ShortcutsSpec::MyCompare(const CLVListItem* a_Item1, const CLVListItem* a_Item2
|
||||||
|
, int32 KeyColumn)
|
||||||
|
{
|
||||||
|
ShortcutsSpec* left = (ShortcutsSpec*) a_Item1;
|
||||||
|
ShortcutsSpec* right = (ShortcutsSpec*) a_Item2;
|
||||||
|
|
||||||
|
int ret = strcmp(left->GetCellText(KeyColumn),
|
||||||
|
right->GetCellText(KeyColumn));
|
||||||
|
return (ret > 0) ? 1 : ((ret == 0) ? 0 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::Pulse(BView* owner)
|
||||||
|
{
|
||||||
|
if ((fCursorPtsValid)&&(owner->Window()->IsActive())) {
|
||||||
|
rgb_color prevColor = owner->HighColor();
|
||||||
|
rgb_color backgroundColor = (GetSelectedColumn() ==
|
||||||
|
STRING_COLUMN_INDEX) ? BeBackgroundGrey : BeListSelectGrey;
|
||||||
|
rgb_color barColor = ((GetSelectedColumn() == STRING_COLUMN_INDEX)
|
||||||
|
&& ((system_time() % 1000000) > 500000)) ? Black : backgroundColor;
|
||||||
|
owner->SetHighColor(barColor);
|
||||||
|
owner->StrokeLine(fCursorPt1, fCursorPt2);
|
||||||
|
owner->SetHighColor(prevColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsSpec::_UpdateIconBitmap()
|
||||||
|
{
|
||||||
|
BString firstWord = ParseArgvZeroFromString(fCommand);
|
||||||
|
|
||||||
|
// Only need to change if the first word has changed...
|
||||||
|
if ((fLastBitmapName == NULL) || (firstWord.Length() == 0) ||
|
||||||
|
(firstWord.Compare(fLastBitmapName))) {
|
||||||
|
if (firstWord.ByteAt(0) == '*')
|
||||||
|
fBitmapValid = IsValidActuatorName(&firstWord.String()[1]);
|
||||||
|
else {
|
||||||
|
fBitmapValid = false; // default till we prove otherwise!
|
||||||
|
|
||||||
|
if (firstWord.Length() > 0) {
|
||||||
|
delete [] fLastBitmapName;
|
||||||
|
fLastBitmapName = new char[firstWord.Length() + 1];
|
||||||
|
strcpy(fLastBitmapName, firstWord.String());
|
||||||
|
|
||||||
|
BEntry progEntry(fLastBitmapName, true);
|
||||||
|
if ((progEntry.InitCheck() == B_NO_ERROR)
|
||||||
|
&& (progEntry.Exists())) {
|
||||||
|
BNode progNode(&progEntry);
|
||||||
|
if (progNode.InitCheck() == B_NO_ERROR) {
|
||||||
|
BNodeInfo progNodeInfo(&progNode);
|
||||||
|
if ((progNodeInfo.InitCheck() == B_NO_ERROR)
|
||||||
|
&& (progNodeInfo.GetTrackerIcon(&fBitmap, B_MINI_ICON)
|
||||||
|
== B_NO_ERROR))
|
||||||
|
fBitmapValid = fBitmap.IsValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ShortcutsSpec_h
|
||||||
|
#define ShortcutsSpec_h
|
||||||
|
|
||||||
|
#include <Bitmap.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "CLVListItem.h"
|
||||||
|
#include "KeyInfos.h"
|
||||||
|
|
||||||
|
class CommandActuator;
|
||||||
|
class MetaKeyStateMap;
|
||||||
|
|
||||||
|
MetaKeyStateMap & GetNthKeyMap(int which);
|
||||||
|
void InitializeMetaMaps();
|
||||||
|
|
||||||
|
/* Objects of this class represent one hotkey "entry" in the preferences
|
||||||
|
* ListView. Each ShortcutsSpec contains the info necessary to generate both
|
||||||
|
* the proper GUI display, and the proper BitFieldTester and CommandActuator
|
||||||
|
* object for the ShortcutsCatcher add-on to use.
|
||||||
|
*/
|
||||||
|
class ShortcutsSpec : public CLVListItem {
|
||||||
|
public:
|
||||||
|
ShortcutsSpec(const char* command);
|
||||||
|
ShortcutsSpec(const ShortcutsSpec& copyMe);
|
||||||
|
ShortcutsSpec(BMessage* from);
|
||||||
|
~ShortcutsSpec();
|
||||||
|
|
||||||
|
virtual status_t Archive(BMessage* into, bool deep = true) const;
|
||||||
|
virtual void Pulse(BView* owner);
|
||||||
|
static BArchivable* Instantiate(BMessage* from);
|
||||||
|
void Update(BView* owner, const BFont* font);
|
||||||
|
const char* GetCellText(int whichColumn) const;
|
||||||
|
void SetCommand(const char* commandStr);
|
||||||
|
|
||||||
|
virtual void DrawItemColumn(BView* owner, BRect item_column_rect, int32 column_index, bool columnSelected, bool complete);
|
||||||
|
|
||||||
|
static int MyCompare(const CLVListItem* a_Item1,
|
||||||
|
const CLVListItem* a_Item2, int32 KeyColumn);
|
||||||
|
|
||||||
|
// Returns the name of the Nth Column.
|
||||||
|
static const char* GetColumnName(int index);
|
||||||
|
|
||||||
|
// Update this spec's state in response to a keystroke to the given
|
||||||
|
// column. Returns true iff a change occurred.
|
||||||
|
bool ProcessColumnKeyStroke(int whichColumn,
|
||||||
|
const char* bytes, int32 key);
|
||||||
|
|
||||||
|
// Same as ProcessColumnKeyStroke, but for a mouse click instead.
|
||||||
|
bool ProcessColumnMouseClick(int whichColumn);
|
||||||
|
|
||||||
|
// Same as ProcessColumnKeyStroke, but for a text string instead.
|
||||||
|
bool ProcessColumnTextString(int whichColumn,
|
||||||
|
const char* string);
|
||||||
|
|
||||||
|
int32 GetSelectedColumn() const {return fSelectedColumn;}
|
||||||
|
void SetSelectedColumn(int32 i) {fSelectedColumn = i;}
|
||||||
|
|
||||||
|
// default layout of columns is set in here.
|
||||||
|
enum {
|
||||||
|
SHIFT_COLUMN_INDEX = 0,
|
||||||
|
CONTROL_COLUMN_INDEX = 1,
|
||||||
|
COMMAND_COLUMN_INDEX = 2,
|
||||||
|
OPTION_COLUMN_INDEX = 3,
|
||||||
|
NUM_META_COLUMNS = 4, // shift, control, command, option, for now
|
||||||
|
KEY_COLUMN_INDEX = NUM_META_COLUMNS,
|
||||||
|
STRING_COLUMN_INDEX = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _CacheViewFont(BView* owner);
|
||||||
|
bool _AttemptTabCompletion();
|
||||||
|
|
||||||
|
// call this to ensure the icon is up-to-date
|
||||||
|
void _UpdateIconBitmap();
|
||||||
|
|
||||||
|
char* fCommand;
|
||||||
|
uint32 fCommandLen; // number of bytes in fCommand buffer
|
||||||
|
uint32 fCommandNul; // index of the NUL byte in fCommand
|
||||||
|
float fTextOffset;
|
||||||
|
|
||||||
|
// icon for associated program. Invalid if none available.
|
||||||
|
BBitmap fBitmap;
|
||||||
|
|
||||||
|
char* fLastBitmapName;
|
||||||
|
bool fBitmapValid;
|
||||||
|
uint32 fKey;
|
||||||
|
int32 fMetaCellStateIndex[NUM_META_COLUMNS];
|
||||||
|
BPoint fCursorPt1;
|
||||||
|
BPoint fCursorPt2;
|
||||||
|
bool fCursorPtsValid;
|
||||||
|
mutable char fScratch[50];
|
||||||
|
int32 fSelectedColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,722 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
* Fredrik Modéen
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ShortcutsWindow.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <Alert.h>
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Clipboard.h>
|
||||||
|
#include <MessageFilter.h>
|
||||||
|
#include <Menu.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <MenuBar.h>
|
||||||
|
#include <ScrollBar.h>
|
||||||
|
#include <ScrollView.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <Input.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "KeyInfos.h"
|
||||||
|
#include "ShortcutsSpec.h"
|
||||||
|
#include "ParseCommandLine.h"
|
||||||
|
#include "MetaKeyStateMap.h"
|
||||||
|
#include "ShortcutsFilterConstants.h"
|
||||||
|
|
||||||
|
// Window sizing constraints
|
||||||
|
#define MIN_WIDTH 600
|
||||||
|
#define MIN_HEIGHT 130
|
||||||
|
#define MAX_WIDTH 65535
|
||||||
|
#define MAX_HEIGHT 65535
|
||||||
|
|
||||||
|
// Default window position
|
||||||
|
#define WINDOW_START_X 30
|
||||||
|
#define WINDOW_START_Y 100
|
||||||
|
|
||||||
|
#define ERROR "Shortcuts Error"
|
||||||
|
#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
|
||||||
|
// meta-key.
|
||||||
|
static BPopUpMenu* CreateMetaPopUp(int col);
|
||||||
|
static BPopUpMenu* CreateMetaPopUp(int col)
|
||||||
|
{
|
||||||
|
MetaKeyStateMap& map = GetNthKeyMap(col);
|
||||||
|
BPopUpMenu * popup = new BPopUpMenu(NULL, false);
|
||||||
|
int numStates = map.GetNumStates();
|
||||||
|
|
||||||
|
for (int i = 0; i < numStates; i++)
|
||||||
|
popup->AddItem(new BMenuItem(map.GetNthStateDesc(i), NULL));
|
||||||
|
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a pop-up that allows the user to choose a key-cap visually
|
||||||
|
static BPopUpMenu* CreateKeysPopUp();
|
||||||
|
static BPopUpMenu* CreateKeysPopUp()
|
||||||
|
{
|
||||||
|
BPopUpMenu* popup = new BPopUpMenu(NULL, false);
|
||||||
|
int numKeys = GetNumKeyIndices();
|
||||||
|
for (int i = 0; i < numKeys; i++) {
|
||||||
|
const char* next = GetKeyName(i);
|
||||||
|
|
||||||
|
if (next)
|
||||||
|
popup->AddItem(new BMenuItem(next, NULL));
|
||||||
|
}
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsWindow::ShortcutsWindow()
|
||||||
|
:
|
||||||
|
BWindow(BRect(WINDOW_START_X, WINDOW_START_Y, WINDOW_START_X + MIN_WIDTH,
|
||||||
|
WINDOW_START_Y + MIN_HEIGHT * 2), "Shortcuts", B_DOCUMENT_WINDOW, 0L),
|
||||||
|
fSavePanel(NULL),
|
||||||
|
fOpenPanel(NULL),
|
||||||
|
fSelectPanel(NULL),
|
||||||
|
fKeySetModified(false),
|
||||||
|
fLastOpenWasAppend(false)
|
||||||
|
{
|
||||||
|
InitializeMetaMaps();
|
||||||
|
SetSizeLimits(MIN_WIDTH, MAX_WIDTH, MIN_HEIGHT, MAX_HEIGHT);
|
||||||
|
BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "Menu Bar");
|
||||||
|
|
||||||
|
BMenu* fileMenu = new BMenu("File");
|
||||||
|
fileMenu->AddItem(new BMenuItem("Open KeySet...",
|
||||||
|
new BMessage(OPEN_KEYSET), 'O'));
|
||||||
|
fileMenu->AddItem(new BMenuItem("Append KeySet...",
|
||||||
|
new BMessage(APPEND_KEYSET), 'A'));
|
||||||
|
fileMenu->AddItem(new BMenuItem("Revert to Saved",
|
||||||
|
new BMessage(REVERT_KEYSET), 'A'));
|
||||||
|
fileMenu->AddItem(new BSeparatorItem);
|
||||||
|
fileMenu->AddItem(new BMenuItem("Save KeySet As...",
|
||||||
|
new BMessage(SAVE_KEYSET_AS), 'S'));
|
||||||
|
fileMenu->AddItem(new BSeparatorItem);
|
||||||
|
fileMenu->AddItem(new BMenuItem("About Shortcuts", new BMessage(B_ABOUT_REQUESTED)));
|
||||||
|
fileMenu->AddItem(new BSeparatorItem);
|
||||||
|
fileMenu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED),
|
||||||
|
'Q'));
|
||||||
|
menuBar->AddItem(fileMenu);
|
||||||
|
|
||||||
|
AddChild(menuBar);
|
||||||
|
|
||||||
|
font_height fh;
|
||||||
|
be_plain_font->GetHeight(&fh);
|
||||||
|
float vButtonHeight = ceil(fh.ascent) + ceil(fh.descent) + 5.0f;
|
||||||
|
|
||||||
|
BRect tableBounds = Bounds();
|
||||||
|
tableBounds.top = menuBar->Bounds().bottom + 1;
|
||||||
|
tableBounds.right -= B_V_SCROLL_BAR_WIDTH;
|
||||||
|
tableBounds.bottom -= (B_H_SCROLL_BAR_HEIGHT + V_SPACING + vButtonHeight +
|
||||||
|
V_SPACING * 2);
|
||||||
|
|
||||||
|
BScrollView* containerView;
|
||||||
|
fColumnListView = new ColumnListView(tableBounds, &containerView, NULL,
|
||||||
|
B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE,
|
||||||
|
B_SINGLE_SELECTION_LIST, true, true, true, B_NO_BORDER);
|
||||||
|
|
||||||
|
fColumnListView->SetEditMessage(new BMessage(HOTKEY_ITEM_MODIFIED),
|
||||||
|
BMessenger(this));
|
||||||
|
|
||||||
|
const float metaWidth = 50.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < ShortcutsSpec::NUM_META_COLUMNS; i++)
|
||||||
|
fColumnListView->AddColumn(
|
||||||
|
new CLVColumn(ShortcutsSpec::GetColumnName(i), CreateMetaPopUp(i),
|
||||||
|
metaWidth, CLV_SORT_KEYABLE));
|
||||||
|
|
||||||
|
fColumnListView->AddColumn(new CLVColumn("Key", CreateKeysPopUp(), 60,
|
||||||
|
CLV_SORT_KEYABLE));
|
||||||
|
|
||||||
|
BPopUpMenu* popup = new BPopUpMenu(NULL, false);
|
||||||
|
popup->AddItem(new BMenuItem("(Choose App with File Requester)", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*InsertString \"Your Text Here\"", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*MoveMouse +20 +0", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*MoveMouseTo 50% 50%", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*MouseButton 1", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*LaunchHandler text/html", NULL));
|
||||||
|
popup->AddItem(new BMenuItem(
|
||||||
|
"*Multi \"*MoveMouseTo 100% 0\" \"*MouseButton 1\"", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*MouseDown", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*MouseUp", NULL));
|
||||||
|
popup->AddItem(new BMenuItem(
|
||||||
|
"*SendMessage application/x-vnd.Be-TRAK 'Tfnd'", NULL));
|
||||||
|
popup->AddItem(new BMenuItem("*Beep", NULL));
|
||||||
|
fColumnListView->AddColumn(new CLVColumn("Application", popup, 323.0,
|
||||||
|
CLV_SORT_KEYABLE));
|
||||||
|
|
||||||
|
fColumnListView->SetSortFunction(ShortcutsSpec::MyCompare);
|
||||||
|
AddChild(containerView);
|
||||||
|
|
||||||
|
fColumnListView->SetSelectionMessage(new BMessage(HOTKEY_ITEM_SELECTED));
|
||||||
|
fColumnListView->SetTarget(this);
|
||||||
|
|
||||||
|
BRect buttonBounds = Bounds();
|
||||||
|
buttonBounds.left += V_SPACING;
|
||||||
|
buttonBounds.right = ((buttonBounds.right - buttonBounds.left) / 2.0f) +
|
||||||
|
buttonBounds.left;
|
||||||
|
buttonBounds.bottom -= V_SPACING * 2;
|
||||||
|
buttonBounds.top = buttonBounds.bottom - vButtonHeight;
|
||||||
|
buttonBounds.right -= B_V_SCROLL_BAR_WIDTH;
|
||||||
|
float origRight = buttonBounds.right;
|
||||||
|
buttonBounds.right = (buttonBounds.left + origRight) * 0.40f -
|
||||||
|
(V_SPACING / 2);
|
||||||
|
AddChild(fAddButton = new ResizableButton(Bounds(), buttonBounds, "add",
|
||||||
|
"Add New Shortcut", new BMessage(ADD_HOTKEY_ITEM)));
|
||||||
|
buttonBounds.left = buttonBounds.right + V_SPACING;
|
||||||
|
buttonBounds.right = origRight;
|
||||||
|
AddChild(fRemoveButton = new ResizableButton(Bounds(), buttonBounds,
|
||||||
|
"remove", "Remove Selected Shortcut",
|
||||||
|
new BMessage(REMOVE_HOTKEY_ITEM)));
|
||||||
|
|
||||||
|
fRemoveButton->SetEnabled(false);
|
||||||
|
|
||||||
|
float offset = (buttonBounds.right - buttonBounds.left) / 2.0f;
|
||||||
|
BRect saveButtonBounds = buttonBounds;
|
||||||
|
saveButtonBounds.right = Bounds().right - B_V_SCROLL_BAR_WIDTH - offset;
|
||||||
|
saveButtonBounds.left = buttonBounds.right + V_SPACING + offset;
|
||||||
|
AddChild(fSaveButton = new ResizableButton(Bounds(), saveButtonBounds,
|
||||||
|
"save", "Save & Apply", new BMessage(SAVE_KEYSET)));
|
||||||
|
|
||||||
|
fSaveButton->SetEnabled(false);
|
||||||
|
|
||||||
|
entry_ref ref;
|
||||||
|
if (_GetSettingsFile(&ref)) {
|
||||||
|
BMessage msg(B_REFS_RECEIVED);
|
||||||
|
msg.AddRef("refs", &ref);
|
||||||
|
msg.AddString("startupRef", "please");
|
||||||
|
PostMessage(&msg); // Tell ourself to load this file if it exists.
|
||||||
|
}
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsWindow::~ShortcutsWindow()
|
||||||
|
{
|
||||||
|
delete fSavePanel;
|
||||||
|
delete fOpenPanel;
|
||||||
|
delete fSelectPanel;
|
||||||
|
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsWindow::QuitRequested()
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if (fKeySetModified) {
|
||||||
|
BAlert* alert = new BAlert(WARNING,
|
||||||
|
"Really quit without saving your changes?", "Don't Save", "Cancel",
|
||||||
|
"Save");
|
||||||
|
switch(alert->Go()) {
|
||||||
|
case 1:
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Save: automatically if possible, otherwise go back and open
|
||||||
|
// up the file requester
|
||||||
|
if (fLastSaved.InitCheck() == B_NO_ERROR) {
|
||||||
|
if (_SaveKeySet(fLastSaved) == false) {
|
||||||
|
(new BAlert(ERROR,
|
||||||
|
"Shortcuts was unable to save your KeySet file!",
|
||||||
|
"Oh no"))->Go();
|
||||||
|
ret = true; //quit anyway
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PostMessage(SAVE_KEYSET);
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
fColumnListView->DeselectAll(); // avoid mysterious crash on PPC!?
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ShortcutsWindow::_GetSettingsFile(entry_ref* eref)
|
||||||
|
{
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
path.Append(SHORTCUTS_SETTING_FILE_NAME);
|
||||||
|
|
||||||
|
if (BEntry(path.Path(), true).GetRef(eref) == B_NO_ERROR)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Saves a settings file to (saveEntry). Returns true iff successful.
|
||||||
|
bool
|
||||||
|
ShortcutsWindow::_SaveKeySet(BEntry& saveEntry)
|
||||||
|
{
|
||||||
|
BFile saveTo(&saveEntry, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||||
|
if (saveTo.InitCheck() != B_NO_ERROR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BMessage saveMsg;
|
||||||
|
for (int i = 0; i < fColumnListView->CountItems(); i++) {
|
||||||
|
BMessage next;
|
||||||
|
if (((ShortcutsSpec*)fColumnListView->ItemAt(i))->Archive(&next)
|
||||||
|
== B_NO_ERROR)
|
||||||
|
saveMsg.AddMessage("spec", &next);
|
||||||
|
else
|
||||||
|
printf("Error archiving ShortcutsSpec #%i!\n",i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = (saveMsg.Flatten(&saveTo) == B_NO_ERROR);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
fKeySetModified = false;
|
||||||
|
fSaveButton->SetEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Appends new entries from the file specified in the "spec" entry of
|
||||||
|
// (loadMsg). Returns true iff successful.
|
||||||
|
bool
|
||||||
|
ShortcutsWindow::_LoadKeySet(const BMessage& loadMsg)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
BMessage msg;
|
||||||
|
while (loadMsg.FindMessage("spec", i++, &msg) == B_NO_ERROR) {
|
||||||
|
ShortcutsSpec* spec = (ShortcutsSpec*)ShortcutsSpec::Instantiate(&msg);
|
||||||
|
if (spec != NULL)
|
||||||
|
fColumnListView->AddItem(spec);
|
||||||
|
else
|
||||||
|
printf("_LoadKeySet: Error parsing spec!\n");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
void
|
||||||
|
ShortcutsWindow::_AddNewSpec(const char* defaultCommand)
|
||||||
|
{
|
||||||
|
_MarkKeySetModified();
|
||||||
|
|
||||||
|
ShortcutsSpec* spec;
|
||||||
|
int curSel = fColumnListView->CurrentSelection();
|
||||||
|
if (curSel >= 0) {
|
||||||
|
spec = new ShortcutsSpec(*((ShortcutsSpec*)
|
||||||
|
fColumnListView->ItemAt(curSel)));
|
||||||
|
|
||||||
|
if (defaultCommand)
|
||||||
|
spec->SetCommand(defaultCommand);
|
||||||
|
} else
|
||||||
|
spec = new ShortcutsSpec(defaultCommand ? defaultCommand : "");
|
||||||
|
|
||||||
|
fColumnListView->AddItem(spec);
|
||||||
|
fColumnListView->Select(fColumnListView->CountItems() - 1);
|
||||||
|
fColumnListView->ScrollToSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsWindow::MessageReceived(BMessage* msg)
|
||||||
|
{
|
||||||
|
switch(msg->what) {
|
||||||
|
case OPEN_KEYSET:
|
||||||
|
case APPEND_KEYSET:
|
||||||
|
fLastOpenWasAppend = (msg->what == APPEND_KEYSET);
|
||||||
|
if (fOpenPanel)
|
||||||
|
fOpenPanel->Show();
|
||||||
|
else {
|
||||||
|
BMessenger m(this);
|
||||||
|
fOpenPanel = new BFilePanel(B_OPEN_PANEL, &m, NULL, 0, false);
|
||||||
|
fOpenPanel->Show();
|
||||||
|
}
|
||||||
|
fOpenPanel->SetButtonLabel(B_DEFAULT_BUTTON, fLastOpenWasAppend ?
|
||||||
|
"Append" : "Open");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REVERT_KEYSET:
|
||||||
|
{
|
||||||
|
// Send a message to myself, to get me to reload the settings file
|
||||||
|
fLastOpenWasAppend = false;
|
||||||
|
BMessage reload(B_REFS_RECEIVED);
|
||||||
|
entry_ref eref;
|
||||||
|
_GetSettingsFile(&eref);
|
||||||
|
reload.AddRef("refs", &eref);
|
||||||
|
reload.AddString("startupRef", "yeah");
|
||||||
|
PostMessage(&reload);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Respond to drag-and-drop messages here
|
||||||
|
case B_SIMPLE_DATA:
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
entry_ref ref;
|
||||||
|
while (msg->FindRef("refs", i++, &ref) == B_NO_ERROR) {
|
||||||
|
BEntry entry(&ref);
|
||||||
|
if (entry.InitCheck() == B_NO_ERROR) {
|
||||||
|
BPath path(&entry);
|
||||||
|
|
||||||
|
if (path.InitCheck() == B_NO_ERROR) {
|
||||||
|
// Add a new item with the given path.
|
||||||
|
BString str(path.Path());
|
||||||
|
DoStandardEscapes(str);
|
||||||
|
_AddNewSpec(str.String());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Respond to FileRequester's messages here
|
||||||
|
case B_REFS_RECEIVED:
|
||||||
|
{
|
||||||
|
// Find file ref
|
||||||
|
entry_ref ref;
|
||||||
|
bool isStartMsg = msg->HasString("startupRef");
|
||||||
|
if (msg->FindRef("refs", &ref) == B_NO_ERROR) {
|
||||||
|
// load the file into (fileMsg)
|
||||||
|
BMessage fileMsg;
|
||||||
|
{
|
||||||
|
BFile file(&ref, B_READ_ONLY);
|
||||||
|
if ((file.InitCheck() != B_NO_ERROR)
|
||||||
|
|| (fileMsg.Unflatten(&file) != B_NO_ERROR)) {
|
||||||
|
if (isStartMsg) {
|
||||||
|
// use this to save to anyway
|
||||||
|
fLastSaved = BEntry(&ref);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
(new BAlert(ERROR,
|
||||||
|
"Shortcuts was couldn't open your KeySet file!"
|
||||||
|
, "Okay"))->Go(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fLastOpenWasAppend == false) {
|
||||||
|
// Clear the menu...
|
||||||
|
ShortcutsSpec * item;
|
||||||
|
do {
|
||||||
|
delete (item = ((ShortcutsSpec*)
|
||||||
|
fColumnListView->RemoveItem(int32(0))));
|
||||||
|
} while (item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_LoadKeySet(fileMsg)) {
|
||||||
|
if (isStartMsg) fLastSaved = BEntry(&ref);
|
||||||
|
fSaveButton->SetEnabled(isStartMsg == false);
|
||||||
|
|
||||||
|
// If we just loaded in the Shortcuts settings file, then
|
||||||
|
// no need to tell the user to save on exit.
|
||||||
|
entry_ref eref;
|
||||||
|
_GetSettingsFile(&eref);
|
||||||
|
if (ref == eref) fKeySetModified = false;
|
||||||
|
} else {
|
||||||
|
(new BAlert(ERROR,
|
||||||
|
"Shortcuts was unable to parse your KeySet file!",
|
||||||
|
"Okay"))->Go(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// These messages come from the pop-up menu of the Applications column
|
||||||
|
case SELECT_APPLICATION:
|
||||||
|
{
|
||||||
|
int csel = fColumnListView->CurrentSelection();
|
||||||
|
if (csel >= 0) {
|
||||||
|
entry_ref aref;
|
||||||
|
if (msg->FindRef("refs", &aref) == B_NO_ERROR) {
|
||||||
|
BEntry ent(&aref);
|
||||||
|
if (ent.InitCheck() == B_NO_ERROR) {
|
||||||
|
BPath path;
|
||||||
|
if ((ent.GetPath(&path) == B_NO_ERROR)
|
||||||
|
&& (((ShortcutsSpec *)
|
||||||
|
fColumnListView->ItemAt(csel))->
|
||||||
|
ProcessColumnTextString(ShortcutsSpec::
|
||||||
|
STRING_COLUMN_INDEX, path.Path()))) {
|
||||||
|
|
||||||
|
fColumnListView->InvalidateItem(csel);
|
||||||
|
_MarkKeySetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SAVE_KEYSET:
|
||||||
|
{
|
||||||
|
bool showSaveError = false;
|
||||||
|
|
||||||
|
const char * name;
|
||||||
|
entry_ref entry;
|
||||||
|
if ((msg->FindString("name", &name) == B_NO_ERROR)
|
||||||
|
&& (msg->FindRef("directory", &entry) == B_NO_ERROR)) {
|
||||||
|
BDirectory dir(&entry);
|
||||||
|
BEntry saveTo(&dir, name, true);
|
||||||
|
showSaveError = ((saveTo.InitCheck() != B_NO_ERROR)
|
||||||
|
|| (_SaveKeySet(saveTo) == false));
|
||||||
|
} else if (fLastSaved.InitCheck() == B_NO_ERROR) {
|
||||||
|
// We've saved this before, save over previous file.
|
||||||
|
showSaveError = (_SaveKeySet(fLastSaved) == false);
|
||||||
|
} else PostMessage(SAVE_KEYSET_AS); // open the save requester...
|
||||||
|
|
||||||
|
if (showSaveError) {
|
||||||
|
(new BAlert(ERROR, "Shortcuts wasn't able to save your keyset."
|
||||||
|
, "Okay"))->Go(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SAVE_KEYSET_AS:
|
||||||
|
{
|
||||||
|
if (fSavePanel)
|
||||||
|
fSavePanel->Show();
|
||||||
|
else {
|
||||||
|
BMessage msg(SAVE_KEYSET);
|
||||||
|
BMessenger messenger(this);
|
||||||
|
fSavePanel = new BFilePanel(B_SAVE_PANEL, &messenger, NULL, 0,
|
||||||
|
false, &msg);
|
||||||
|
fSavePanel->Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ABOUT_REQUESTED:
|
||||||
|
be_app_messenger.SendMessage(B_ABOUT_REQUESTED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADD_HOTKEY_ITEM:
|
||||||
|
_AddNewSpec(NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMOVE_HOTKEY_ITEM:
|
||||||
|
{
|
||||||
|
int index = fColumnListView->CurrentSelection();
|
||||||
|
if (index >= 0) {
|
||||||
|
CLVListItem* item = (CLVListItem*)
|
||||||
|
fColumnListView->ItemAt(index);
|
||||||
|
fColumnListView->RemoveItem(index);
|
||||||
|
delete item;
|
||||||
|
_MarkKeySetModified();
|
||||||
|
|
||||||
|
// Rules for new selection: If there is an item at (index),
|
||||||
|
// select it. Otherwise, if there is an item at (index-1),
|
||||||
|
// select it. Otherwise, select nothing.
|
||||||
|
int num = fColumnListView->CountItems();
|
||||||
|
if (num > 0) {
|
||||||
|
if (index < num)
|
||||||
|
fColumnListView->Select(index);
|
||||||
|
else {
|
||||||
|
if (index > 0)
|
||||||
|
index--;
|
||||||
|
if (index < num)
|
||||||
|
fColumnListView->Select(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Received when the user clicks on the ColumnListView
|
||||||
|
case HOTKEY_ITEM_SELECTED:
|
||||||
|
{
|
||||||
|
int32 index = -1;
|
||||||
|
msg->FindInt32("index", &index);
|
||||||
|
bool validItem = (index >= 0);
|
||||||
|
fRemoveButton->SetEnabled(validItem);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Received when an entry is to be modified in response to GUI activity
|
||||||
|
case HOTKEY_ITEM_MODIFIED:
|
||||||
|
{
|
||||||
|
int32 row, column;
|
||||||
|
|
||||||
|
if ((msg->FindInt32("row", &row) == B_NO_ERROR)
|
||||||
|
&& (msg->FindInt32("column", &column) == B_NO_ERROR)) {
|
||||||
|
int32 key;
|
||||||
|
const char* bytes;
|
||||||
|
|
||||||
|
if (row >= 0) {
|
||||||
|
ShortcutsSpec* item = (ShortcutsSpec*)
|
||||||
|
fColumnListView->ItemAt(row);
|
||||||
|
bool repaintNeeded = false; // default
|
||||||
|
|
||||||
|
if (msg->HasInt32("mouseClick")) {
|
||||||
|
repaintNeeded = item->ProcessColumnMouseClick(column);
|
||||||
|
} else if ((msg->FindString("bytes", &bytes) == B_NO_ERROR)
|
||||||
|
&& (msg->FindInt32("key", &key) == B_NO_ERROR)) {
|
||||||
|
repaintNeeded = item->ProcessColumnKeyStroke(column,
|
||||||
|
bytes, key);
|
||||||
|
} else if (msg->FindInt32("unmappedkey", &key) ==
|
||||||
|
B_NO_ERROR) {
|
||||||
|
repaintNeeded = ((column == item->KEY_COLUMN_INDEX)
|
||||||
|
&& ((key > 0xFF) || (GetKeyName(key) != NULL))
|
||||||
|
&& (item->ProcessColumnKeyStroke(column, NULL,
|
||||||
|
key)));
|
||||||
|
} else if (msg->FindString("text", &bytes) == B_NO_ERROR) {
|
||||||
|
if ((bytes[0] == '(')&&(bytes[1] == 'C')) {
|
||||||
|
if (fSelectPanel)
|
||||||
|
fSelectPanel->Show();
|
||||||
|
else {
|
||||||
|
BMessage msg(SELECT_APPLICATION);
|
||||||
|
BMessenger m(this);
|
||||||
|
fSelectPanel = new BFilePanel(B_OPEN_PANEL, &m,
|
||||||
|
NULL, 0, false, &msg);
|
||||||
|
fSelectPanel->Show();
|
||||||
|
}
|
||||||
|
fSelectPanel->SetButtonLabel(B_DEFAULT_BUTTON,
|
||||||
|
"Select");
|
||||||
|
} else
|
||||||
|
repaintNeeded = item->ProcessColumnTextString(
|
||||||
|
column, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repaintNeeded) {
|
||||||
|
fColumnListView->InvalidateItem(row);
|
||||||
|
_MarkKeySetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BWindow::MessageReceived(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsWindow::_MarkKeySetModified()
|
||||||
|
{
|
||||||
|
if (fKeySetModified == false) {
|
||||||
|
fKeySetModified = true;
|
||||||
|
fSaveButton->SetEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsWindow::Quit()
|
||||||
|
{
|
||||||
|
for (int i = fColumnListView->CountItems() - 1; i >= 0; i--)
|
||||||
|
delete (ShortcutsSpec*)fColumnListView->ItemAt(i);
|
||||||
|
|
||||||
|
fColumnListView->MakeEmpty();
|
||||||
|
BWindow::Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsWindow::FrameResized(float w, float h)
|
||||||
|
{
|
||||||
|
fAddButton->ChangeToNewSize(w, h);
|
||||||
|
fRemoveButton->ChangeToNewSize(w, h);
|
||||||
|
fSaveButton->ChangeToNewSize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShortcutsWindow::DispatchMessage(BMessage* msg, BHandler* handler)
|
||||||
|
{
|
||||||
|
switch(msg->what) {
|
||||||
|
case B_COPY:
|
||||||
|
case B_CUT:
|
||||||
|
if (be_clipboard->Lock()) {
|
||||||
|
int32 row = fColumnListView->CurrentSelection();
|
||||||
|
int32 column = fColumnListView->GetSelectedColumn();
|
||||||
|
if ((row >= 0)
|
||||||
|
&& (column == ShortcutsSpec::STRING_COLUMN_INDEX)) {
|
||||||
|
ShortcutsSpec* spec = (ShortcutsSpec*)
|
||||||
|
fColumnListView->ItemAt(row);
|
||||||
|
if (spec) {
|
||||||
|
BMessage* data = be_clipboard->Data();
|
||||||
|
data->RemoveName("text/plain");
|
||||||
|
data->AddData("text/plain", B_MIME_TYPE,
|
||||||
|
spec->GetCellText(column),
|
||||||
|
strlen(spec->GetCellText(column)));
|
||||||
|
be_clipboard->Commit();
|
||||||
|
|
||||||
|
if (msg->what == B_CUT) {
|
||||||
|
spec->ProcessColumnTextString(column, "");
|
||||||
|
_MarkKeySetModified();
|
||||||
|
fColumnListView->InvalidateItem(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
be_clipboard->Unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_PASTE:
|
||||||
|
if (be_clipboard->Lock()) {
|
||||||
|
BMessage* data = be_clipboard->Data();
|
||||||
|
const char* text;
|
||||||
|
ssize_t textLen;
|
||||||
|
if (data->FindData("text/plain", B_MIME_TYPE, (const void**)
|
||||||
|
&text, &textLen) == B_NO_ERROR) {
|
||||||
|
int32 row = fColumnListView->CurrentSelection();
|
||||||
|
int32 column = fColumnListView->GetSelectedColumn();
|
||||||
|
if ((row >= 0)
|
||||||
|
&& (column == ShortcutsSpec::STRING_COLUMN_INDEX)) {
|
||||||
|
ShortcutsSpec* spec = (ShortcutsSpec*)
|
||||||
|
fColumnListView->ItemAt(row);
|
||||||
|
if (spec) {
|
||||||
|
for (ssize_t i = 0; i < textLen; i++) {
|
||||||
|
char buf[2] = {text[i], 0x00};
|
||||||
|
spec->ProcessColumnKeyStroke(column, buf, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fColumnListView->InvalidateItem(row);
|
||||||
|
_MarkKeySetModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
be_clipboard->Unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BWindow::DispatchMessage(msg, handler);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ShortcutsWindow_h
|
||||||
|
#define ShortcutsWindow_h
|
||||||
|
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Window.h>
|
||||||
|
#include <Point.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <FilePanel.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
#include "ResizableButton.h"
|
||||||
|
|
||||||
|
// This class defines our preferences/configuration window.
|
||||||
|
class ShortcutsWindow : public BWindow {
|
||||||
|
public:
|
||||||
|
// If (optSaveTo) is non-NULL, settings will be loaded from the file it
|
||||||
|
// represents.
|
||||||
|
ShortcutsWindow();
|
||||||
|
~ShortcutsWindow();
|
||||||
|
|
||||||
|
virtual void DispatchMessage(BMessage* msg, BHandler* handler);
|
||||||
|
virtual void Quit();
|
||||||
|
virtual void FrameResized(float w, float h);
|
||||||
|
virtual void MessageReceived(BMessage * msg);
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
// BMessage 'what' codes, representing commands understood by this Window.
|
||||||
|
enum {
|
||||||
|
ADD_HOTKEY_ITEM = 'SpKy', // Add a new hotkey entry to the GUI list.
|
||||||
|
REMOVE_HOTKEY_ITEM, // Remove a hotkey entry from the GUI list.
|
||||||
|
HOTKEY_ITEM_SELECTED, // Give the "focus bar" to the specified
|
||||||
|
// entry.
|
||||||
|
HOTKEY_ITEM_MODIFIED, // Update the state of an entry to reflect
|
||||||
|
// user's changes.
|
||||||
|
OPEN_KEYSET, // Bring up a File requester to load new
|
||||||
|
// settings.
|
||||||
|
APPEND_KEYSET, // Bring up a File requester to append
|
||||||
|
// settings.
|
||||||
|
REVERT_KEYSET, // Dump the current state and re-read
|
||||||
|
// settings from disk.
|
||||||
|
SAVE_KEYSET, // Save the current settings to disk
|
||||||
|
SAVE_KEYSET_AS, // Bring up a File requester to save
|
||||||
|
// current settings.
|
||||||
|
SELECT_APPLICATION, // Set the current entry to point to the
|
||||||
|
// given file.
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
BMenuItem* _CreateActuatorPresetMenuItem(const char* label)
|
||||||
|
const;
|
||||||
|
void _AddNewSpec(const char* defaultCommand);
|
||||||
|
void _MarkKeySetModified();
|
||||||
|
bool _LoadKeySet(const BMessage& loadMsg);
|
||||||
|
bool _SaveKeySet(BEntry & saveEntry);
|
||||||
|
bool _GetSettingsFile(entry_ref* ref);
|
||||||
|
|
||||||
|
ResizableButton* fAddButton;
|
||||||
|
ResizableButton* fRemoveButton;
|
||||||
|
ResizableButton* fSaveButton;
|
||||||
|
ColumnListView* fColumnListView;
|
||||||
|
BFilePanel* fSavePanel; // for saving settings
|
||||||
|
BFilePanel* fOpenPanel; // for loading settings
|
||||||
|
BFilePanel* fSelectPanel; // for selecting apps to launch
|
||||||
|
|
||||||
|
// Points to the settings file to save to
|
||||||
|
BEntry fLastSaved;
|
||||||
|
|
||||||
|
// true iff changes were made since last load or save
|
||||||
|
bool fKeySetModified;
|
||||||
|
|
||||||
|
// true iff the file-requester's ref should be appended to current
|
||||||
|
bool fLastOpenWasAppend;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
//Column list header source file
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES
|
||||||
|
//******************************************************************************************************
|
||||||
|
#define CLVColumn_CPP
|
||||||
|
#include <string.h>
|
||||||
|
#include "CLVColumn.h"
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
#include "CLVColumnLabelView.h"
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CLVColumn CLASS DEFINITION
|
||||||
|
//******************************************************************************************************
|
||||||
|
CLVColumn::CLVColumn(const char* label,BPopUpMenu * popup,float width,uint32 flags,float min_width)
|
||||||
|
{
|
||||||
|
fPopup = popup;
|
||||||
|
|
||||||
|
if(flags & CLV_EXPANDER)
|
||||||
|
{
|
||||||
|
label = NULL;
|
||||||
|
width = 20.0;
|
||||||
|
min_width = 20.0;
|
||||||
|
flags &= CLV_NOT_MOVABLE | CLV_LOCK_AT_BEGINNING | CLV_HIDDEN | CLV_LOCK_WITH_RIGHT;
|
||||||
|
flags |= CLV_EXPANDER | CLV_NOT_RESIZABLE | CLV_MERGE_WITH_RIGHT;
|
||||||
|
}
|
||||||
|
if(min_width < 4.0)
|
||||||
|
min_width = 4.0;
|
||||||
|
if(width < min_width)
|
||||||
|
width = min_width;
|
||||||
|
if(label)
|
||||||
|
{
|
||||||
|
char* Temp = new char[strlen(label)+1];
|
||||||
|
strcpy(Temp,label);
|
||||||
|
label = Temp;
|
||||||
|
}
|
||||||
|
if(label)
|
||||||
|
{
|
||||||
|
fLabel = new char[strlen(label)+1];
|
||||||
|
strcpy((char*)fLabel,label);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fLabel = NULL;
|
||||||
|
fWidth = width;
|
||||||
|
fMinWidth = min_width;
|
||||||
|
fFlags = flags;
|
||||||
|
fPushedByExpander = false;
|
||||||
|
fParent = NULL;
|
||||||
|
fSortMode = NoSort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLVColumn::~CLVColumn()
|
||||||
|
{
|
||||||
|
if(fLabel) delete[] fLabel;
|
||||||
|
if(fParent) fParent->RemoveColumn(this);
|
||||||
|
delete fPopup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float CLVColumn::Width() const
|
||||||
|
{
|
||||||
|
return fWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumn::SetWidth(float width)
|
||||||
|
{
|
||||||
|
if(width < fMinWidth)
|
||||||
|
width = fMinWidth;
|
||||||
|
if(width != fWidth)
|
||||||
|
{
|
||||||
|
float OldWidth = fWidth;
|
||||||
|
fWidth = width;
|
||||||
|
if(IsShown() && fParent)
|
||||||
|
{
|
||||||
|
BWindow* ParentWindow = fParent->Window();
|
||||||
|
if(ParentWindow)
|
||||||
|
ParentWindow->Lock();
|
||||||
|
//Figure out the area after this column to scroll
|
||||||
|
BRect ColumnViewBounds = fParent->fColumnLabelView->Bounds();
|
||||||
|
BRect MainViewBounds = fParent->Bounds();
|
||||||
|
BRect SourceArea = ColumnViewBounds;
|
||||||
|
SourceArea.left = fColumnEnd+1.0;
|
||||||
|
BRect DestArea = SourceArea;
|
||||||
|
float Delta = width-OldWidth;
|
||||||
|
DestArea.left += Delta;
|
||||||
|
DestArea.right += Delta;
|
||||||
|
float LimitShift;
|
||||||
|
if(DestArea.right > ColumnViewBounds.right)
|
||||||
|
{
|
||||||
|
LimitShift = DestArea.right-ColumnViewBounds.right;
|
||||||
|
DestArea.right -= LimitShift;
|
||||||
|
SourceArea.right -= LimitShift;
|
||||||
|
}
|
||||||
|
if(DestArea.left < ColumnViewBounds.left)
|
||||||
|
{
|
||||||
|
LimitShift = ColumnViewBounds.left - DestArea.left;
|
||||||
|
DestArea.left += LimitShift;
|
||||||
|
SourceArea.left += LimitShift;
|
||||||
|
}
|
||||||
|
//Scroll the area that is being shifted
|
||||||
|
if(ParentWindow)
|
||||||
|
ParentWindow->UpdateIfNeeded();
|
||||||
|
fParent->fColumnLabelView->CopyBits(SourceArea,DestArea);
|
||||||
|
SourceArea.top = MainViewBounds.top;
|
||||||
|
SourceArea.bottom = MainViewBounds.bottom;
|
||||||
|
DestArea.top = MainViewBounds.top;
|
||||||
|
DestArea.bottom = MainViewBounds.bottom;
|
||||||
|
fParent->CopyBits(SourceArea,DestArea);
|
||||||
|
|
||||||
|
//Invalidate the region that got revealed
|
||||||
|
DestArea = ColumnViewBounds;
|
||||||
|
if(width > OldWidth)
|
||||||
|
{
|
||||||
|
DestArea.left = fColumnEnd+1.0;
|
||||||
|
DestArea.right = fColumnEnd+Delta;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DestArea.left = ColumnViewBounds.right+Delta+1.0;
|
||||||
|
DestArea.right = ColumnViewBounds.right;
|
||||||
|
}
|
||||||
|
fParent->fColumnLabelView->Invalidate(DestArea);
|
||||||
|
DestArea.top = MainViewBounds.top;
|
||||||
|
DestArea.bottom = MainViewBounds.bottom;
|
||||||
|
fParent->Invalidate(DestArea);
|
||||||
|
|
||||||
|
//Invalidate the old or new resize handle as necessary
|
||||||
|
DestArea = ColumnViewBounds;
|
||||||
|
if(width > OldWidth)
|
||||||
|
DestArea.left = fColumnEnd;
|
||||||
|
else
|
||||||
|
DestArea.left = fColumnEnd + Delta;
|
||||||
|
DestArea.right = DestArea.left;
|
||||||
|
fParent->fColumnLabelView->Invalidate(DestArea);
|
||||||
|
|
||||||
|
//Update the column sizes, positions and group positions
|
||||||
|
fParent->UpdateColumnSizesDataRectSizeScrollBars();
|
||||||
|
fParent->fColumnLabelView->UpdateDragGroups();
|
||||||
|
if(ParentWindow)
|
||||||
|
ParentWindow->Unlock();
|
||||||
|
}
|
||||||
|
if(fParent)
|
||||||
|
fParent->ColumnWidthChanged(fParent->fColumnList.IndexOf(this),fWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32 CLVColumn::Flags() const
|
||||||
|
{
|
||||||
|
return fFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CLVColumn::IsShown() const
|
||||||
|
{
|
||||||
|
if(fFlags & CLV_HIDDEN)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumn::SetShown(bool Shown)
|
||||||
|
{
|
||||||
|
bool shown = IsShown();
|
||||||
|
if(shown != Shown)
|
||||||
|
{
|
||||||
|
if(Shown)
|
||||||
|
fFlags &= 0xFFFFFFFF^CLV_HIDDEN;
|
||||||
|
else
|
||||||
|
fFlags |= CLV_HIDDEN;
|
||||||
|
if(fParent)
|
||||||
|
{
|
||||||
|
float UpdateLeft = fColumnBegin;
|
||||||
|
BWindow* ParentWindow = fParent->Window();
|
||||||
|
if(ParentWindow)
|
||||||
|
ParentWindow->Lock();
|
||||||
|
fParent->UpdateColumnSizesDataRectSizeScrollBars();
|
||||||
|
fParent->fColumnLabelView->UpdateDragGroups();
|
||||||
|
if(Shown)
|
||||||
|
UpdateLeft = fColumnBegin;
|
||||||
|
BRect Area = fParent->fColumnLabelView->Bounds();
|
||||||
|
Area.left = UpdateLeft;
|
||||||
|
fParent->fColumnLabelView->Invalidate(Area);
|
||||||
|
Area = fParent->Bounds();
|
||||||
|
Area.left = UpdateLeft;
|
||||||
|
fParent->Invalidate(Area);
|
||||||
|
if(fFlags & CLV_EXPANDER)
|
||||||
|
{
|
||||||
|
if(!Shown)
|
||||||
|
fParent->fExpanderColumn = -1;
|
||||||
|
else
|
||||||
|
fParent->fExpanderColumn = fParent->IndexOfColumn(this);
|
||||||
|
}
|
||||||
|
if(ParentWindow)
|
||||||
|
ParentWindow->Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLVSortMode CLVColumn::SortMode() const
|
||||||
|
{
|
||||||
|
return fSortMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLVColumn::SetSortMode(CLVSortMode mode)
|
||||||
|
{
|
||||||
|
if(fParent)
|
||||||
|
fParent->SetSortMode(fParent->IndexOfColumn(this),mode);
|
||||||
|
else
|
||||||
|
fSortMode = mode;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#ifndef CLVColumn_h
|
||||||
|
#define CLVColumn_h
|
||||||
|
|
||||||
|
#include <support/SupportDefs.h>
|
||||||
|
#include <interface/PopUpMenu.h>
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES AND CLASS NAME DECLARATIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
class ColumnListView;
|
||||||
|
class CLVColumn;
|
||||||
|
class CLVListItem;
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CONSTANTS
|
||||||
|
//******************************************************************************************************
|
||||||
|
//Flags
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CLV_SORT_KEYABLE = 0x00000001, //Can be used as the sorting key
|
||||||
|
CLV_NOT_MOVABLE = 0x00000002, //Column can't be moved by user
|
||||||
|
CLV_NOT_RESIZABLE = 0x00000004, //Column can't be resized by user
|
||||||
|
CLV_LOCK_AT_BEGINNING = 0x00000008, //Movable columns may not be placed or moved by the user
|
||||||
|
//into a position before this one
|
||||||
|
CLV_LOCK_AT_END = 0x00000010, //Movable columns may not be placed or moved by the user
|
||||||
|
//into a position after this one
|
||||||
|
CLV_HIDDEN = 0x00000020, //This column is hidden initially
|
||||||
|
CLV_MERGE_WITH_RIGHT = 0x00000040, //Merge this column label with the one that follows it.
|
||||||
|
CLV_LOCK_WITH_RIGHT = 0x00000080, //Lock this column to the one that follows it such that
|
||||||
|
//if the column to the right is moved by the user, this
|
||||||
|
//one will move with it and vice versa
|
||||||
|
CLV_EXPANDER = 0x00000100, //Column contains an expander. You may only use one
|
||||||
|
//expander in a ColumnListView, and an expander may not be
|
||||||
|
//added to a non-hierarchal ColumnListView. It may not
|
||||||
|
//have a label. Its width is automatically set to 20.0.
|
||||||
|
//The only flags that affect it are CLV_NOT_MOVABLE,
|
||||||
|
//CLV_LOCK_AT_BEGINNING, CLV_NOT_SHOWN and
|
||||||
|
//CLV_LOCK_WITH_RIGHT. The others are set for you:
|
||||||
|
//CLV_NOT_RESIZABLE | CLV_MERGE_WITH_RIGHT
|
||||||
|
CLV_PUSH_PASS = 0x00000200 //Causes this column, if pushed by an expander to the
|
||||||
|
//left, to pass that push on and also push the next
|
||||||
|
}; //column to the right.
|
||||||
|
|
||||||
|
enum CLVSortMode
|
||||||
|
{
|
||||||
|
Ascending,
|
||||||
|
Descending,
|
||||||
|
NoSort
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** ColumnListView CLASS DECLARATION
|
||||||
|
//******************************************************************************************************
|
||||||
|
class CLVColumn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Constructor and destructor
|
||||||
|
CLVColumn( const char* label,
|
||||||
|
BPopUpMenu * popup = NULL,
|
||||||
|
float width = 20.0,
|
||||||
|
uint32 flags = 0L,
|
||||||
|
float min_width = 20.0);
|
||||||
|
virtual ~CLVColumn();
|
||||||
|
|
||||||
|
//Archival stuff
|
||||||
|
/* Not implemented yet
|
||||||
|
CLVColumn(BMessage* archive);
|
||||||
|
static CLVColumn* Instantiate(BMessage* data);
|
||||||
|
virtual status_t Archive(BMessage* data, bool deep = true) const;
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Functions
|
||||||
|
float Width() const;
|
||||||
|
virtual void SetWidth(float width); //Can be overridden to detect changes to the column width
|
||||||
|
//however since you are probably overriding
|
||||||
|
//ColumnListView and dealing with an array of columns
|
||||||
|
//anyway, it is probably more useful to override
|
||||||
|
//ColumnListView::ColumnWidthChanged to detect changes to
|
||||||
|
//column widths
|
||||||
|
uint32 Flags() const;
|
||||||
|
bool IsShown() const;
|
||||||
|
void SetShown(bool shown);
|
||||||
|
CLVSortMode SortMode() const;
|
||||||
|
void SetSortMode(CLVSortMode mode);
|
||||||
|
const char * GetLabel() const {return fLabel;}
|
||||||
|
BPopUpMenu * GetPopup() {return fPopup;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ColumnListView;
|
||||||
|
friend class CLVColumnLabelView;
|
||||||
|
friend class CLVListItem;
|
||||||
|
|
||||||
|
const char *fLabel;
|
||||||
|
float fWidth;
|
||||||
|
float fMinWidth;
|
||||||
|
float fColumnBegin;
|
||||||
|
float fColumnEnd;
|
||||||
|
uint32 fFlags;
|
||||||
|
bool fPushedByExpander;
|
||||||
|
CLVSortMode fSortMode;
|
||||||
|
ColumnListView* fParent;
|
||||||
|
BPopUpMenu * fPopup; // added by jaf
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,756 @@
|
|||||||
|
//ColumnLabelView class source file
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES
|
||||||
|
//******************************************************************************************************
|
||||||
|
#define CLVColumnLabelView_CPP
|
||||||
|
#include "CLVColumnLabelView.h"
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
#include "CLVColumn.h"
|
||||||
|
#include "MouseWatcher.h"
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** FUNCTION DEFINITIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
CLVColumnLabelView::CLVColumnLabelView(BRect Bounds,ColumnListView* parent,const BFont* Font)
|
||||||
|
: BView(Bounds,NULL,B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP,B_WILL_DRAW|B_FRAME_EVENTS),
|
||||||
|
fDragGroups(10)
|
||||||
|
{
|
||||||
|
SetFont(Font);
|
||||||
|
SetViewColor(BeBackgroundGrey);
|
||||||
|
SetLowColor(BeBackgroundGrey);
|
||||||
|
SetHighColor(Black);
|
||||||
|
fParent = parent;
|
||||||
|
fDisplayList = &fParent->fColumnDisplayList;
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
fColumnDragging = false;
|
||||||
|
fColumnResizing = false;
|
||||||
|
font_height FontAttributes;
|
||||||
|
Font->GetHeight(&FontAttributes);
|
||||||
|
fFontAscent = ceil(FontAttributes.ascent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLVColumnLabelView::~CLVColumnLabelView()
|
||||||
|
{
|
||||||
|
int32 NumberOfGroups = fDragGroups.CountItems();
|
||||||
|
for(int32 Counter = 0; Counter < NumberOfGroups; Counter++)
|
||||||
|
fDragGroups.RemoveItem(int32(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::Draw(BRect UpdateRect)
|
||||||
|
{
|
||||||
|
BRegion ClippingRegion;
|
||||||
|
GetClippingRegion(&ClippingRegion);
|
||||||
|
BRect ViewBounds = Bounds();
|
||||||
|
|
||||||
|
//Draw each column label in turn
|
||||||
|
float ColumnBegin = 0.0;
|
||||||
|
float ColumnEnd = -1.0;
|
||||||
|
bool MergeWithLeft = false;
|
||||||
|
int32 NumberOfColumns = fDisplayList->CountItems();
|
||||||
|
BPoint Start,Stop;
|
||||||
|
for(int32 ColumnDraw = 0; ColumnDraw < NumberOfColumns; ColumnDraw++)
|
||||||
|
{
|
||||||
|
CLVColumn* ThisColumn = (CLVColumn*)fDisplayList->ItemAt(ColumnDraw);
|
||||||
|
if(ThisColumn->IsShown())
|
||||||
|
{
|
||||||
|
//Figure out where this column is
|
||||||
|
ColumnBegin = ThisColumn->fColumnBegin;
|
||||||
|
ColumnEnd = ThisColumn->fColumnEnd;
|
||||||
|
//Start by figuring out if this column will merge with a shown column to the right
|
||||||
|
bool MergeWithRight = false;
|
||||||
|
if(ThisColumn->fFlags & CLV_MERGE_WITH_RIGHT)
|
||||||
|
{
|
||||||
|
for(int32 ColumnCounter = ColumnDraw+1; ColumnCounter < NumberOfColumns;
|
||||||
|
ColumnCounter++)
|
||||||
|
{
|
||||||
|
CLVColumn* NextColumn = (CLVColumn*)fDisplayList->ItemAt(ColumnCounter);
|
||||||
|
if(NextColumn->IsShown())
|
||||||
|
{
|
||||||
|
//The next column is shown
|
||||||
|
MergeWithRight = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(!(NextColumn->fFlags & CLV_MERGE_WITH_RIGHT))
|
||||||
|
//The next column is not shown and doesn't pass on the merge
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ClippingRegion.Intersects(BRect(ColumnBegin,ViewBounds.top,ColumnEnd,
|
||||||
|
ViewBounds.bottom)))
|
||||||
|
{
|
||||||
|
//Need to draw this column
|
||||||
|
BeginLineArray(4);
|
||||||
|
//Top line
|
||||||
|
Start.Set(ColumnBegin,ViewBounds.top);
|
||||||
|
Stop.Set(ColumnEnd-1.0,ViewBounds.top);
|
||||||
|
if(MergeWithRight && !(ThisColumn == fColumnClicked && fColumnResizing))
|
||||||
|
Stop.x = ColumnEnd;
|
||||||
|
AddLine(Start,Stop,BeHighlight);
|
||||||
|
//Left line
|
||||||
|
if(!MergeWithLeft)
|
||||||
|
AddLine(BPoint(ColumnBegin,ViewBounds.top+1.0),
|
||||||
|
BPoint(ColumnBegin,ViewBounds.bottom),BeHighlight);
|
||||||
|
//Bottom line
|
||||||
|
Start.Set(ColumnBegin+1.0,ViewBounds.bottom);
|
||||||
|
if(MergeWithLeft)
|
||||||
|
Start.x = ColumnBegin;
|
||||||
|
Stop.Set(ColumnEnd-1.0,ViewBounds.bottom);
|
||||||
|
if(MergeWithRight && !(ThisColumn == fColumnClicked && fColumnResizing))
|
||||||
|
Stop.x = ColumnEnd;
|
||||||
|
AddLine(Start,Stop,BeShadow);
|
||||||
|
//Right line
|
||||||
|
if(ThisColumn == fColumnClicked && fColumnResizing)
|
||||||
|
AddLine(BPoint(ColumnEnd,ViewBounds.top),BPoint(ColumnEnd,ViewBounds.bottom),
|
||||||
|
BeFocusBlue);
|
||||||
|
else if(!MergeWithRight)
|
||||||
|
AddLine(BPoint(ColumnEnd,ViewBounds.top),BPoint(ColumnEnd,ViewBounds.bottom),
|
||||||
|
BeShadow);
|
||||||
|
EndLineArray();
|
||||||
|
|
||||||
|
//Add the label
|
||||||
|
if(ThisColumn->fLabel)
|
||||||
|
{
|
||||||
|
//Limit the clipping region to the interior of the box
|
||||||
|
BRegion TextRegion;
|
||||||
|
TextRegion.Include(BRect(ColumnBegin+1.0,ViewBounds.top+1.0,ColumnEnd-1.0,
|
||||||
|
ViewBounds.bottom-1.0));
|
||||||
|
ConstrainClippingRegion(&TextRegion);
|
||||||
|
|
||||||
|
//Draw the label
|
||||||
|
if(ThisColumn == fColumnClicked && !fColumnResizing)
|
||||||
|
SetHighColor(BeFocusBlue);
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
|
DrawString(ThisColumn->fLabel,BPoint(ColumnBegin+9.0,ViewBounds.top+2.0+fFontAscent));
|
||||||
|
SetDrawingMode(B_OP_COPY);
|
||||||
|
|
||||||
|
//Underline if this is a selected sort column
|
||||||
|
if(fParent->fSortKeyList.HasItem(ThisColumn) && ThisColumn->fSortMode != NoSort)
|
||||||
|
{
|
||||||
|
float Width = StringWidth(ThisColumn->fLabel);
|
||||||
|
StrokeLine(BPoint(ColumnBegin+8.0,ViewBounds.top+2.0+fFontAscent+2.0),
|
||||||
|
BPoint(ColumnBegin+8.0+Width,ViewBounds.top+2.0+fFontAscent+2.0));
|
||||||
|
}
|
||||||
|
if(ThisColumn == fColumnClicked && !fColumnResizing)
|
||||||
|
SetHighColor(Black);
|
||||||
|
|
||||||
|
//Restore the clipping region
|
||||||
|
ConstrainClippingRegion(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Set MergeWithLeft flag for the next column to the appropriate state
|
||||||
|
MergeWithLeft = MergeWithRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add highlight and shadow to the region after the columns if necessary
|
||||||
|
if(ColumnEnd < ViewBounds.right)
|
||||||
|
{
|
||||||
|
ColumnBegin = ColumnEnd+1.0;
|
||||||
|
if(ClippingRegion.Intersects(BRect(ColumnEnd+1.0,ViewBounds.top,ViewBounds.right,
|
||||||
|
ViewBounds.bottom)))
|
||||||
|
{
|
||||||
|
BeginLineArray(3);
|
||||||
|
//Top line
|
||||||
|
AddLine(BPoint(ColumnBegin,ViewBounds.top),BPoint(ViewBounds.right,ViewBounds.top),
|
||||||
|
BeHighlight);
|
||||||
|
//Left line
|
||||||
|
AddLine(BPoint(ColumnBegin,ViewBounds.top+1.0),BPoint(ColumnBegin,ViewBounds.bottom),
|
||||||
|
BeHighlight);
|
||||||
|
//Bottom line
|
||||||
|
Start.Set(ColumnBegin+1.0,ViewBounds.bottom);
|
||||||
|
if(MergeWithLeft)
|
||||||
|
Start.x = ColumnBegin;
|
||||||
|
Stop.Set(ViewBounds.right,ViewBounds.bottom);
|
||||||
|
AddLine(Start,Stop,BeShadow);
|
||||||
|
EndLineArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw the dragging box if necessary
|
||||||
|
if(fColumnClicked && fColumnDragging)
|
||||||
|
{
|
||||||
|
float DragOutlineLeft = fPreviousMousePos.x-fDragBoxMouseHoldOffset;
|
||||||
|
float GroupBegin = ((CLVDragGroup*)fDragGroups.ItemAt(fDragGroup))->GroupBegin;
|
||||||
|
if(DragOutlineLeft < GroupBegin && fSnapGroupBefore == -1)
|
||||||
|
DragOutlineLeft = GroupBegin;
|
||||||
|
if(DragOutlineLeft > GroupBegin && fSnapGroupAfter == -1)
|
||||||
|
DragOutlineLeft = GroupBegin;
|
||||||
|
float DragOutlineRight = DragOutlineLeft + fDragBoxWidth;
|
||||||
|
BeginLineArray(4);
|
||||||
|
AddLine(BPoint(DragOutlineLeft,ViewBounds.top),BPoint(DragOutlineRight,
|
||||||
|
ViewBounds.top),BeFocusBlue);
|
||||||
|
AddLine(BPoint(DragOutlineLeft,ViewBounds.bottom),BPoint(DragOutlineRight,
|
||||||
|
ViewBounds.bottom),BeFocusBlue);
|
||||||
|
AddLine(BPoint(DragOutlineLeft,ViewBounds.top+1.0),BPoint(DragOutlineLeft,
|
||||||
|
ViewBounds.bottom-1.0),BeFocusBlue);
|
||||||
|
AddLine(BPoint(DragOutlineRight,ViewBounds.top+1.0),BPoint(DragOutlineRight,
|
||||||
|
ViewBounds.bottom-1.0),BeFocusBlue);
|
||||||
|
EndLineArray();
|
||||||
|
fPrevDragOutlineLeft = DragOutlineLeft;
|
||||||
|
fPrevDragOutlineRight = DragOutlineRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::MouseDown(BPoint Point)
|
||||||
|
{
|
||||||
|
//Only pay attention to primary mouse button
|
||||||
|
bool WatchMouse = false;
|
||||||
|
BPoint MousePos;
|
||||||
|
uint32 Buttons;
|
||||||
|
GetMouse(&MousePos,&Buttons);
|
||||||
|
if(Buttons == B_PRIMARY_MOUSE_BUTTON)
|
||||||
|
{
|
||||||
|
BRect ViewBounds = Bounds();
|
||||||
|
|
||||||
|
//Make sure no other column was already clicked. If so, just discard the old one and redraw the
|
||||||
|
//view
|
||||||
|
if(fColumnClicked != NULL)
|
||||||
|
{
|
||||||
|
Invalidate();
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find the column that the user clicked, if any
|
||||||
|
bool GrabbedResizeTab = false;
|
||||||
|
int32 NumberOfColumns = fDisplayList->CountItems();
|
||||||
|
int32 ColumnFind;
|
||||||
|
CLVColumn* ThisColumn;
|
||||||
|
for(ColumnFind = 0; ColumnFind < NumberOfColumns; ColumnFind++)
|
||||||
|
{
|
||||||
|
ThisColumn = (CLVColumn*)fDisplayList->ItemAt(ColumnFind);
|
||||||
|
if(ThisColumn->IsShown())
|
||||||
|
{
|
||||||
|
float ColumnBegin = ThisColumn->fColumnBegin;
|
||||||
|
float ColumnEnd = ThisColumn->fColumnEnd;
|
||||||
|
if ((Point.x >= ColumnBegin && Point.x <= ColumnEnd) ||
|
||||||
|
((ColumnFind == NumberOfColumns-1)&&(Point.x >= ColumnBegin))) // anything after the rightmost column can drag... jaf
|
||||||
|
{
|
||||||
|
const float resizeTolerance = 5.0f; // jaf is too clumsy to click on a 2 pixel space. :)
|
||||||
|
|
||||||
|
//User clicked in this column
|
||||||
|
if(Point.x <= ColumnBegin+resizeTolerance)
|
||||||
|
{
|
||||||
|
//User clicked the resize tab preceding this column
|
||||||
|
for(ColumnFind--; ColumnFind >= 0; ColumnFind--)
|
||||||
|
{
|
||||||
|
ThisColumn = (CLVColumn*)fDisplayList->ItemAt(ColumnFind);
|
||||||
|
if(ThisColumn->IsShown())
|
||||||
|
{
|
||||||
|
GrabbedResizeTab = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(Point.x >= ColumnEnd-resizeTolerance)
|
||||||
|
{
|
||||||
|
//User clicked the resize tab for (after) this column
|
||||||
|
GrabbedResizeTab = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The user clicked in this column
|
||||||
|
fColumnClicked = (CLVColumn*)fDisplayList->ItemAt(ColumnFind);
|
||||||
|
fColumnResizing = false;
|
||||||
|
fPreviousMousePos = Point;
|
||||||
|
fMouseClickedPos = Point;
|
||||||
|
fColumnDragging = false;
|
||||||
|
SetSnapMinMax();
|
||||||
|
fDragBoxMouseHoldOffset = Point.x-
|
||||||
|
((CLVDragGroup*)fDragGroups.ItemAt(fDragGroup))->GroupBegin;
|
||||||
|
Invalidate(BRect(ColumnBegin+1.0,ViewBounds.top+1.0,ColumnEnd-1.0,
|
||||||
|
ViewBounds.bottom-1.0));
|
||||||
|
|
||||||
|
//Start watching the mouse
|
||||||
|
WatchMouse = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(GrabbedResizeTab)
|
||||||
|
{
|
||||||
|
//The user grabbed a resize tab. See if resizing of this column is allowed
|
||||||
|
if(!(ThisColumn->fFlags & CLV_NOT_RESIZABLE))
|
||||||
|
{
|
||||||
|
fColumnClicked = (CLVColumn*)fDisplayList->ItemAt(ColumnFind);
|
||||||
|
fColumnResizing = true;
|
||||||
|
fPreviousMousePos = Point;
|
||||||
|
fMouseClickedPos = Point;
|
||||||
|
fColumnDragging = false;
|
||||||
|
fResizeMouseHoldOffset = Point.x-fColumnClicked->fColumnEnd;
|
||||||
|
Invalidate(BRect(fColumnClicked->fColumnEnd,ViewBounds.top,ThisColumn->fColumnEnd,
|
||||||
|
ViewBounds.bottom));
|
||||||
|
|
||||||
|
//Start watching the mouse
|
||||||
|
WatchMouse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(WatchMouse)
|
||||||
|
{
|
||||||
|
thread_id MouseWatcherThread = StartMouseWatcher(this);
|
||||||
|
if(MouseWatcherThread == B_NO_MORE_THREADS || MouseWatcherThread == B_NO_MEMORY)
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::MessageReceived(BMessage *message)
|
||||||
|
{
|
||||||
|
if(message->what != MW_MOUSE_MOVED && message->what != MW_MOUSE_DOWN && message->what != MW_MOUSE_UP)
|
||||||
|
BView::MessageReceived(message);
|
||||||
|
else if(fColumnClicked != NULL)
|
||||||
|
{
|
||||||
|
BPoint MousePos;
|
||||||
|
message->FindPoint("where",&MousePos);
|
||||||
|
uint32 Buttons;
|
||||||
|
message->FindInt32("buttons",(int32*)&Buttons);
|
||||||
|
uint32 Modifiers;
|
||||||
|
message->FindInt32("modifiers",(int32*)&Modifiers);
|
||||||
|
BRect ViewBounds;
|
||||||
|
ViewBounds = Bounds();
|
||||||
|
uint32 ColumnFlags = fColumnClicked->Flags();
|
||||||
|
if(Buttons == B_PRIMARY_MOUSE_BUTTON)
|
||||||
|
{
|
||||||
|
//Mouse is still held down
|
||||||
|
if(!fColumnResizing)
|
||||||
|
{
|
||||||
|
//User is clicking or dragging
|
||||||
|
if((MousePos.x<fMouseClickedPos.x-2.0 || MousePos.x>fMouseClickedPos.x+2.0) &&
|
||||||
|
!fColumnDragging)
|
||||||
|
{
|
||||||
|
//User is initiating a drag
|
||||||
|
if(fTheDragGroup->Flags & CLV_NOT_MOVABLE)
|
||||||
|
{
|
||||||
|
//Not allowed to drag this column - terminate the click
|
||||||
|
Invalidate(BRect(fColumnClicked->fColumnBegin,ViewBounds.top,
|
||||||
|
fColumnClicked->fColumnEnd,ViewBounds.bottom));
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Actually initiate a drag
|
||||||
|
fColumnDragging = true;
|
||||||
|
fPrevDragOutlineLeft = -1.0;
|
||||||
|
fPrevDragOutlineRight = -1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Now deal with dragging
|
||||||
|
if(fColumnDragging)
|
||||||
|
{
|
||||||
|
//User is dragging
|
||||||
|
if(MousePos.x<fPreviousMousePos.x || MousePos.x>fPreviousMousePos.x)
|
||||||
|
{
|
||||||
|
//Mouse moved since I last checked
|
||||||
|
ViewBounds = Bounds();
|
||||||
|
|
||||||
|
bool ColumnSnapped;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//Live dragging of columns
|
||||||
|
ColumnSnapped = false;
|
||||||
|
float ColumnsUpdateLeft,ColumnsUpdateRight;
|
||||||
|
float MainViewUpdateLeft,MainViewUpdateRight;
|
||||||
|
CLVColumn* LastSwapColumn;
|
||||||
|
if(fSnapMin != -1.0 && MousePos.x < fSnapMin)
|
||||||
|
{
|
||||||
|
//Shift the group left
|
||||||
|
ColumnsUpdateLeft = fTheShownGroupBefore->GroupBegin;
|
||||||
|
ColumnsUpdateRight = fTheDragGroup->GroupEnd;
|
||||||
|
MainViewUpdateLeft = ColumnsUpdateLeft;
|
||||||
|
MainViewUpdateRight = ColumnsUpdateRight;
|
||||||
|
LastSwapColumn = fTheShownGroupBefore->LastColumnShown;
|
||||||
|
if(fTheDragGroup->LastColumnShown->fFlags & CLV_MERGE_WITH_RIGHT)
|
||||||
|
ColumnsUpdateRight += 1.0;
|
||||||
|
else if(fTheShownGroupBefore->LastColumnShown->fFlags & CLV_MERGE_WITH_RIGHT)
|
||||||
|
ColumnsUpdateRight += 1.0;
|
||||||
|
ShiftDragGroup(fSnapGroupBefore);
|
||||||
|
ColumnSnapped = true;
|
||||||
|
}
|
||||||
|
if(fSnapMax != -1.0 && MousePos.x > fSnapMax)
|
||||||
|
{
|
||||||
|
//Shift the group right
|
||||||
|
ColumnsUpdateLeft = fTheDragGroup->GroupBegin;
|
||||||
|
ColumnsUpdateRight = fTheShownGroupAfter->GroupEnd;
|
||||||
|
MainViewUpdateLeft = ColumnsUpdateLeft;
|
||||||
|
MainViewUpdateRight = ColumnsUpdateRight;
|
||||||
|
LastSwapColumn = fTheDragGroup->LastColumnShown;
|
||||||
|
if(fTheDragGroup->LastColumnShown->fFlags & CLV_MERGE_WITH_RIGHT)
|
||||||
|
ColumnsUpdateRight += 1.0;
|
||||||
|
else if(fTheShownGroupAfter->LastColumnShown->fFlags & CLV_MERGE_WITH_RIGHT)
|
||||||
|
ColumnsUpdateRight += 1.0;
|
||||||
|
ShiftDragGroup(fSnapGroupAfter+1);
|
||||||
|
ColumnSnapped = true;
|
||||||
|
}
|
||||||
|
if(ColumnSnapped)
|
||||||
|
{
|
||||||
|
//Redraw the snapped column labels
|
||||||
|
Invalidate(BRect(ColumnsUpdateLeft,ViewBounds.top,ColumnsUpdateRight,
|
||||||
|
ViewBounds.bottom));
|
||||||
|
BRect MainViewBounds = fParent->Bounds();
|
||||||
|
//Modify MainViewUpdateRight if more columns are pushed by expanders
|
||||||
|
if(LastSwapColumn->fFlags & CLV_EXPANDER ||
|
||||||
|
(LastSwapColumn->fPushedByExpander && (LastSwapColumn->fFlags &
|
||||||
|
CLV_PUSH_PASS)))
|
||||||
|
{
|
||||||
|
int32 NumberOfColumns = fDisplayList->CountItems();
|
||||||
|
for(int32 ColumnCounter = fDisplayList->IndexOf(LastSwapColumn)+1;
|
||||||
|
ColumnCounter < NumberOfColumns; ColumnCounter++)
|
||||||
|
{
|
||||||
|
CLVColumn* ThisColumn =
|
||||||
|
(CLVColumn*)fDisplayList->ItemAt(ColumnCounter);
|
||||||
|
if(ThisColumn->IsShown())
|
||||||
|
{
|
||||||
|
if(ThisColumn->fPushedByExpander)
|
||||||
|
MainViewUpdateRight = ThisColumn->fColumnEnd;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fParent->Invalidate(BRect(MainViewUpdateLeft,MainViewBounds.top,
|
||||||
|
MainViewUpdateRight,MainViewBounds.bottom));
|
||||||
|
}
|
||||||
|
}while(ColumnSnapped);
|
||||||
|
//Erase and redraw the drag rectangle but not the interior to avoid label flicker
|
||||||
|
float Min = fPrevDragOutlineLeft;
|
||||||
|
float Max = fPrevDragOutlineRight;
|
||||||
|
float Min2 = MousePos.x-fDragBoxMouseHoldOffset;
|
||||||
|
float GroupBegin = ((CLVDragGroup*)fDragGroups.ItemAt(fDragGroup))->GroupBegin;
|
||||||
|
if(Min2 < GroupBegin && fSnapGroupBefore == -1)
|
||||||
|
Min2 = GroupBegin;
|
||||||
|
if(Min2 > GroupBegin && fSnapGroupAfter == -1)
|
||||||
|
Min2 = GroupBegin;
|
||||||
|
float Max2 = Min2 + fDragBoxWidth;
|
||||||
|
float Temp;
|
||||||
|
if(Min2 < Min || Min == -1.0)
|
||||||
|
{Temp = Min2;Min2 = Min;Min = Temp;}
|
||||||
|
if(Max2 > Max || Max == -1.0)
|
||||||
|
{Temp = Max2;Max2 = Max;Max = Temp;}
|
||||||
|
Invalidate(BRect(Min,ViewBounds.top+1.0,Min,ViewBounds.bottom-1.0));
|
||||||
|
if(Min2 != -1.0)
|
||||||
|
Invalidate(BRect(Min2,ViewBounds.top+1.0,Min2,ViewBounds.bottom-1.0));
|
||||||
|
Invalidate(BRect(Max,ViewBounds.top+1.0,Max,ViewBounds.bottom-1.0));
|
||||||
|
if(Max2 != -1.0)
|
||||||
|
Invalidate(BRect(Max2,ViewBounds.top+1.0,Max2,ViewBounds.bottom-1.0));
|
||||||
|
Invalidate(BRect(Min,ViewBounds.top,Max,ViewBounds.top));
|
||||||
|
Invalidate(BRect(Min,ViewBounds.bottom,Max,ViewBounds.bottom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//User is resizing the column
|
||||||
|
if(MousePos.x<fPreviousMousePos.x || MousePos.x>fPreviousMousePos.x)
|
||||||
|
{
|
||||||
|
float NewWidth = MousePos.x - fResizeMouseHoldOffset - fColumnClicked->fColumnBegin;
|
||||||
|
if(NewWidth < fColumnClicked->fMinWidth)
|
||||||
|
NewWidth = fColumnClicked->fMinWidth;
|
||||||
|
if(NewWidth != fColumnClicked->fWidth)
|
||||||
|
{
|
||||||
|
fColumnClicked->SetWidth(NewWidth);
|
||||||
|
fParent->ColumnWidthChanged(fParent->IndexOfColumn(fColumnClicked),NewWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(Buttons == 0)
|
||||||
|
{
|
||||||
|
//Mouse button was released
|
||||||
|
if(!fColumnDragging && !fColumnResizing)
|
||||||
|
{
|
||||||
|
//Column was clicked
|
||||||
|
if(ColumnFlags&CLV_SORT_KEYABLE)
|
||||||
|
{
|
||||||
|
//The column is a "sortable" column
|
||||||
|
if(!(Modifiers&B_SHIFT_KEY))
|
||||||
|
{
|
||||||
|
//The user wants to select it as the main sorting column
|
||||||
|
if(fParent->fSortKeyList.ItemAt(0) == fColumnClicked)
|
||||||
|
//The column was already selected; switch sort modes
|
||||||
|
fParent->ReverseSortMode(fParent->fColumnList.IndexOf(fColumnClicked));
|
||||||
|
else
|
||||||
|
//The user selected this column for sorting
|
||||||
|
fParent->SetSortKey(fParent->fColumnList.IndexOf(fColumnClicked));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The user wants to add it as a secondary sorting column
|
||||||
|
if(fParent->fSortKeyList.HasItem(fColumnClicked))
|
||||||
|
//The column was already selected; switch sort modes
|
||||||
|
fParent->ReverseSortMode(fParent->fColumnList.IndexOf(fColumnClicked));
|
||||||
|
else
|
||||||
|
//The user selected this column for sorting
|
||||||
|
fParent->AddSortKey(fParent->fColumnList.IndexOf(fColumnClicked));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(fColumnDragging)
|
||||||
|
{
|
||||||
|
//Column was dragging; erase the drag box but not the interior to avoid label flicker
|
||||||
|
Invalidate(BRect(fPrevDragOutlineLeft,ViewBounds.top+1.0,
|
||||||
|
fPrevDragOutlineLeft,ViewBounds.bottom-1.0));
|
||||||
|
Invalidate(BRect(fPrevDragOutlineRight,ViewBounds.top+1.0,
|
||||||
|
fPrevDragOutlineRight,ViewBounds.bottom-1.0));
|
||||||
|
Invalidate(BRect(fPrevDragOutlineLeft,ViewBounds.top,
|
||||||
|
fPrevDragOutlineRight,ViewBounds.top));
|
||||||
|
Invalidate(BRect(fPrevDragOutlineLeft,ViewBounds.bottom,
|
||||||
|
fPrevDragOutlineRight,ViewBounds.bottom));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
//Column was resizing; erase the drag tab
|
||||||
|
Invalidate(BRect(fColumnClicked->fColumnEnd,ViewBounds.top,fColumnClicked->fColumnEnd,
|
||||||
|
ViewBounds.bottom));
|
||||||
|
//Unhighlight the label and forget the column
|
||||||
|
Invalidate(BRect(fColumnClicked->fColumnBegin+1.0,ViewBounds.top+1.0,
|
||||||
|
fColumnClicked->fColumnEnd-1.0,ViewBounds.bottom-1.0));
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
fColumnDragging = false;
|
||||||
|
fColumnResizing = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Unused button combination
|
||||||
|
//Unhighlight the label and forget the column
|
||||||
|
Invalidate(BRect(fColumnClicked->fColumnBegin+1.0,ViewBounds.top+1.0,
|
||||||
|
fColumnClicked->fColumnEnd-1.0,ViewBounds.bottom-1.0));
|
||||||
|
fColumnClicked = NULL;
|
||||||
|
fColumnDragging = false;
|
||||||
|
fColumnResizing = false;
|
||||||
|
}
|
||||||
|
fPreviousMousePos = MousePos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::ShiftDragGroup(int32 NewPos)
|
||||||
|
//Shift the drag group into a new position
|
||||||
|
{
|
||||||
|
int32 NumberOfGroups = fDragGroups.CountItems();
|
||||||
|
int32 GroupCounter;
|
||||||
|
CLVDragGroup* ThisGroup;
|
||||||
|
int32 NumberOfColumnsInGroup;
|
||||||
|
int32 ColumnCounter;
|
||||||
|
BList NewDisplayList;
|
||||||
|
|
||||||
|
//Copy the groups up to the new position
|
||||||
|
for(GroupCounter = 0; GroupCounter < NewPos; GroupCounter++)
|
||||||
|
{
|
||||||
|
if(GroupCounter != fDragGroup)
|
||||||
|
{
|
||||||
|
ThisGroup = (CLVDragGroup*)fDragGroups.ItemAt(GroupCounter);
|
||||||
|
NumberOfColumnsInGroup = ThisGroup->GroupStopDispListIndex -
|
||||||
|
ThisGroup->GroupStartDispListIndex + 1;
|
||||||
|
for(ColumnCounter = ThisGroup->GroupStartDispListIndex; ColumnCounter <=
|
||||||
|
ThisGroup->GroupStopDispListIndex; ColumnCounter++)
|
||||||
|
NewDisplayList.AddItem(fDisplayList->ItemAt(ColumnCounter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Copy the group into the new position
|
||||||
|
ThisGroup = (CLVDragGroup*)fDragGroups.ItemAt(fDragGroup);
|
||||||
|
NumberOfColumnsInGroup = ThisGroup->GroupStopDispListIndex - ThisGroup->GroupStartDispListIndex + 1;
|
||||||
|
for(ColumnCounter = ThisGroup->GroupStartDispListIndex; ColumnCounter <=
|
||||||
|
ThisGroup->GroupStopDispListIndex; ColumnCounter++)
|
||||||
|
NewDisplayList.AddItem(fDisplayList->ItemAt(ColumnCounter));
|
||||||
|
//Copy the rest of the groups, but skip the dragging group
|
||||||
|
for(GroupCounter = NewPos; GroupCounter < NumberOfGroups; GroupCounter++)
|
||||||
|
{
|
||||||
|
if(GroupCounter != fDragGroup)
|
||||||
|
{
|
||||||
|
ThisGroup = (CLVDragGroup*)fDragGroups.ItemAt(GroupCounter);
|
||||||
|
NumberOfColumnsInGroup = ThisGroup->GroupStopDispListIndex -
|
||||||
|
ThisGroup->GroupStartDispListIndex + 1;
|
||||||
|
for(ColumnCounter = ThisGroup->GroupStartDispListIndex; ColumnCounter <=
|
||||||
|
ThisGroup->GroupStopDispListIndex; ColumnCounter++)
|
||||||
|
NewDisplayList.AddItem(fDisplayList->ItemAt(ColumnCounter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the new order
|
||||||
|
*fDisplayList = NewDisplayList;
|
||||||
|
|
||||||
|
//Update columns and drag groups
|
||||||
|
fParent->UpdateColumnSizesDataRectSizeScrollBars();
|
||||||
|
UpdateDragGroups();
|
||||||
|
SetSnapMinMax();
|
||||||
|
|
||||||
|
//Inform the program that the display order changed
|
||||||
|
int32* NewOrder = fParent->DisplayOrder();
|
||||||
|
fParent->DisplayOrderChanged(NewOrder);
|
||||||
|
delete[] NewOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::UpdateDragGroups()
|
||||||
|
{
|
||||||
|
//Make a copy of the DragGroups list. Use it to store the CLVDragGroup's for recycling
|
||||||
|
BList TempList(fDragGroups);
|
||||||
|
fDragGroups.MakeEmpty();
|
||||||
|
int32 NumberOfColumns = fDisplayList->CountItems();
|
||||||
|
bool ContinueGroup = false;
|
||||||
|
CLVDragGroup* CurrentGroup;
|
||||||
|
for(int32 Counter = 0; Counter < NumberOfColumns; Counter++)
|
||||||
|
{
|
||||||
|
CLVColumn* CurrentColumn = (CLVColumn*)fDisplayList->ItemAt(Counter);
|
||||||
|
if(!ContinueGroup)
|
||||||
|
{
|
||||||
|
//Recycle or obtain a new CLVDragGroup
|
||||||
|
CurrentGroup = (CLVDragGroup*)TempList.RemoveItem(int32(0));
|
||||||
|
if(CurrentGroup == NULL)
|
||||||
|
CurrentGroup = new CLVDragGroup;
|
||||||
|
//Add the CLVDragGroup to the DragGroups list
|
||||||
|
fDragGroups.AddItem(CurrentGroup);
|
||||||
|
//Set up the new DragGroup
|
||||||
|
CurrentGroup->GroupStartDispListIndex = Counter;
|
||||||
|
CurrentGroup->GroupStopDispListIndex = Counter;
|
||||||
|
CurrentGroup->Flags = 0;
|
||||||
|
if(CurrentColumn->IsShown())
|
||||||
|
{
|
||||||
|
CurrentGroup->GroupBegin = CurrentColumn->fColumnBegin;
|
||||||
|
CurrentGroup->GroupEnd = CurrentColumn->fColumnEnd;
|
||||||
|
CurrentGroup->LastColumnShown = CurrentColumn;
|
||||||
|
CurrentGroup->Shown = true;
|
||||||
|
if(CurrentColumn->fFlags & CLV_LOCK_AT_BEGINNING)
|
||||||
|
CurrentGroup->AllLockBeginning = true;
|
||||||
|
else
|
||||||
|
CurrentGroup->AllLockBeginning = false;
|
||||||
|
if(CurrentColumn->fFlags & CLV_LOCK_AT_END)
|
||||||
|
CurrentGroup->AllLockEnd = true;
|
||||||
|
else
|
||||||
|
CurrentGroup->AllLockEnd = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentGroup->GroupBegin = -1.0;
|
||||||
|
CurrentGroup->GroupEnd = -1.0;
|
||||||
|
CurrentGroup->LastColumnShown = NULL;
|
||||||
|
CurrentGroup->Shown = false;
|
||||||
|
if(CurrentColumn->fFlags & CLV_LOCK_AT_BEGINNING)
|
||||||
|
CurrentGroup->AllLockBeginning = true;
|
||||||
|
else
|
||||||
|
CurrentGroup->AllLockBeginning = false;
|
||||||
|
if(CurrentColumn->fFlags & CLV_LOCK_AT_END)
|
||||||
|
CurrentGroup->AllLockEnd = true;
|
||||||
|
else
|
||||||
|
CurrentGroup->AllLockEnd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Add this column to the current DragGroup
|
||||||
|
CurrentGroup->GroupStopDispListIndex = Counter;
|
||||||
|
if(CurrentColumn->IsShown())
|
||||||
|
{
|
||||||
|
if(CurrentGroup->GroupBegin == -1.0)
|
||||||
|
CurrentGroup->GroupBegin = CurrentColumn->fColumnBegin;
|
||||||
|
CurrentGroup->GroupEnd = CurrentColumn->fColumnEnd;
|
||||||
|
CurrentGroup->LastColumnShown = CurrentColumn;
|
||||||
|
CurrentGroup->Shown = true;
|
||||||
|
}
|
||||||
|
if(!(CurrentColumn->fFlags & CLV_LOCK_AT_BEGINNING))
|
||||||
|
CurrentGroup->AllLockBeginning = false;
|
||||||
|
if(!(CurrentColumn->fFlags & CLV_LOCK_AT_END))
|
||||||
|
CurrentGroup->AllLockEnd = false;
|
||||||
|
}
|
||||||
|
CurrentGroup->Flags |= CurrentColumn->fFlags & (CLV_NOT_MOVABLE|CLV_LOCK_AT_BEGINNING|
|
||||||
|
CLV_LOCK_AT_END);
|
||||||
|
//See if I should add more columns to this group
|
||||||
|
if(CurrentColumn->fFlags & CLV_LOCK_WITH_RIGHT)
|
||||||
|
ContinueGroup = true;
|
||||||
|
else
|
||||||
|
ContinueGroup = false;
|
||||||
|
}
|
||||||
|
//If any unused groups remain in TempList, delete them
|
||||||
|
while((CurrentGroup = (CLVDragGroup*)TempList.RemoveItem(int32(0))) != NULL)
|
||||||
|
delete CurrentGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVColumnLabelView::SetSnapMinMax()
|
||||||
|
{
|
||||||
|
//Find the column group that the user is dragging and the shown group before it
|
||||||
|
int32 NumberOfGroups = fDragGroups.CountItems();
|
||||||
|
int32 ColumnCount;
|
||||||
|
fDragGroup = -1;
|
||||||
|
fTheShownGroupBefore = NULL;
|
||||||
|
fSnapGroupBefore = -1;
|
||||||
|
CLVDragGroup* ThisGroup;
|
||||||
|
int32 GroupCounter;
|
||||||
|
for(GroupCounter = 0; GroupCounter < NumberOfGroups; GroupCounter++)
|
||||||
|
{
|
||||||
|
ThisGroup = (CLVDragGroup*)fDragGroups.ItemAt(GroupCounter);
|
||||||
|
for(ColumnCount = ThisGroup->GroupStartDispListIndex; ColumnCount <=
|
||||||
|
ThisGroup->GroupStopDispListIndex; ColumnCount++)
|
||||||
|
if(fDisplayList->ItemAt(ColumnCount) == fColumnClicked)
|
||||||
|
{
|
||||||
|
fDragGroup = GroupCounter;
|
||||||
|
fTheDragGroup = ThisGroup;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(fDragGroup != -1)
|
||||||
|
break;
|
||||||
|
else if(ThisGroup->Shown)
|
||||||
|
{
|
||||||
|
fTheShownGroupBefore = ThisGroup;
|
||||||
|
fSnapGroupBefore = GroupCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find the position of shown group after the one that the user is dragging
|
||||||
|
fTheShownGroupAfter = NULL;
|
||||||
|
fSnapGroupAfter = -1;
|
||||||
|
for(GroupCounter = fDragGroup+1; GroupCounter < NumberOfGroups; GroupCounter++)
|
||||||
|
{
|
||||||
|
ThisGroup = (CLVDragGroup*)fDragGroups.ItemAt(GroupCounter);
|
||||||
|
if(ThisGroup->Shown)
|
||||||
|
{
|
||||||
|
fTheShownGroupAfter = ThisGroup;
|
||||||
|
fSnapGroupAfter = GroupCounter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//See if it can actually snap in the given direction
|
||||||
|
if(fSnapGroupBefore != -1)
|
||||||
|
{
|
||||||
|
if(fTheShownGroupBefore->Flags & CLV_LOCK_AT_BEGINNING)
|
||||||
|
if(!fTheDragGroup->AllLockBeginning)
|
||||||
|
fSnapGroupBefore = -1;
|
||||||
|
if(fTheDragGroup->Flags & CLV_LOCK_AT_END)
|
||||||
|
if(!fTheShownGroupBefore->AllLockEnd)
|
||||||
|
fSnapGroupBefore = -1;
|
||||||
|
}
|
||||||
|
if(fSnapGroupAfter != -1)
|
||||||
|
{
|
||||||
|
if(fTheShownGroupAfter->Flags & CLV_LOCK_AT_END)
|
||||||
|
if(!fTheDragGroup->AllLockEnd)
|
||||||
|
fSnapGroupAfter = -1;
|
||||||
|
if(fTheDragGroup->Flags & CLV_LOCK_AT_BEGINNING)
|
||||||
|
if(!fTheShownGroupAfter->AllLockBeginning)
|
||||||
|
fSnapGroupAfter = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find the minumum and maximum positions for the group to snap
|
||||||
|
fSnapMin = -1.0;
|
||||||
|
fSnapMax = -1.0;
|
||||||
|
fDragBoxWidth = fTheDragGroup->GroupEnd-fTheDragGroup->GroupBegin;
|
||||||
|
if(fSnapGroupBefore != -1)
|
||||||
|
{
|
||||||
|
fSnapMin = fTheShownGroupBefore->GroupBegin + fDragBoxWidth;
|
||||||
|
if(fSnapMin > fTheShownGroupBefore->GroupEnd)
|
||||||
|
fSnapMin = fTheShownGroupBefore->GroupEnd;
|
||||||
|
}
|
||||||
|
if(fSnapGroupAfter != -1)
|
||||||
|
{
|
||||||
|
fSnapMax = fTheShownGroupAfter->GroupEnd - fDragBoxWidth;
|
||||||
|
if(fSnapMax < fTheShownGroupAfter->GroupBegin)
|
||||||
|
fSnapMax = fTheShownGroupAfter->GroupBegin;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#ifndef CLVColumnLabelView_h
|
||||||
|
#define CLVColumnLabelView_h
|
||||||
|
|
||||||
|
#include <support/SupportDefs.h>
|
||||||
|
#include <InterfaceKit.h>
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES AND CLASS NAME DECLARATIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
class ColumnListView;
|
||||||
|
class CLVColumn;
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CLASS AND STRUCTURE DECLARATIONS, ASSOCIATED CONSTANTS AND STATIC FUNCTIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
struct CLVDragGroup
|
||||||
|
{
|
||||||
|
int32 GroupStartDispListIndex; //Indices in the column display list where this group starts
|
||||||
|
int32 GroupStopDispListIndex; //and finishes
|
||||||
|
float GroupBegin,GroupEnd; //-1.0 if whole group is hidden
|
||||||
|
CLVColumn* LastColumnShown;
|
||||||
|
bool AllLockBeginning;
|
||||||
|
bool AllLockEnd;
|
||||||
|
bool Shown; //False if none of the columns in this group are shown
|
||||||
|
uint32 Flags; //Uses CLV_NOT_MOVABLE, CLV_LOCK_AT_BEGINNING, CLV_LOCK_AT_END
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CLVColumnLabelView : public BView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Constructor and destructor
|
||||||
|
CLVColumnLabelView(BRect Bounds,ColumnListView* Parent,const BFont* Font);
|
||||||
|
~CLVColumnLabelView();
|
||||||
|
|
||||||
|
//BView overrides
|
||||||
|
void Draw(BRect UpdateRect);
|
||||||
|
void MouseDown(BPoint Point);
|
||||||
|
void MessageReceived(BMessage *message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ColumnListView;
|
||||||
|
friend class CLVColumn;
|
||||||
|
|
||||||
|
float fFontAscent;
|
||||||
|
BList* fDisplayList;
|
||||||
|
|
||||||
|
//Column select and drag stuff
|
||||||
|
CLVColumn* fColumnClicked;
|
||||||
|
BPoint fPreviousMousePos;
|
||||||
|
BPoint fMouseClickedPos;
|
||||||
|
bool fColumnDragging;
|
||||||
|
bool fColumnResizing;
|
||||||
|
BList fDragGroups; //Groups of CLVColumns that must drag together
|
||||||
|
int32 fDragGroup; //Index into DragGroups of the group being dragged by user
|
||||||
|
CLVDragGroup* fTheDragGroup;
|
||||||
|
CLVDragGroup* fTheShownGroupBefore;
|
||||||
|
CLVDragGroup* fTheShownGroupAfter;
|
||||||
|
int32 fSnapGroupBefore, //Index into DragGroups of TheShownGroupBefore and
|
||||||
|
fSnapGroupAfter; //TheShownGroupAfter, if the group the user is dragging is
|
||||||
|
//allowed to snap there, otherwise -1
|
||||||
|
float fDragBoxMouseHoldOffset,fResizeMouseHoldOffset;
|
||||||
|
float fDragBoxWidth; //Can include multiple columns; depends on CLV_LOCK_WITH_RIGHT
|
||||||
|
float fPrevDragOutlineLeft,fPrevDragOutlineRight;
|
||||||
|
float fSnapMin,fSnapMax; //-1.0 indicates the column can't snap in the given direction
|
||||||
|
ColumnListView* fParent;
|
||||||
|
|
||||||
|
//Private functions
|
||||||
|
void ShiftDragGroup(int32 NewPos);
|
||||||
|
void UpdateDragGroups();
|
||||||
|
void SetSnapMinMax();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
//CLVListItem source file
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES
|
||||||
|
//******************************************************************************************************
|
||||||
|
#define CLVListItem_CPP
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "CLVListItem.h"
|
||||||
|
#include "ColumnListView.h"
|
||||||
|
#include "CLVColumn.h"
|
||||||
|
#include "PrefilledBitmap.h"
|
||||||
|
|
||||||
|
#include "InterfaceKit.h"
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CLVItem CLASS DEFINITION
|
||||||
|
//******************************************************************************************************
|
||||||
|
CLVListItem::CLVListItem(uint32 level, bool superitem, bool expanded, float minheight)
|
||||||
|
: BListItem(level, expanded),
|
||||||
|
fExpanderButtonRect(-1.0,-1.0,-1.0,-1.0),
|
||||||
|
fExpanderColumnRect(-1.0,-1.0,-1.0,-1.0),
|
||||||
|
_selectedColumn(-1)
|
||||||
|
{
|
||||||
|
fSuperItem = superitem;
|
||||||
|
fOutlineLevel = level;
|
||||||
|
fMinHeight = minheight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLVListItem::~CLVListItem()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
bool CLVListItem::IsSuperItem() const
|
||||||
|
{
|
||||||
|
return fSuperItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVListItem::SetSuperItem(bool superitem)
|
||||||
|
{
|
||||||
|
fSuperItem = superitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32 CLVListItem::OutlineLevel() const
|
||||||
|
{
|
||||||
|
return fOutlineLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLVListItem::SetOutlineLevel(uint32 level)
|
||||||
|
{
|
||||||
|
fOutlineLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLVListItem::Pulse(BView * owner)
|
||||||
|
{
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLVListItem::DrawItem(BView* owner, BRect itemRect, bool complete)
|
||||||
|
{
|
||||||
|
BList* DisplayList = &((ColumnListView*)owner)->fColumnDisplayList;
|
||||||
|
int32 NumberOfColumns = DisplayList->CountItems();
|
||||||
|
float PushMax = itemRect.right;
|
||||||
|
CLVColumn* ThisColumn;
|
||||||
|
BRect ThisColumnRect = itemRect;
|
||||||
|
float ExpanderDelta = OutlineLevel() * 20.0;
|
||||||
|
//Figure out what the limit is for expanders pushing other columns
|
||||||
|
for(int32 Counter = 0; Counter < NumberOfColumns; Counter++)
|
||||||
|
{
|
||||||
|
ThisColumn = (CLVColumn*)DisplayList->ItemAt(Counter);
|
||||||
|
if((ThisColumn->fFlags & CLV_EXPANDER) || ThisColumn->fPushedByExpander)
|
||||||
|
PushMax = ThisColumn->fColumnEnd;
|
||||||
|
}
|
||||||
|
BRegion ClippingRegion;
|
||||||
|
if(!complete)
|
||||||
|
owner->GetClippingRegion(&ClippingRegion);
|
||||||
|
else
|
||||||
|
ClippingRegion.Set(itemRect);
|
||||||
|
float LastColumnEnd = -1.0;
|
||||||
|
|
||||||
|
//Draw the columns
|
||||||
|
for(int32 Counter = 0; Counter < NumberOfColumns; Counter++)
|
||||||
|
{
|
||||||
|
ThisColumn = (CLVColumn*)DisplayList->ItemAt(Counter);
|
||||||
|
if(!ThisColumn->IsShown())
|
||||||
|
continue;
|
||||||
|
ThisColumnRect.left = ThisColumn->fColumnBegin;
|
||||||
|
ThisColumnRect.right = LastColumnEnd = ThisColumn->fColumnEnd;
|
||||||
|
float Shift = 0.0;
|
||||||
|
if((ThisColumn->fFlags & CLV_EXPANDER) || ThisColumn->fPushedByExpander)
|
||||||
|
Shift = ExpanderDelta;
|
||||||
|
if(ThisColumn->fFlags & CLV_EXPANDER)
|
||||||
|
{
|
||||||
|
ThisColumnRect.right += Shift;
|
||||||
|
if(ThisColumnRect.right > PushMax)
|
||||||
|
ThisColumnRect.right = PushMax;
|
||||||
|
fExpanderColumnRect = ThisColumnRect;
|
||||||
|
if(ClippingRegion.Intersects(ThisColumnRect))
|
||||||
|
{
|
||||||
|
//Give the programmer a chance to do his kind of highlighting if the item is selected
|
||||||
|
int32 actualIndex = ((ColumnListView*)owner)->fColumnList.IndexOf(ThisColumn);
|
||||||
|
DrawItemColumn(owner, ThisColumnRect, actualIndex, (_selectedColumn == actualIndex), complete);
|
||||||
|
if(fSuperItem)
|
||||||
|
{
|
||||||
|
//Draw the expander, clip manually
|
||||||
|
float TopOffset = ceil((ThisColumnRect.bottom-ThisColumnRect.top-10.0)/2.0);
|
||||||
|
float LeftOffset = ThisColumn->fColumnEnd + Shift - 3.0 - 10.0;
|
||||||
|
float RightClip = LeftOffset + 10.0 - ThisColumnRect.right;
|
||||||
|
if(RightClip < 0.0)
|
||||||
|
RightClip = 0.0;
|
||||||
|
BBitmap* Arrow;
|
||||||
|
if(IsExpanded())
|
||||||
|
Arrow = &((ColumnListView*)owner)->fDownArrow;
|
||||||
|
else
|
||||||
|
Arrow = &((ColumnListView*)owner)->fRightArrow;
|
||||||
|
if(LeftOffset <= ThisColumnRect.right)
|
||||||
|
{
|
||||||
|
fExpanderButtonRect.Set(LeftOffset,ThisColumnRect.top+TopOffset,
|
||||||
|
LeftOffset+10.0-RightClip,ThisColumnRect.top+TopOffset+10.0);
|
||||||
|
owner->SetDrawingMode(B_OP_OVER);
|
||||||
|
owner->DrawBitmap(Arrow, BRect(0.0,0.0,10.0-RightClip,10.0),fExpanderButtonRect);
|
||||||
|
owner->SetDrawingMode(B_OP_COPY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fExpanderButtonRect.Set(-1.0,-1.0,-1.0,-1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThisColumnRect.left += Shift;
|
||||||
|
ThisColumnRect.right += Shift;
|
||||||
|
if(Shift > 0.0 && ThisColumnRect.right > PushMax)
|
||||||
|
ThisColumnRect.right = PushMax;
|
||||||
|
if(ThisColumnRect.right >= ThisColumnRect.left && ClippingRegion.Intersects(ThisColumnRect))
|
||||||
|
{
|
||||||
|
int32 actualIndex = ((ColumnListView*)owner)->fColumnList.IndexOf(ThisColumn);
|
||||||
|
DrawItemColumn(owner, ThisColumnRect, actualIndex, (_selectedColumn == actualIndex), complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Fill the area after all the columns (so the select highlight goes all the way across)
|
||||||
|
ThisColumnRect.left = LastColumnEnd + 1.0;
|
||||||
|
ThisColumnRect.right = owner->Bounds().right;
|
||||||
|
if(ThisColumnRect.left <= ThisColumnRect.right && ClippingRegion.Intersects(ThisColumnRect))
|
||||||
|
{
|
||||||
|
DrawItemColumn(owner, ThisColumnRect,-1, false, complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float CLVListItem::ExpanderShift(int32 column_index, BView* owner)
|
||||||
|
{
|
||||||
|
BList* DisplayList = &((ColumnListView*)owner)->fColumnDisplayList;
|
||||||
|
CLVColumn* ThisColumn = (CLVColumn*)DisplayList->ItemAt(column_index);
|
||||||
|
float ExpanderDelta = OutlineLevel() * 20.0;
|
||||||
|
if(!ThisColumn->fPushedByExpander)
|
||||||
|
ExpanderDelta = 0.0;
|
||||||
|
return ExpanderDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CLVListItem::Update(BView* owner, const BFont* font)
|
||||||
|
{
|
||||||
|
BListItem::Update(owner,font);
|
||||||
|
float ItemHeight = Height();
|
||||||
|
if(ItemHeight < fMinHeight)
|
||||||
|
ItemHeight = fMinHeight;
|
||||||
|
SetWidth(((ColumnListView*)owner)->fPageWidth);
|
||||||
|
SetHeight(ItemHeight);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef CLVListItem_h
|
||||||
|
#define CLVListItem_h
|
||||||
|
|
||||||
|
#include <interface/ListItem.h>
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES AND CLASS NAME DECLARATIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
class ColumnListView;
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CLVItem CLASS DECLARATION
|
||||||
|
//******************************************************************************************************
|
||||||
|
class CLVListItem : public BListItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Constructor and destructor
|
||||||
|
CLVListItem(uint32 level = 0, bool superitem = false, bool expanded = false, float minheight = 0.0);
|
||||||
|
virtual ~CLVListItem();
|
||||||
|
|
||||||
|
//Archival stuff
|
||||||
|
/* Not implemented yet
|
||||||
|
CLVItem(BMessage* archive);
|
||||||
|
static CLVItem* Instantiate(BMessage* data);
|
||||||
|
virtual status_t Archive(BMessage* data, bool deep = true) const;
|
||||||
|
*/
|
||||||
|
|
||||||
|
virtual void DrawItemColumn(BView* owner, BRect item_column_rect, int32 column_index, bool columnSelected,
|
||||||
|
bool complete) = 0; //column_index (0-N) is based on the order in which the columns were added
|
||||||
|
//to the ColumnListView, not the display order. An index of -1 indicates
|
||||||
|
//that the program needs to draw a blank area beyond the last column. The
|
||||||
|
//main purpose is to allow the highlighting bar to continue all the way to
|
||||||
|
//the end of the ColumnListView, even after the end of the last column.
|
||||||
|
|
||||||
|
virtual void DrawItem(BView* owner, BRect itemRect, bool complete);
|
||||||
|
//In general, you don't need or want to override DrawItem().
|
||||||
|
float ExpanderShift(int32 column_index, BView* owner);
|
||||||
|
virtual void Update(BView* owner, const BFont* font);
|
||||||
|
bool IsSuperItem() const;
|
||||||
|
void SetSuperItem(bool superitem);
|
||||||
|
uint32 OutlineLevel() const;
|
||||||
|
void SetOutlineLevel(uint32 level);
|
||||||
|
|
||||||
|
virtual void Pulse(BView * owner); // Called periodically when this item is selected.
|
||||||
|
|
||||||
|
int32 GetSelectedColumn() const {return _selectedColumn;}
|
||||||
|
void SetSelectedColumn(int32 i) {_selectedColumn = i;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ColumnListView;
|
||||||
|
|
||||||
|
bool fSuperItem;
|
||||||
|
uint32 fOutlineLevel;
|
||||||
|
float fMinHeight;
|
||||||
|
BRect fExpanderButtonRect;
|
||||||
|
BRect fExpanderColumnRect;
|
||||||
|
BList* fSortingContextBList;
|
||||||
|
ColumnListView* fSortingContextCLV;
|
||||||
|
int32 _selectedColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef JColors_h
|
||||||
|
#define JColors_h
|
||||||
|
|
||||||
|
//Useful until be gets around to making these sorts of things
|
||||||
|
//globals akin to be_plain_font, etc.
|
||||||
|
#include <interface/ColorControl.h>
|
||||||
|
|
||||||
|
//Be standard UI colors
|
||||||
|
const rgb_color BeBackgroundGrey = {216,216,216, 255};
|
||||||
|
const rgb_color BeInactiveControlGrey = {240,240,240, 255};
|
||||||
|
const rgb_color BeFocusBlue = {0, 0, 229, 255};
|
||||||
|
const rgb_color BeHighlight = {255,255,255, 255};
|
||||||
|
const rgb_color BeShadow = {152,152,152, 255};
|
||||||
|
const rgb_color BeDarkShadow = {108,108,108, 255};
|
||||||
|
const rgb_color BeLightShadow = {194,194,194, 255};
|
||||||
|
const rgb_color BeButtonGrey = {232,232,232, 255};
|
||||||
|
const rgb_color BeInactiveGrey = {127,127,127, 255};
|
||||||
|
const rgb_color BeListSelectGrey = {178,178,178, 255};
|
||||||
|
const rgb_color BeTitleBarYellow = {255,203,0, 255};
|
||||||
|
|
||||||
|
//Other colors
|
||||||
|
const rgb_color Black = {0, 0, 0, 255};
|
||||||
|
const rgb_color White = {255,255,255, 255};
|
||||||
|
const rgb_color Red = {255,0, 0, 255};
|
||||||
|
const rgb_color Green = {0, 167,0, 255};
|
||||||
|
const rgb_color LightGreen = {90, 240,90, 255};
|
||||||
|
const rgb_color Blue = {49, 61, 225, 255};
|
||||||
|
const rgb_color LightBlue = {64, 162,255, 255};
|
||||||
|
const rgb_color Purple = {144,64, 221, 255};
|
||||||
|
const rgb_color LightPurple = {166,74, 255, 255};
|
||||||
|
const rgb_color Lavender = {193,122,255, 255};
|
||||||
|
const rgb_color Yellow = {255,203,0, 255};
|
||||||
|
const rgb_color Orange = {255,163,0, 255};
|
||||||
|
const rgb_color Flesh = {255,231,186, 255};
|
||||||
|
const rgb_color Tan = {208,182,121, 255};
|
||||||
|
const rgb_color Brown = {154,110,45, 255};
|
||||||
|
const rgb_color LightMetallicBlue = {143,166,240, 255};
|
||||||
|
const rgb_color MedMetallicBlue = {75, 96, 154, 255};
|
||||||
|
const rgb_color DarkMetallicBlue = {78, 89, 126, 255};
|
||||||
|
|
||||||
|
const rgb_color ReallyLightPurple = {255,210,255, 255};
|
||||||
|
const rgb_color LightYellow = {255,255,210, 255};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,201 @@
|
|||||||
|
#ifndef ColumnListView_h
|
||||||
|
#define ColumnListView_h
|
||||||
|
|
||||||
|
//Column list view header file
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** PROJECT HEADER FILES AND CLASS NAME DECLARATIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
|
||||||
|
#include <interface/ListView.h>
|
||||||
|
|
||||||
|
#include "Colors.h"
|
||||||
|
#include "CLVColumn.h"
|
||||||
|
class CLVListItem;
|
||||||
|
class CLVColumnLabelView;
|
||||||
|
class CLVFillerView;
|
||||||
|
class CLVContainerView;
|
||||||
|
#include "PrefilledBitmap.h"
|
||||||
|
#include "ScrollViewCorner.h"
|
||||||
|
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** CONSTANTS AND TYPE DEFINITIONS
|
||||||
|
//******************************************************************************************************
|
||||||
|
typedef int (*CLVCompareFuncPtr)(const CLVListItem* item1, const CLVListItem* item2, int32 sort_key);
|
||||||
|
|
||||||
|
//******************************************************************************************************
|
||||||
|
//**** ColumnListView CLASS DECLARATION
|
||||||
|
//******************************************************************************************************
|
||||||
|
class ColumnListView : public BListView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//Constructor and destructor
|
||||||
|
ColumnListView( BRect Frame,
|
||||||
|
BScrollView** ContainerView, //Used to get back a pointer to the container
|
||||||
|
//view that will hold the ColumnListView, the
|
||||||
|
//the CLVColumnLabelView, and the scrollbars.
|
||||||
|
//If no scroll bars or border are asked for,
|
||||||
|
//this will act like a plain BView container.
|
||||||
|
const char* Name = NULL,
|
||||||
|
uint32 ResizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
||||||
|
uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE,
|
||||||
|
list_view_type Type = B_SINGLE_SELECTION_LIST,
|
||||||
|
bool hierarchical = false,
|
||||||
|
bool horizontal = true, //Which scroll bars should I add, if any
|
||||||
|
bool vertical = true,
|
||||||
|
border_style border = B_NO_BORDER, //What type of border to add, if any
|
||||||
|
const BFont* LabelFont = be_plain_font);
|
||||||
|
virtual ~ColumnListView();
|
||||||
|
void AddScrollViewCorner();
|
||||||
|
|
||||||
|
//Archival stuff
|
||||||
|
/*** Not implemented yet
|
||||||
|
ColumnListView(BMessage* archive);
|
||||||
|
static ColumnListView* Instantiate(BMessage* data);
|
||||||
|
virtual status_t Archive(BMessage* data, bool deep = true) const;
|
||||||
|
***/
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage * msg);
|
||||||
|
|
||||||
|
//Column setup functions
|
||||||
|
virtual bool AddColumn(CLVColumn* Column); //Note that a column may only be added to
|
||||||
|
//one ColumnListView at a time, and may not
|
||||||
|
//be added more than once to the same
|
||||||
|
//ColumnListView without removing it
|
||||||
|
//inbetween
|
||||||
|
virtual bool AddColumnList(BList* NewColumns);
|
||||||
|
virtual bool RemoveColumn(CLVColumn* Column);
|
||||||
|
virtual bool RemoveColumns(CLVColumn* Column, int32 Count); //Finds Column in ColumnList
|
||||||
|
//and removes Count columns and
|
||||||
|
//their data from the view
|
||||||
|
//and its items
|
||||||
|
int32 CountColumns() const;
|
||||||
|
int32 IndexOfColumn(CLVColumn* column) const;
|
||||||
|
CLVColumn * ColumnAt(BPoint point) const; // Returns column located at point on screen --added by jaf
|
||||||
|
CLVColumn* ColumnAt(int32 column_index) const;
|
||||||
|
virtual bool SetDisplayOrder(const int32* Order);
|
||||||
|
//Sets the display order: each int32 in the Order list specifies the column index of the
|
||||||
|
//next column to display. Note that this DOES NOT get called if the user drags a
|
||||||
|
//column, so overriding it will not inform you of user changes. If you need that info,
|
||||||
|
//override DisplayOrderChanged instead. Also note that SetDisplayOrder does call
|
||||||
|
//DisplayOrderChanged(false).
|
||||||
|
virtual void ColumnWidthChanged(int32 ColumnIndex, float NewWidth);
|
||||||
|
virtual void DisplayOrderChanged(const int32* order);
|
||||||
|
//Override this if you want to find out when the display order changed.
|
||||||
|
int32* DisplayOrder() const; //Gets the display order in the same format as that used by
|
||||||
|
//SetDisplayOrder. The returned array belongs to the caller and
|
||||||
|
//must be delete[]'d when done with it.
|
||||||
|
virtual void SetSortKey(int32 ColumnIndex);
|
||||||
|
//Set it to -1 to remove the sort key.
|
||||||
|
virtual void AddSortKey(int32 ColumnIndex);
|
||||||
|
void ReverseSortMode(int32 ColumnIndex);
|
||||||
|
virtual void SetSortMode(int32 ColumnIndex,CLVSortMode Mode);
|
||||||
|
int32 Sorting(int32* SortKeys, CLVSortMode* SortModes) const;
|
||||||
|
//Returns the number of used sort keys, and fills the provided arrays with the sort keys
|
||||||
|
//by column index and sort modes, in priority order. The pointers should point to an array
|
||||||
|
//int32 SortKeys[n], and an array CLVSortMode SortModes[n] where n is the number of sortable
|
||||||
|
//columns in the ColumnListView. Note: sorting will only occur if the key column is shown.
|
||||||
|
void SetSorting(int32 NumberOfKeys, int32* SortKeys, CLVSortMode* SortModes);
|
||||||
|
//Sets the sorting parameters using the same format returned by Sorting
|
||||||
|
|
||||||
|
//BView overrides
|
||||||
|
virtual void FrameResized(float Width, float Height);
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void ScrollTo(BPoint point);
|
||||||
|
virtual void MouseDown(BPoint point);
|
||||||
|
|
||||||
|
//List functions
|
||||||
|
virtual bool AddUnder(CLVListItem*, CLVListItem* superitem);
|
||||||
|
virtual bool AddItem(CLVListItem*, int32 fullListIndex);
|
||||||
|
virtual bool AddItem(CLVListItem*);
|
||||||
|
virtual bool AddList(BList* newItems); //This must be a BList of
|
||||||
|
//CLVListItem*'s, NOT BListItem*'s
|
||||||
|
virtual bool AddList(BList* newItems, int32 fullListIndex); //This must be a BList of
|
||||||
|
//CLVListItem*'s, NOT BListItem*'s
|
||||||
|
virtual bool RemoveItem(CLVListItem* item);
|
||||||
|
virtual BListItem* RemoveItem(int32 fullListIndex); //Actually returns CLVListItem
|
||||||
|
virtual bool RemoveItems(int32 fullListIndex, int32 count);
|
||||||
|
virtual void MakeEmpty();
|
||||||
|
CLVListItem* FullListItemAt(int32 fullListIndex) const;
|
||||||
|
int32 FullListIndexOf(const CLVListItem* item) const;
|
||||||
|
int32 FullListIndexOf(BPoint point) const;
|
||||||
|
CLVListItem* FullListFirstItem() const;
|
||||||
|
CLVListItem* FullListLastItem() const;
|
||||||
|
bool FullListHasItem(const CLVListItem* item) const;
|
||||||
|
int32 FullListCountItems() const;
|
||||||
|
bool FullListIsEmpty() const;
|
||||||
|
int32 FullListCurrentSelection(int32 index = 0) const;
|
||||||
|
void FullListDoForEach(bool (*func)(CLVListItem*));
|
||||||
|
void FullListDoForEach(bool (*func)(CLVListItem*, void*), void* arg2);
|
||||||
|
CLVListItem* Superitem(const CLVListItem* item) const;
|
||||||
|
int32 FullListNumberOfSubitems(const CLVListItem* item) const;
|
||||||
|
virtual void Expand(CLVListItem* item);
|
||||||
|
virtual void Collapse(CLVListItem* item);
|
||||||
|
bool IsExpanded(int32 fullListIndex) const;
|
||||||
|
void SetSortFunction(CLVCompareFuncPtr compare);
|
||||||
|
void SortItems();
|
||||||
|
|
||||||
|
virtual void KeyDown(const char * bytes, int32 numBytes);
|
||||||
|
|
||||||
|
void SetEditMessage(BMessage * newMsg, BMessenger target);
|
||||||
|
// Sets a BMessage that will be sent every time a key is pressed, or the mouse
|
||||||
|
// is clicked in the active cell. (newMsg) becomes property of this ColumnListView.
|
||||||
|
// Copies of (newMsg) will be sent to (target).
|
||||||
|
|
||||||
|
virtual void Pulse();
|
||||||
|
// Used to make the cursor blink on the string column...
|
||||||
|
|
||||||
|
int32 GetSelectedColumn() const {return _selectedColumn;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class CLVMainView;
|
||||||
|
friend class CLVColumn;
|
||||||
|
friend class CLVColumnLabelView;
|
||||||
|
friend class CLVListItem;
|
||||||
|
|
||||||
|
int32 GetActualIndexOf(int32 displayIndex) const;
|
||||||
|
// Returns the "real" index of the given display index, or -1 if there is none.
|
||||||
|
|
||||||
|
int32 GetDisplayIndexOf(int32 actualIndex) const;
|
||||||
|
// Returns the display index of the given "real" index, or -1 if there is none.
|
||||||
|
|
||||||
|
void SetSelectedColumnIndex(int32 selectedColumnIndex);
|
||||||
|
// Call this to change _selectedColumn to a new value properly.
|
||||||
|
|
||||||
|
void UpdateColumnSizesDataRectSizeScrollBars();
|
||||||
|
void UpdateScrollBars();
|
||||||
|
void ColumnsChanged();
|
||||||
|
void CreateContainer(bool horizontal, bool vertical, border_style border, uint32 ResizingMode,
|
||||||
|
uint32 flags);
|
||||||
|
void SortListArray(CLVListItem** SortArray, int32 NumberOfItems);
|
||||||
|
void MakeEmptyPrivate();
|
||||||
|
bool AddListPrivate(BList* newItems, int32 fullListIndex);
|
||||||
|
bool AddItemPrivate(CLVListItem* item, int32 fullListIndex);
|
||||||
|
void SortFullListSegment(int32 OriginalListStartIndex, int32 InsertionPoint, BList* NewList);
|
||||||
|
BList* SortItemsInThisLevel(int32 OriginalListStartIndex);
|
||||||
|
static int PlainBListSortFunc(BListItem** item1, BListItem** item2);
|
||||||
|
static int HierarchicalBListSortFunc(BListItem** item1, BListItem** item2);
|
||||||
|
|
||||||
|
CLVColumnLabelView* fColumnLabelView;
|
||||||
|
CLVContainerView* fScrollView;
|
||||||
|
ScrollViewCorner* fFillerView;
|
||||||
|
bool fHierarchical;
|
||||||
|
BList fColumnList;
|
||||||
|
BList fColumnDisplayList;
|
||||||
|
float fDataWidth,fDataHeight,fPageWidth,fPageHeight;
|
||||||
|
BList fSortKeyList; //List contains CLVColumn pointers
|
||||||
|
PrefilledBitmap fRightArrow;
|
||||||
|
PrefilledBitmap fDownArrow;
|
||||||
|
BList fFullItemList;
|
||||||
|
int32 fExpanderColumn;
|
||||||
|
CLVCompareFuncPtr fCompare;
|
||||||
|
|
||||||
|
// added by jaf
|
||||||
|
int32 _selectedColumn; // actual index of the column that contains the active cell.
|
||||||
|
BMessage * _editMessage; // if non-NULL, sent on keypress or when active cell is clicked.
|
||||||
|
BMessenger _editTarget; // target for _editMessage.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "MouseWatcher.h"
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <InterfaceKit.h>
|
||||||
|
|
||||||
|
int32 MouseWatcher(void* data);
|
||||||
|
|
||||||
|
|
||||||
|
thread_id StartMouseWatcher(BView* TargetView)
|
||||||
|
{
|
||||||
|
thread_id MouseWatcherThread = spawn_thread(MouseWatcher,"MouseWatcher",B_NORMAL_PRIORITY,
|
||||||
|
new BMessenger(TargetView));
|
||||||
|
if(MouseWatcherThread != B_NO_MORE_THREADS && MouseWatcherThread != B_NO_MEMORY)
|
||||||
|
resume_thread(MouseWatcherThread);
|
||||||
|
return MouseWatcherThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32 MouseWatcher(void* data)
|
||||||
|
{
|
||||||
|
BMessenger* TheMessenger = (BMessenger*)data;
|
||||||
|
BPoint PreviousPos;
|
||||||
|
uint32 PreviousButtons;
|
||||||
|
bool FirstCheck = true;
|
||||||
|
BMessage MessageToSend;
|
||||||
|
MessageToSend.AddPoint("where",BPoint(0,0));
|
||||||
|
MessageToSend.AddInt32("buttons",0);
|
||||||
|
MessageToSend.AddInt32("modifiers",0);
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if (!TheMessenger->LockTarget())
|
||||||
|
{
|
||||||
|
delete TheMessenger;
|
||||||
|
return 0; // window is dead so exit
|
||||||
|
}
|
||||||
|
BLooper *TheLooper;
|
||||||
|
BView* TheView = (BView*)TheMessenger->Target(&TheLooper);
|
||||||
|
BPoint Where;
|
||||||
|
uint32 Buttons;
|
||||||
|
TheView->GetMouse(&Where,&Buttons,false);
|
||||||
|
if(FirstCheck)
|
||||||
|
{
|
||||||
|
PreviousPos = Where;
|
||||||
|
PreviousButtons = Buttons;
|
||||||
|
FirstCheck = false;
|
||||||
|
}
|
||||||
|
bool Send = false;
|
||||||
|
if(Buttons != PreviousButtons || Buttons == 0 || Where != PreviousPos)
|
||||||
|
{
|
||||||
|
if(Buttons == 0)
|
||||||
|
MessageToSend.what = MW_MOUSE_UP;
|
||||||
|
else if(Buttons != PreviousButtons)
|
||||||
|
MessageToSend.what = MW_MOUSE_DOWN;
|
||||||
|
else
|
||||||
|
MessageToSend.what = MW_MOUSE_MOVED;
|
||||||
|
MessageToSend.ReplacePoint("where",Where);
|
||||||
|
MessageToSend.ReplaceInt32("buttons",Buttons);
|
||||||
|
MessageToSend.ReplaceInt32("modifiers",modifiers());
|
||||||
|
Send = true;
|
||||||
|
}
|
||||||
|
TheLooper->Unlock();
|
||||||
|
if(Send)
|
||||||
|
TheMessenger->SendMessage(&MessageToSend);
|
||||||
|
if(Buttons == 0)
|
||||||
|
{
|
||||||
|
//Button was released
|
||||||
|
delete TheMessenger;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
snooze(50000);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/****DOCUMENTATION
|
||||||
|
Once started, MouseWatcher will watch the mouse until the mouse buttons are all released, sending
|
||||||
|
messages to the target BView (TargetView is specified as the target handler in the BMessenger used to
|
||||||
|
send the messages. The BLooper == window of the target view is determined automatically by the
|
||||||
|
BMessenger)
|
||||||
|
|
||||||
|
If the mouse moves, a MW_MOUSE_MOVED message is sent.
|
||||||
|
If the mouse buttons are changed, but not released, a MW_MOUSE_DOWN message is sent.
|
||||||
|
If the mouse button(s) are released, a MW_MOUSE_UP message is sent.
|
||||||
|
|
||||||
|
These messages will have three data entries:
|
||||||
|
|
||||||
|
"where" (B_POINT_TYPE) - The position of the mouse in TargetView's coordinate system.
|
||||||
|
"buttons" (B_INT32_TYPE) - The mouse buttons. See BView::GetMouse().
|
||||||
|
"modifiers" (B_INT32_TYPE) - The modifier keys held down at the time. See modifiers().
|
||||||
|
|
||||||
|
Once it is started, you can't stop it, but that shouldn't matter - the user will most likely release
|
||||||
|
the buttons soon, and you can interpret the events however you want.
|
||||||
|
|
||||||
|
StartMouseWatcher returns a valid thread ID, or it returns an error code:
|
||||||
|
B_NO_MORE_THREADS. all thread_id numbers are currently in use.
|
||||||
|
B_NO_MEMORY. Not enough memory to allocate the resources for another thread.
|
||||||
|
****/
|
||||||
|
#ifndef MouseWatcher_h
|
||||||
|
#define MouseWatcher_h
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
class BView;
|
||||||
|
|
||||||
|
const uint32 MW_MOUSE_DOWN = 'Mw-D';
|
||||||
|
const uint32 MW_MOUSE_UP = 'Mw-U';
|
||||||
|
const uint32 MW_MOUSE_MOVED = 'Mw-M';
|
||||||
|
|
||||||
|
thread_id StartMouseWatcher(BView* TargetView);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "PrefilledBitmap.h"
|
||||||
|
|
||||||
|
PrefilledBitmap::PrefilledBitmap(BRect bounds, color_space space, const void *data, bool acceptsViews,
|
||||||
|
bool needsContiguousMemory)
|
||||||
|
: BBitmap(bounds, space, acceptsViews, needsContiguousMemory)
|
||||||
|
{
|
||||||
|
int32 length = ((int32(bounds.right-bounds.left)+3) / 4) * 4;
|
||||||
|
length *= int32(bounds.bottom-bounds.top)+1;
|
||||||
|
SetBits(data, length, 0, space);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PrefilledBitmap::~PrefilledBitmap()
|
||||||
|
{ }
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef PreFilledBitmap_h
|
||||||
|
#define PreFilledBitmap_h
|
||||||
|
|
||||||
|
#include <interface/Bitmap.h>
|
||||||
|
|
||||||
|
//Useful until be implements BBitmap::BBitmap(BRect bounds, color_space space, const void *data,
|
||||||
|
// bool acceptsViews, bool needsContiguousMemory)
|
||||||
|
//or something like it...
|
||||||
|
|
||||||
|
class PrefilledBitmap : public BBitmap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrefilledBitmap(BRect bounds, color_space space, const void *data, bool acceptsViews,
|
||||||
|
bool needsContiguousMemory);
|
||||||
|
~PrefilledBitmap();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#include "Colors.h"
|
||||||
|
#include "ScrollViewCorner.h"
|
||||||
|
|
||||||
|
#include <InterfaceKit.h>
|
||||||
|
|
||||||
|
ScrollViewCorner::ScrollViewCorner(float Left,float Top)
|
||||||
|
: BView(BRect(Left,Top,Left+B_V_SCROLL_BAR_WIDTH,Top+B_H_SCROLL_BAR_HEIGHT),NULL,B_FOLLOW_RIGHT |
|
||||||
|
B_FOLLOW_BOTTOM,B_WILL_DRAW)
|
||||||
|
{
|
||||||
|
SetHighColor(BeShadow);
|
||||||
|
SetViewColor(BeInactiveGrey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ScrollViewCorner::~ScrollViewCorner()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
void ScrollViewCorner::Draw(BRect Update)
|
||||||
|
{
|
||||||
|
if(Update.bottom >= B_H_SCROLL_BAR_HEIGHT)
|
||||||
|
StrokeLine(BPoint(0.0,B_H_SCROLL_BAR_HEIGHT),BPoint(B_V_SCROLL_BAR_WIDTH,B_H_SCROLL_BAR_HEIGHT));
|
||||||
|
if(Update.right >= B_V_SCROLL_BAR_WIDTH)
|
||||||
|
StrokeLine(BPoint(B_V_SCROLL_BAR_WIDTH,0.0),
|
||||||
|
BPoint(B_V_SCROLL_BAR_WIDTH,B_H_SCROLL_BAR_HEIGHT-1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef ScrollViewCorner_h
|
||||||
|
#define ScrollViewCorner_h
|
||||||
|
|
||||||
|
//If you have a BScrollView with horizontal and vertical sliders that isn't
|
||||||
|
//seated to the lower-right corner of a B_DOCUMENT_WINDOW, there's a "hole"
|
||||||
|
//between the sliders that needs to be filled. You can use this to fill it.
|
||||||
|
//In general, it looks best to set the ScrollViewCorner color to
|
||||||
|
//BeInactiveControlGrey if the vertical BScrollBar is inactive, and the color
|
||||||
|
//to BeBackgroundGrey if the vertical BScrollBar is active. Have a look at
|
||||||
|
//Demo3 of ColumnListView to see what I mean if this is unclear.
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollViewCorner : public BView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScrollViewCorner(float Left,float Top);
|
||||||
|
~ScrollViewCorner();
|
||||||
|
void Draw(BRect Update);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2009 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Jeremy Friesner
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ShortcutsApp.h"
|
||||||
|
#include "KeyInfos.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
InitKeyIndices();
|
||||||
|
(new ShortcutsApp)->Run();
|
||||||
|
delete be_app;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user