the first steps towards Icon-O-Matic
* added a framework with many classes that I think will be useful * currently, the StateView and Manipulator interface are used to allow editing a single VectorPath object, nothing more... the CommandStack framework is also used to support Undo/Redo git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17822 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,6 +13,7 @@ SubInclude HAIKU_TOP src apps diskprobe ;
|
||||
SubInclude HAIKU_TOP src apps expander ;
|
||||
SubInclude HAIKU_TOP src apps fontdemo ;
|
||||
SubInclude HAIKU_TOP src apps glteapot ;
|
||||
SubInclude HAIKU_TOP src apps icon-o-matic ;
|
||||
SubInclude HAIKU_TOP src apps installer ;
|
||||
SubInclude HAIKU_TOP src apps magnify ;
|
||||
SubInclude HAIKU_TOP src apps mediaplayer ;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "CanvasView.h"
|
||||
|
||||
#include "CommandStack.h"
|
||||
|
||||
CanvasView::CanvasView(BRect frame)
|
||||
: StateView(frame, "canvas view", B_FOLLOW_ALL, B_WILL_DRAW)
|
||||
{
|
||||
#if __HAIKU__
|
||||
SetFlags(Flags() | B_SUBPIXEL_PRECISE);
|
||||
#endif // __HAIKU__
|
||||
}
|
||||
|
||||
|
||||
CanvasView::~CanvasView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CanvasView::_HandleKeyDown(uint32 key, uint32 modifiers)
|
||||
{
|
||||
switch (key) {
|
||||
case 'z':
|
||||
case 'y':
|
||||
if (modifiers & B_SHIFT_KEY)
|
||||
CommandStack()->Redo();
|
||||
else
|
||||
CommandStack()->Undo();
|
||||
break;
|
||||
|
||||
default:
|
||||
return StateView::HandleKeyDown(key, modifiers);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef CANVAS_VIEW_H
|
||||
#define CANVAS_VIEW_H
|
||||
|
||||
#include "StateView.h"
|
||||
|
||||
class CanvasView : public StateView {
|
||||
public:
|
||||
CanvasView(BRect frame);
|
||||
virtual ~CanvasView();
|
||||
|
||||
protected:
|
||||
// StateView interface
|
||||
virtual bool _HandleKeyDown(uint32 key, uint32 modifiers);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // CANVAS_VIEW_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "IconEditorApp.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Document.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
IconEditorApp::IconEditorApp()
|
||||
: BApplication("application/x-vnd.Haiku-Icon-O-Matic"),
|
||||
fMainWindow(NULL),
|
||||
fDocument(new Document("test"))
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
IconEditorApp::~IconEditorApp()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// QuitRequested
|
||||
bool
|
||||
IconEditorApp::QuitRequested()
|
||||
{
|
||||
// TODO: ask main window if quitting is ok
|
||||
fMainWindow->Lock();
|
||||
fMainWindow->Quit();
|
||||
fMainWindow = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
IconEditorApp::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
// case MSG_OPEN:
|
||||
// break;
|
||||
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ReadyToRun
|
||||
void
|
||||
IconEditorApp::ReadyToRun()
|
||||
{
|
||||
fMainWindow = new MainWindow(this, fDocument);
|
||||
fMainWindow->Show();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef ICON_EDITOR_APP_H
|
||||
#define ICON_EDITOR_APP_H
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class Document;
|
||||
class MainWindow;
|
||||
|
||||
class IconEditorApp : public BApplication {
|
||||
public:
|
||||
IconEditorApp();
|
||||
virtual ~IconEditorApp();
|
||||
|
||||
// BApplication interface
|
||||
virtual bool QuitRequested();
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void ReadyToRun();
|
||||
|
||||
// IconEditorApp
|
||||
|
||||
private:
|
||||
MainWindow* fMainWindow;
|
||||
Document* fDocument;
|
||||
};
|
||||
|
||||
#endif // ICON_EDITOR_APP_H
|
||||
@@ -0,0 +1,79 @@
|
||||
SubDir HAIKU_TOP src apps icon-o-matic ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
AddSubDirSupportedPlatforms libbe_test ;
|
||||
|
||||
# source directories
|
||||
local sourceDirs =
|
||||
document
|
||||
generic
|
||||
generic/command
|
||||
generic/gui
|
||||
generic/gui/panel
|
||||
generic/gui/popup_control
|
||||
generic/gui/scrollview
|
||||
generic/gui/stateview
|
||||
generic/listener
|
||||
generic/selection
|
||||
generic/support
|
||||
shape
|
||||
shape/commands
|
||||
;
|
||||
|
||||
local sourceDir ;
|
||||
for sourceDir in $(sourceDirs) {
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps icon-o-matic $(sourceDir) ] ;
|
||||
}
|
||||
|
||||
# system headers
|
||||
UseLibraryHeaders agg ;
|
||||
|
||||
Application Icon-O-Matic :
|
||||
#document
|
||||
Document.cpp
|
||||
#generic/command
|
||||
Command.cpp
|
||||
CommandStack.cpp
|
||||
Selectable.cpp
|
||||
Selection.cpp
|
||||
#generic/gui
|
||||
#generic/gui/panel
|
||||
#generic/gui/popup_control
|
||||
#generic/gui/scrollview
|
||||
#generic/gui/stateview
|
||||
Manipulator.cpp
|
||||
MultipleManipulatorState.cpp
|
||||
StateView.cpp
|
||||
ViewState.cpp
|
||||
#generic/listener
|
||||
Observable.cpp
|
||||
Observer.cpp
|
||||
#generic/selection
|
||||
#generic/support
|
||||
RWLocker.cpp
|
||||
support.cpp
|
||||
#shape
|
||||
PathManipulator.cpp
|
||||
VectorPath.cpp
|
||||
#shape/commands
|
||||
AddPointCommand.cpp
|
||||
ChangePointCommand.cpp
|
||||
InsertPointCommand.cpp
|
||||
PathCommand.cpp
|
||||
RemovePointsCommand.cpp
|
||||
#
|
||||
CanvasView.cpp
|
||||
IconEditorApp.cpp
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
: be libagg.a
|
||||
;
|
||||
|
||||
|
||||
|
||||
# also install in app_server test environment
|
||||
if ( $(TARGET_PLATFORM) = libbe_test ) {
|
||||
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : Icon-O-Matic
|
||||
: tests!apps ;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include "Document.h"
|
||||
#include "CanvasView.h"
|
||||
#include "IconEditorApp.h"
|
||||
|
||||
// TODO: just for testing
|
||||
#include "MultipleManipulatorState.h"
|
||||
#include "PathManipulator.h"
|
||||
#include "VectorPath.h"
|
||||
|
||||
// constructor
|
||||
MainWindow::MainWindow(IconEditorApp* app, Document* document)
|
||||
: BWindow(BRect(50.0, 50.0, 689, 529), "Icon-O-Matic",
|
||||
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS),
|
||||
fApp(app),
|
||||
fDocument(document),
|
||||
fCanvasView(NULL)
|
||||
{
|
||||
_Init();
|
||||
}
|
||||
|
||||
// destructor
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
MainWindow::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
// QuitRequested
|
||||
bool
|
||||
MainWindow::QuitRequested()
|
||||
{
|
||||
// forward this to app but return "false" in order
|
||||
// to have a single code path for quitting
|
||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _Init
|
||||
void
|
||||
MainWindow::_Init()
|
||||
{
|
||||
// create the GUI
|
||||
BView* topView = _CreateGUI(Bounds());
|
||||
AddChild(topView);
|
||||
|
||||
fCanvasView->SetCatchAllEvents(true);
|
||||
fCanvasView->SetCommandStack(fDocument->CommandStack());
|
||||
// fCanvasView->SetSelection(fDocument->Selection());
|
||||
|
||||
// TODO: for testing only:
|
||||
MultipleManipulatorState* state = new MultipleManipulatorState(fCanvasView);
|
||||
fCanvasView->SetState(state);
|
||||
|
||||
VectorPath* path = new VectorPath();
|
||||
PathManipulator* pathManipulator = new PathManipulator(path);
|
||||
state->AddManipulator(pathManipulator);
|
||||
// ----
|
||||
}
|
||||
|
||||
// _CreateGUI
|
||||
BView*
|
||||
MainWindow::_CreateGUI(BRect bounds)
|
||||
{
|
||||
fCanvasView = new CanvasView(bounds);
|
||||
|
||||
return fCanvasView;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef MAIN_WINDOW_H
|
||||
#define MAIN_WINDOW_H
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class CanvasView;
|
||||
class Document;
|
||||
class IconEditorApp;
|
||||
|
||||
class MainWindow : public BWindow {
|
||||
public:
|
||||
MainWindow(IconEditorApp* app,
|
||||
Document* document);
|
||||
virtual ~MainWindow();
|
||||
|
||||
// BWindow interface
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual bool QuitRequested();
|
||||
|
||||
private:
|
||||
void _Init();
|
||||
BView* _CreateGUI(BRect frame);
|
||||
|
||||
IconEditorApp* fApp;
|
||||
Document* fDocument;
|
||||
|
||||
CanvasView* fCanvasView;
|
||||
};
|
||||
|
||||
#endif // MAIN_WINDOW_H
|
||||
@@ -0,0 +1,33 @@
|
||||
--------- random thoughts
|
||||
|
||||
|
||||
* works a bit like WonderBrush
|
||||
|
||||
* list of vector path objects
|
||||
|
||||
* tree of object instances, such that the same vector path
|
||||
object can be visible at different locations with different fill styles
|
||||
|
||||
* instances of paths can have additional vector transformers
|
||||
|
||||
* "add points" mode is problematic when having multiple manipulators for
|
||||
different paths showing at the same time...
|
||||
|
||||
|
||||
--------- icon format
|
||||
|
||||
* 192 "built-in" (pre-defined) style definitions
|
||||
* up to 64 additional style definitions per document
|
||||
* solid colors and different types of gradients
|
||||
* uint8 precision for coordinates on a 64x64 virtual pixel grid
|
||||
(* removal (freezing) of transformations at export time
|
||||
not sure about this one, it would remove the possiblity
|
||||
to store vector path only once for referenced objects)
|
||||
* referencing of fill style by uint8 id
|
||||
* IFF type chunk format
|
||||
|
||||
|
||||
--------- rendering
|
||||
|
||||
* compound shape single pass rendering (if possible)
|
||||
* auto hinting (aligning to pixels) of marked shapes
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Document.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Entry.h>
|
||||
|
||||
#include "CommandStack.h"
|
||||
#include "Selection.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
Document::Document(const char* name)
|
||||
: RWLocker("document rw lock"),
|
||||
fCommandStack(new (nothrow) ::CommandStack()),
|
||||
fSelection(new (nothrow) ::Selection()),
|
||||
|
||||
fRef(NULL)
|
||||
{
|
||||
SetName(name);
|
||||
}
|
||||
|
||||
// destructor
|
||||
Document::~Document()
|
||||
{
|
||||
delete fCommandStack;
|
||||
delete fSelection;
|
||||
delete fRef;
|
||||
}
|
||||
|
||||
// SetName
|
||||
void
|
||||
Document::SetName(const char* name)
|
||||
{
|
||||
fName = name;
|
||||
}
|
||||
|
||||
// Name
|
||||
const char*
|
||||
Document::Name() const
|
||||
{
|
||||
return fName.String();
|
||||
}
|
||||
|
||||
// SetRef
|
||||
void
|
||||
Document::SetRef(const entry_ref& ref)
|
||||
{
|
||||
if (!fRef)
|
||||
fRef = new (nothrow) entry_ref(ref);
|
||||
else
|
||||
*fRef = ref;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef DOCUMENT_H
|
||||
#define DOCUMENT_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "RWLocker.h"
|
||||
|
||||
struct entry_ref;
|
||||
|
||||
class CommandStack;
|
||||
class Selection;
|
||||
|
||||
class Document : public RWLocker {
|
||||
public:
|
||||
Document(const char* name = NULL);
|
||||
virtual ~Document();
|
||||
|
||||
::CommandStack* CommandStack() const
|
||||
{ return fCommandStack; }
|
||||
|
||||
::Selection* Selection() const
|
||||
{ return fSelection; }
|
||||
|
||||
void SetName(const char* name);
|
||||
const char* Name() const;
|
||||
|
||||
void SetRef(const entry_ref& ref);
|
||||
const entry_ref* Ref() const
|
||||
{ return fRef; }
|
||||
|
||||
private:
|
||||
::CommandStack* fCommandStack;
|
||||
::Selection* fSelection;
|
||||
|
||||
BString fName;
|
||||
entry_ref* fRef;
|
||||
};
|
||||
|
||||
#endif // DOCUMENT_H
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
// constructor
|
||||
Command::Command()
|
||||
: fTimeStamp(system_time())
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
Command::InitCheck()
|
||||
{
|
||||
return B_NO_INIT;
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
Command::Perform()
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
Command::Undo()
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
Command::Redo()
|
||||
{
|
||||
return Perform();
|
||||
}
|
||||
|
||||
// GetName
|
||||
void
|
||||
Command::GetName(BString& name)
|
||||
{
|
||||
name << "Name of action goes here.";
|
||||
}
|
||||
|
||||
// CombineWithNext
|
||||
bool
|
||||
Command::CombineWithNext(const Command* next)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// CombineWithPrevious
|
||||
bool
|
||||
Command::CombineWithPrevious(const Command* previous)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// _GetString
|
||||
const char*
|
||||
Command::_GetString(uint32 key, const char* defaultString) const
|
||||
{
|
||||
// if (LanguageManager* manager = LanguageManager::Default())
|
||||
// return manager->GetString(key, defaultString);
|
||||
// else
|
||||
return defaultString;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef COMMAND_H
|
||||
#define COMMAND_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <String.h>
|
||||
|
||||
class BString;
|
||||
|
||||
class Command {
|
||||
public:
|
||||
Command();
|
||||
virtual ~Command();
|
||||
|
||||
virtual status_t InitCheck();
|
||||
|
||||
virtual status_t Perform();
|
||||
virtual status_t Undo();
|
||||
virtual status_t Redo();
|
||||
|
||||
virtual void GetName(BString& name);
|
||||
|
||||
virtual bool CombineWithNext(const Command* next);
|
||||
virtual bool CombineWithPrevious(const Command* previous);
|
||||
|
||||
protected:
|
||||
const char* _GetString(uint32 key,
|
||||
const char* defaultString) const;
|
||||
|
||||
bigtime_t fTimeStamp;
|
||||
};
|
||||
|
||||
#endif // COMMAND_H
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "CommandStack.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Locker.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
// constructor
|
||||
CommandStack::CommandStack()
|
||||
: BLocker("history"),
|
||||
Observable(),
|
||||
fSavedCommand(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
CommandStack::~CommandStack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
CommandStack::Perform(Command* command)
|
||||
{
|
||||
status_t ret = command ? B_OK : B_BAD_VALUE;
|
||||
if (Lock()) {
|
||||
if (ret == B_OK)
|
||||
ret = command->InitCheck();
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = command->Perform();
|
||||
|
||||
if (ret == B_OK)
|
||||
ret = AddCommand(command);
|
||||
|
||||
if (ret != B_OK) {
|
||||
// no one else feels responsible...
|
||||
delete command;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// AddCommand
|
||||
status_t
|
||||
CommandStack::AddCommand(Command* command)
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
if (Lock()) {
|
||||
if (command && (status = command->InitCheck()) == B_OK) {
|
||||
// try to collapse commands to a single command
|
||||
bool add = true;
|
||||
if (!fUndoHistory.empty()) {
|
||||
if (Command* top = fUndoHistory.top()) {
|
||||
if (top->CombineWithNext(command)) {
|
||||
add = false;
|
||||
delete command;
|
||||
} else if (command->CombineWithPrevious(top)) {
|
||||
fUndoHistory.pop();
|
||||
delete top;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
fUndoHistory.push(command);
|
||||
|
||||
// the redo stack needs to be empty
|
||||
// as soon as an command was added (also in case of collapsing)
|
||||
while (!fRedoHistory.empty()) {
|
||||
delete fRedoHistory.top();
|
||||
fRedoHistory.pop();
|
||||
}
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
Notify();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
CommandStack::Undo()
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
if (Lock()) {
|
||||
if (!fUndoHistory.empty()) {
|
||||
Command* command = fUndoHistory.top();
|
||||
fUndoHistory.pop();
|
||||
status = command->Undo();
|
||||
if (status == B_OK)
|
||||
fRedoHistory.push(command);
|
||||
else
|
||||
fUndoHistory.push(command);
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
Notify();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
CommandStack::Redo()
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
if (Lock()) {
|
||||
if (!fRedoHistory.empty()) {
|
||||
Command* command = fRedoHistory.top();
|
||||
fRedoHistory.pop();
|
||||
status = command->Redo();
|
||||
if (status == B_OK)
|
||||
fUndoHistory.push(command);
|
||||
else
|
||||
fRedoHistory.push(command);
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
Notify();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// UndoName
|
||||
bool
|
||||
CommandStack::GetUndoName(BString& name)
|
||||
{
|
||||
bool success = false;
|
||||
if (Lock()) {
|
||||
if (!fUndoHistory.empty()) {
|
||||
name << " ";
|
||||
fUndoHistory.top()->GetName(name);
|
||||
success = true;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// RedoName
|
||||
bool
|
||||
CommandStack::GetRedoName(BString& name)
|
||||
{
|
||||
bool success = false;
|
||||
if (Lock()) {
|
||||
if (!fRedoHistory.empty()) {
|
||||
name << " ";
|
||||
fRedoHistory.top()->GetName(name);
|
||||
success = true;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// Clear
|
||||
void
|
||||
CommandStack::Clear()
|
||||
{
|
||||
if (Lock()) {
|
||||
while (!fUndoHistory.empty()) {
|
||||
delete fUndoHistory.top();
|
||||
fUndoHistory.pop();
|
||||
}
|
||||
while (!fRedoHistory.empty()) {
|
||||
delete fRedoHistory.top();
|
||||
fRedoHistory.pop();
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
|
||||
Notify();
|
||||
}
|
||||
|
||||
// Save
|
||||
void
|
||||
CommandStack::Save()
|
||||
{
|
||||
if (Lock()) {
|
||||
if (!fUndoHistory.empty())
|
||||
fSavedCommand = fUndoHistory.top();
|
||||
Unlock();
|
||||
}
|
||||
|
||||
Notify();
|
||||
}
|
||||
|
||||
// IsSaved
|
||||
bool
|
||||
CommandStack::IsSaved()
|
||||
{
|
||||
bool saved = false;
|
||||
if (Lock()) {
|
||||
saved = fUndoHistory.empty();
|
||||
if (fSavedCommand && !saved) {
|
||||
if (fSavedCommand == fUndoHistory.top())
|
||||
saved = true;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef COMMAND_STACK_H
|
||||
#define COMMAND_STACK_H
|
||||
|
||||
#include <stack.h>
|
||||
|
||||
#include <Locker.h>
|
||||
|
||||
#include "Observable.h"
|
||||
|
||||
class BString;
|
||||
class Command;
|
||||
|
||||
class CommandStack : public BLocker,
|
||||
public Observable {
|
||||
public:
|
||||
CommandStack();
|
||||
virtual ~CommandStack();
|
||||
|
||||
status_t Perform(Command* command);
|
||||
status_t AddCommand(Command* command);
|
||||
|
||||
status_t Undo();
|
||||
status_t Redo();
|
||||
|
||||
bool GetUndoName(BString& name);
|
||||
bool GetRedoName(BString& name);
|
||||
|
||||
void Clear();
|
||||
void Save();
|
||||
bool IsSaved();
|
||||
|
||||
private:
|
||||
|
||||
typedef stack<Command*> command_stack;
|
||||
|
||||
command_stack fUndoHistory;
|
||||
command_stack fRedoHistory;
|
||||
Command* fSavedCommand;
|
||||
};
|
||||
|
||||
#endif // COMMAND_STACK_H
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "CompoundCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// constructor
|
||||
CompoundCommand::CompoundCommand(Command** commands,
|
||||
int32 count,
|
||||
const char* name,
|
||||
int32 nameIndex)
|
||||
: Command(),
|
||||
fCommands(commands),
|
||||
fCount(count),
|
||||
fName(name),
|
||||
fNameIndex(nameIndex)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
CompoundCommand::~CompoundCommand()
|
||||
{
|
||||
for (int32 i = 0; i < fCount; i++)
|
||||
delete fCommands[i];
|
||||
delete[] fCommands;
|
||||
}
|
||||
|
||||
// InitCheck
|
||||
status_t
|
||||
CompoundCommand::InitCheck()
|
||||
{
|
||||
status_t status = fCommands && fCount > 0 ? B_OK : B_BAD_VALUE;
|
||||
return status;
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
CompoundCommand::Perform()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status >= B_OK) {
|
||||
int32 i = 0;
|
||||
for (; i < fCount; i++) {
|
||||
if (fCommands[i])
|
||||
status = fCommands[i]->Perform();
|
||||
if (status < B_OK)
|
||||
break;
|
||||
}
|
||||
/* if (status < B_OK) {
|
||||
// roll back
|
||||
i--;
|
||||
for (; i >= 0; i--) {
|
||||
if (fCommands[i])
|
||||
fCommands[i]->Undo();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
CompoundCommand::Undo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status >= B_OK) {
|
||||
int32 i = fCount - 1;
|
||||
for (; i >= 0; i--) {
|
||||
if (fCommands[i])
|
||||
status = fCommands[i]->Undo();
|
||||
if (status < B_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
CompoundCommand::Redo()
|
||||
{
|
||||
return Perform();
|
||||
}
|
||||
|
||||
// GetName
|
||||
void
|
||||
CompoundCommand::GetName(BString& name)
|
||||
{
|
||||
name << _GetString(fNameIndex, fName.String());
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef COMPOUND_ACTION_H
|
||||
#define COMPOUND_ACTION_H
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
class CompoundCommand : public Command {
|
||||
public:
|
||||
CompoundCommand(Command** commands,
|
||||
int32 count,
|
||||
const char* name,
|
||||
int32 nameIndex);
|
||||
virtual ~CompoundCommand();
|
||||
|
||||
virtual status_t InitCheck();
|
||||
|
||||
virtual status_t Perform();
|
||||
virtual status_t Undo();
|
||||
virtual status_t Redo();
|
||||
|
||||
virtual void GetName(BString& name);
|
||||
|
||||
private:
|
||||
Command** fCommands;
|
||||
int32 fCount;
|
||||
|
||||
BString fName;
|
||||
int32 fNameIndex;
|
||||
};
|
||||
|
||||
#endif // COMPOUND_ACTION_H
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Group.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// constructor
|
||||
Group::Group(BRect frame, const char* name, orientation direction)
|
||||
: BView(frame, name, B_FOLLOW_ALL, B_FRAME_EVENTS),
|
||||
fOrientation(direction),
|
||||
fInset(4.0),
|
||||
fSpacing(0.0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
}
|
||||
|
||||
// destructor
|
||||
Group::~Group()
|
||||
{
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
Group::AttachedToWindow()
|
||||
{
|
||||
// trigger a layout
|
||||
FrameResized(Bounds().Width(), Bounds().Height());
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
Group::FrameResized(float width, float height)
|
||||
{
|
||||
// layout controls
|
||||
BRect r(Bounds());
|
||||
r.InsetBy(fInset, fInset);
|
||||
_LayoutControls(r);
|
||||
}
|
||||
|
||||
// GetPreferredSize
|
||||
void
|
||||
Group::GetPreferredSize(float* width, float* height)
|
||||
{
|
||||
BRect r(_MinFrame());
|
||||
|
||||
if (width)
|
||||
*width = r.Width();
|
||||
if (height)
|
||||
*height = r.Height();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _LayoutControls
|
||||
void
|
||||
Group::_LayoutControls(BRect r) const
|
||||
{
|
||||
if (fOrientation == B_HORIZONTAL) {
|
||||
r.left -= fSpacing;
|
||||
for (int32 i = 0; BView* child = ChildAt(i); i++) {
|
||||
r.right = r.left + child->Bounds().Width() + 2 * fSpacing;
|
||||
_LayoutControl(child, r);
|
||||
r.left = r.right + 1.0 - fSpacing;
|
||||
}
|
||||
} else {
|
||||
r.top -= fSpacing;
|
||||
for (int32 i = 0; BView* child = ChildAt(i); i++) {
|
||||
r.bottom = r.top + child->Bounds().Height() + 2 * fSpacing;
|
||||
_LayoutControl(child, r);
|
||||
r.top = r.bottom + 1.0 - fSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _MinFrame
|
||||
BRect
|
||||
Group::_MinFrame() const
|
||||
{
|
||||
float minWidth = fInset * 2.0;
|
||||
float minHeight = fInset * 2.0;
|
||||
|
||||
if (fOrientation == B_HORIZONTAL) {
|
||||
minWidth += fSpacing;
|
||||
for (int32 i = 0; BView* child = ChildAt(i); i++) {
|
||||
minWidth += child->Bounds().Width() + fSpacing;
|
||||
minHeight = max_c(minHeight,
|
||||
child->Bounds().Height() + fInset * 2.0);
|
||||
}
|
||||
} else {
|
||||
minHeight += fSpacing;
|
||||
for (int32 i = 0; BView* child = ChildAt(i); i++) {
|
||||
minHeight += child->Bounds().Height() + fSpacing;
|
||||
minWidth = max_c(minWidth,
|
||||
child->Bounds().Width() + fInset * 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
|
||||
}
|
||||
|
||||
// _LayoutControl
|
||||
void
|
||||
Group::_LayoutControl(BView* view, BRect frame,
|
||||
bool resizeWidth, bool resizeHeight) const
|
||||
{
|
||||
if (!resizeHeight)
|
||||
// center vertically
|
||||
frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
|
||||
if (!resizeWidth)
|
||||
// center horizontally
|
||||
frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
|
||||
view->MoveTo(frame.LeftTop());
|
||||
float width = resizeWidth ? frame.Width() : view->Bounds().Width();
|
||||
float height = resizeHeight ? frame.Height() : view->Bounds().Height();
|
||||
if (resizeWidth || resizeHeight)
|
||||
view->ResizeTo(width, height);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef GROUP_H
|
||||
#define GROUP_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class Group : public BView {
|
||||
public:
|
||||
Group(BRect frame,
|
||||
const char* name,
|
||||
orientation direction = B_HORIZONTAL);
|
||||
virtual ~Group();
|
||||
|
||||
// BView interface
|
||||
virtual void AttachedToWindow();
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void GetPreferredSize(float* width, float* height);
|
||||
|
||||
// TODO: allow setting inset and spacing
|
||||
|
||||
private:
|
||||
void _LayoutControls(BRect frame) const;
|
||||
BRect _MinFrame() const;
|
||||
void _LayoutControl(BView* view,
|
||||
BRect frame,
|
||||
bool resizeWidth = false,
|
||||
bool resizeHeight = false) const;
|
||||
|
||||
orientation fOrientation;
|
||||
float fInset;
|
||||
float fSpacing;
|
||||
};
|
||||
|
||||
#endif // GROUP_H
|
||||
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "IconButton.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Control.h>
|
||||
#include <Entry.h>
|
||||
#include <Looper.h>
|
||||
#include <Message.h>
|
||||
#include <Mime.h>
|
||||
#include <Path.h>
|
||||
#include <Region.h>
|
||||
#include <Roster.h>
|
||||
#include <TranslationUtils.h>
|
||||
#include <Window.h>
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
IconButton::IconButton(const char* name, uint32 id, const char* label,
|
||||
BMessage* message, BHandler* target)
|
||||
: BView(BRect(0.0, 0.0, 10.0, 10.0), name, B_FOLLOW_NONE, B_WILL_DRAW),
|
||||
BInvoker(message, target),
|
||||
fButtonState(STATE_ENABLED),
|
||||
fID(id),
|
||||
fNormalBitmap(NULL),
|
||||
fDisabledBitmap(NULL),
|
||||
fClickedBitmap(NULL),
|
||||
fDisabledClickedBitmap(NULL),
|
||||
fLabel(label),
|
||||
fTargetCache(target)
|
||||
{
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
}
|
||||
|
||||
// destructor
|
||||
IconButton::~IconButton()
|
||||
{
|
||||
_DeleteBitmaps();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
IconButton::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
IconButton::AttachedToWindow()
|
||||
{
|
||||
SetTarget(fTargetCache);
|
||||
if (!Target()) {
|
||||
SetTarget(Window());
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
IconButton::Draw(BRect area)
|
||||
{
|
||||
rgb_color background = LowColor();
|
||||
if (MView* parent = dynamic_cast<MView*>(Parent()))
|
||||
background = parent->getcolor();
|
||||
rgb_color lightShadow, shadow, darkShadow, light;
|
||||
BRect r(Bounds());
|
||||
BBitmap* bitmap = fNormalBitmap;
|
||||
// adjust colors and bitmap according to flags
|
||||
if (IsEnabled()) {
|
||||
lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
shadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||
light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
SetHighColor(0, 0, 0, 255);
|
||||
} else {
|
||||
lightShadow = tint_color(background, 1.11);
|
||||
shadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
light = tint_color(background, B_LIGHTEN_2_TINT);
|
||||
bitmap = fDisabledBitmap;
|
||||
SetHighColor(tint_color(background, B_DISABLED_LABEL_TINT));
|
||||
}
|
||||
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED)) {
|
||||
if (IsEnabled()) {
|
||||
// background = tint_color(background, B_DARKEN_2_TINT);
|
||||
// background = tint_color(background, B_LIGHTEN_1_TINT);
|
||||
background = tint_color(background, B_DARKEN_1_TINT);
|
||||
bitmap = fClickedBitmap;
|
||||
} else {
|
||||
// background = tint_color(background, B_DARKEN_1_TINT);
|
||||
// background = tint_color(background, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
|
||||
background = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
|
||||
bitmap = fDisabledClickedBitmap;
|
||||
}
|
||||
// background
|
||||
SetLowColor(background);
|
||||
r.InsetBy(2.0, 2.0);
|
||||
StrokeLine(r.LeftBottom(), r.LeftTop(), B_SOLID_LOW);
|
||||
StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_LOW);
|
||||
r.InsetBy(-2.0, -2.0);
|
||||
}
|
||||
// draw frame only if tracking
|
||||
if (DrawBorder()) {
|
||||
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||
DrawPressedBorder(r, background, shadow, darkShadow, lightShadow, light);
|
||||
else
|
||||
DrawNormalBorder(r, background, shadow, darkShadow, lightShadow, light);
|
||||
r.InsetBy(2.0, 2.0);
|
||||
} else
|
||||
_DrawFrame(r, background, background, background, background);
|
||||
float width = Bounds().Width();
|
||||
float height = Bounds().Height();
|
||||
// bitmap
|
||||
BRegion originalClippingRegion;
|
||||
if (bitmap && bitmap->IsValid()) {
|
||||
float x = floorf((width - bitmap->Bounds().Width()) / 2.0 + 0.5);
|
||||
float y = floorf((height - bitmap->Bounds().Height()) / 2.0 + 0.5);
|
||||
BPoint point(x, y);
|
||||
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||
point += BPoint(1.0, 1.0);
|
||||
if (bitmap->ColorSpace() == B_RGBA32 || bitmap->ColorSpace() == B_RGBA32_BIG) {
|
||||
FillRect(r, B_SOLID_LOW);
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||
}
|
||||
DrawBitmap(bitmap, point);
|
||||
// constrain clipping region
|
||||
BRegion region= originalClippingRegion;
|
||||
GetClippingRegion(®ion);
|
||||
region.Exclude(bitmap->Bounds().OffsetByCopy(point));
|
||||
ConstrainClippingRegion(®ion);
|
||||
}
|
||||
// background
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
FillRect(r, B_SOLID_LOW);
|
||||
ConstrainClippingRegion(&originalClippingRegion);
|
||||
// label
|
||||
if (fLabel.CountChars() > 0) {
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
float y = Bounds().bottom - 4.0;
|
||||
y -= fh.descent;
|
||||
float x = (width - StringWidth(fLabel.String())) / 2.0;
|
||||
DrawString(fLabel.String(), BPoint(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
IconButton::MouseDown(BPoint where)
|
||||
{
|
||||
if (IsValid()) {
|
||||
if (_HasFlags(STATE_ENABLED)/* && !_HasFlags(STATE_FORCE_PRESSED)*/) {
|
||||
if (Bounds().Contains(where)) {
|
||||
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
|
||||
_AddFlags(STATE_PRESSED | STATE_TRACKING);
|
||||
} else {
|
||||
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
IconButton::MouseUp(BPoint where)
|
||||
{
|
||||
if (IsValid()) {
|
||||
// if (!_HasFlags(STATE_FORCE_PRESSED)) {
|
||||
if (_HasFlags(STATE_ENABLED) && _HasFlags(STATE_PRESSED) && Bounds().Contains(where))
|
||||
Invoke();
|
||||
else if (Bounds().Contains(where))
|
||||
_AddFlags(STATE_INSIDE);
|
||||
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
IconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
|
||||
{
|
||||
if (IsValid()) {
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
||||
// catch a mouse up event that we might have missed
|
||||
if (!buttons && _HasFlags(STATE_PRESSED)) {
|
||||
MouseUp(where);
|
||||
return;
|
||||
}
|
||||
if (buttons && !_HasFlags(STATE_TRACKING))
|
||||
return;
|
||||
if ((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
|
||||
&& _HasFlags(STATE_ENABLED))
|
||||
_AddFlags(STATE_INSIDE);
|
||||
else
|
||||
_ClearFlags(STATE_INSIDE);
|
||||
if (_HasFlags(STATE_TRACKING)) {
|
||||
if (Bounds().Contains(where))
|
||||
_AddFlags(STATE_PRESSED);
|
||||
else
|
||||
_ClearFlags(STATE_PRESSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPreferredSize
|
||||
void
|
||||
IconButton::GetPreferredSize(float* width, float* height)
|
||||
{
|
||||
layoutprefs();
|
||||
|
||||
if (width)
|
||||
*width = mpm.mini.x;
|
||||
if (height)
|
||||
*height = mpm.mini.y;
|
||||
}
|
||||
|
||||
// Invoke
|
||||
status_t
|
||||
IconButton::Invoke(BMessage* message)
|
||||
{
|
||||
if (!message)
|
||||
message = Message();
|
||||
if (message) {
|
||||
BMessage clone(*message);
|
||||
clone.AddInt64("be:when", system_time());
|
||||
clone.AddPointer("be:source", (BView*)this);
|
||||
clone.AddInt32("be:value", Value());
|
||||
clone.AddInt32("id", ID());
|
||||
return BInvoker::Invoke(&clone);
|
||||
}
|
||||
return BInvoker::Invoke(message);
|
||||
}
|
||||
|
||||
#define MIN_SPACE 15.0
|
||||
|
||||
// layoutprefs
|
||||
minimax
|
||||
IconButton::layoutprefs()
|
||||
{
|
||||
float minWidth = 0.0;
|
||||
float minHeight = 0.0;
|
||||
if (IsValid()) {
|
||||
minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0;
|
||||
minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0;
|
||||
} else {
|
||||
minWidth += MIN_SPACE;
|
||||
minHeight += MIN_SPACE;
|
||||
}
|
||||
if (minWidth < MIN_SPACE)
|
||||
minWidth = MIN_SPACE;
|
||||
if (minHeight < MIN_SPACE)
|
||||
minHeight = MIN_SPACE;
|
||||
if (fLabel.CountChars() > 0) {
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
minHeight += ceilf(fh.ascent + fh.descent) + 4.0;
|
||||
minWidth += StringWidth(fLabel.String()) + 4.0;
|
||||
}
|
||||
mpm.mini.x = minWidth + 4.0;
|
||||
// mpm.maxi.x = 10000.0 + 4.0;
|
||||
mpm.maxi.x = minWidth + 4.0;
|
||||
mpm.mini.y = minHeight + 4.0;
|
||||
// mpm.maxi.y = 10000.0 + 4.0;
|
||||
mpm.maxi.y = minHeight + 4.0;
|
||||
mpm.weight = 0.0;
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
IconButton::layout(BRect rect)
|
||||
{
|
||||
MoveTo(rect.LeftTop());
|
||||
ResizeTo(rect.Width(), rect.Height());
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// SetPressed
|
||||
void
|
||||
IconButton::SetPressed(bool pressed)
|
||||
{
|
||||
if (pressed)
|
||||
_AddFlags(STATE_FORCE_PRESSED);
|
||||
else
|
||||
_ClearFlags(STATE_FORCE_PRESSED);
|
||||
}
|
||||
|
||||
// IsPressed
|
||||
bool
|
||||
IconButton::IsPressed() const
|
||||
{
|
||||
return _HasFlags(STATE_FORCE_PRESSED);
|
||||
}
|
||||
|
||||
// SetIcon
|
||||
status_t
|
||||
IconButton::SetIcon(const char* pathToBitmap)
|
||||
{
|
||||
status_t status = B_BAD_VALUE;
|
||||
if (pathToBitmap) {
|
||||
BBitmap* fileBitmap = NULL;
|
||||
// try to load bitmap from either relative or absolute path
|
||||
BEntry entry(pathToBitmap, true);
|
||||
if (!entry.Exists()) {
|
||||
app_info info;
|
||||
status = be_app->GetAppInfo(&info);
|
||||
if (status == B_OK) {
|
||||
BEntry app_entry(&info.ref, true);
|
||||
BPath path;
|
||||
app_entry.GetPath(&path);
|
||||
status = path.InitCheck();
|
||||
if (status == B_OK) {
|
||||
status = path.GetParent(&path);
|
||||
if (status == B_OK) {
|
||||
status = path.Append(pathToBitmap, true);
|
||||
if (status == B_OK)
|
||||
fileBitmap = BTranslationUtils::GetBitmap(path.Path());
|
||||
else
|
||||
printf("IconButton::SetIcon() - path.Append() failed: %s\n", strerror(status));
|
||||
} else
|
||||
printf("IconButton::SetIcon() - path.GetParent() failed: %s\n", strerror(status));
|
||||
} else
|
||||
printf("IconButton::SetIcon() - path.InitCheck() failed: %s\n", strerror(status));
|
||||
} else
|
||||
printf("IconButton::SetIcon() - be_app->GetAppInfo() failed: %s\n", strerror(status));
|
||||
} else
|
||||
fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
|
||||
if (fileBitmap) {
|
||||
status = _MakeBitmaps(fileBitmap);
|
||||
delete fileBitmap;
|
||||
} else
|
||||
status = B_ERROR;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// SetIcon
|
||||
status_t
|
||||
IconButton::SetIcon(const BBitmap* bitmap)
|
||||
{
|
||||
if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
|
||||
status_t status = bitmap->InitCheck();
|
||||
if (status >= B_OK) {
|
||||
if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
|
||||
status = _MakeBitmaps(rgb32Bitmap);
|
||||
delete rgb32Bitmap;
|
||||
} else
|
||||
status = B_NO_MEMORY;
|
||||
}
|
||||
return status;
|
||||
} else
|
||||
return _MakeBitmaps(bitmap);
|
||||
}
|
||||
|
||||
// SetIcon
|
||||
status_t
|
||||
IconButton::SetIcon(const BMimeType* fileType, bool small)
|
||||
{
|
||||
status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
|
||||
if (status >= B_OK) {
|
||||
BBitmap* mimeBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_CMAP8);
|
||||
if (mimeBitmap && mimeBitmap->IsValid()) {
|
||||
status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON : B_LARGE_ICON);
|
||||
if (status >= B_OK) {
|
||||
if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
|
||||
status = _MakeBitmaps(bitmap);
|
||||
delete bitmap;
|
||||
} else
|
||||
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
||||
} else
|
||||
printf("IconButton::SetIcon() - fileType->GetIcon() failed: %s\n", strerror(status));
|
||||
} else
|
||||
printf("IconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
|
||||
delete mimeBitmap;
|
||||
} else
|
||||
printf("IconButton::SetIcon() - fileType is not valid: %s\n", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
// SetIcon
|
||||
status_t
|
||||
IconButton::SetIcon(const unsigned char* bitsFromQuickRes,
|
||||
uint32 width, uint32 height, color_space format, bool convertToBW)
|
||||
{
|
||||
status_t status = B_BAD_VALUE;
|
||||
if (bitsFromQuickRes && width > 0 && height > 0) {
|
||||
BBitmap* quickResBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, width - 1.0, height - 1.0), format);
|
||||
status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
|
||||
if (status >= B_OK) {
|
||||
// It doesn't look right to copy BitsLength() bytes, but bitmaps
|
||||
// exported from QuickRes still contain their padding, so it is alright.
|
||||
memcpy(quickResBitmap->Bits(), bitsFromQuickRes, quickResBitmap->BitsLength());
|
||||
if (format != B_RGB32 && format != B_RGBA32 && format != B_RGB32_BIG && format != B_RGBA32_BIG) {
|
||||
// colorspace needs conversion
|
||||
BBitmap* bitmap = new(nothrow) BBitmap(quickResBitmap->Bounds(), B_RGB32, true);
|
||||
if (bitmap && bitmap->IsValid()) {
|
||||
BView* helper = new BView(bitmap->Bounds(), "helper",
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
if (bitmap->Lock()) {
|
||||
bitmap->AddChild(helper);
|
||||
helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
helper->FillRect(helper->Bounds());
|
||||
helper->SetDrawingMode(B_OP_OVER);
|
||||
helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
|
||||
helper->Sync();
|
||||
bitmap->Unlock();
|
||||
}
|
||||
status = _MakeBitmaps(bitmap);
|
||||
} else
|
||||
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
||||
delete bitmap;
|
||||
} else {
|
||||
// native colorspace (32 bits)
|
||||
if (convertToBW) {
|
||||
// convert to gray scale icon
|
||||
uint8* bits = (uint8*)quickResBitmap->Bits();
|
||||
uint32 bpr = quickResBitmap->BytesPerRow();
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
uint8* handle = bits;
|
||||
uint8 gray;
|
||||
for (uint32 x = 0; x < width; x++) {
|
||||
gray = uint8((116 * handle[0] + 600 * handle[1] + 308 * handle[2]) / 1024);
|
||||
handle[0] = gray;
|
||||
handle[1] = gray;
|
||||
handle[2] = gray;
|
||||
handle += 4;
|
||||
}
|
||||
bits += bpr;
|
||||
}
|
||||
}
|
||||
status = _MakeBitmaps(quickResBitmap);
|
||||
}
|
||||
} else
|
||||
printf("IconButton::SetIcon() - error allocating bitmap: %s\n", strerror(status));
|
||||
delete quickResBitmap;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// ClearIcon
|
||||
void
|
||||
IconButton::ClearIcon()
|
||||
{
|
||||
_DeleteBitmaps();
|
||||
_Update();
|
||||
}
|
||||
|
||||
// Bitmap
|
||||
BBitmap*
|
||||
IconButton::Bitmap() const
|
||||
{
|
||||
BBitmap* bitmap = NULL;
|
||||
if (fNormalBitmap && fNormalBitmap->IsValid()) {
|
||||
bitmap = new(nothrow) BBitmap(fNormalBitmap);
|
||||
if (bitmap->IsValid()) {
|
||||
// TODO: remove this functionality when we use real transparent bitmaps
|
||||
uint8* bits = (uint8*)bitmap->Bits();
|
||||
uint32 bpr = bitmap->BytesPerRow();
|
||||
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
||||
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
||||
color_space format = bitmap->ColorSpace();
|
||||
if (format == B_CMAP8) {
|
||||
// replace gray with magic transparent index
|
||||
} else if (format == B_RGB32) {
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
uint8* bitsHandle = bits;
|
||||
for (uint32 x = 0; x < width; x++) {
|
||||
if (bitsHandle[0] == 216
|
||||
&& bitsHandle[1] == 216
|
||||
&& bitsHandle[2] == 216) {
|
||||
bitsHandle[3] = 0; // make this pixel completely transparent
|
||||
}
|
||||
bitsHandle += 4;
|
||||
}
|
||||
bits += bpr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delete bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
// DrawBorder
|
||||
bool
|
||||
IconButton::DrawBorder() const
|
||||
{
|
||||
return (IsEnabled() && (_HasFlags(STATE_INSIDE) || _HasFlags(STATE_TRACKING))
|
||||
|| _HasFlags(STATE_FORCE_PRESSED));
|
||||
}
|
||||
|
||||
// DrawNormalBorder
|
||||
void
|
||||
IconButton::DrawNormalBorder(BRect r, rgb_color background,
|
||||
rgb_color shadow, rgb_color darkShadow,
|
||||
rgb_color lightShadow, rgb_color light)
|
||||
{
|
||||
_DrawFrame(r, shadow, darkShadow, light, lightShadow);
|
||||
}
|
||||
|
||||
// DrawPressedBorder
|
||||
void
|
||||
IconButton::DrawPressedBorder(BRect r, rgb_color background,
|
||||
rgb_color shadow, rgb_color darkShadow,
|
||||
rgb_color lightShadow, rgb_color light)
|
||||
{
|
||||
_DrawFrame(r, shadow, light, darkShadow, background);
|
||||
}
|
||||
|
||||
// IsValid
|
||||
bool
|
||||
IconButton::IsValid() const
|
||||
{
|
||||
return (fNormalBitmap && fDisabledBitmap && fClickedBitmap && fDisabledClickedBitmap
|
||||
&& fNormalBitmap->IsValid()
|
||||
&& fDisabledBitmap->IsValid()
|
||||
&& fClickedBitmap->IsValid()
|
||||
&& fDisabledClickedBitmap->IsValid());
|
||||
}
|
||||
|
||||
// Value
|
||||
int32
|
||||
IconButton::Value() const
|
||||
{
|
||||
return _HasFlags(STATE_PRESSED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
IconButton::SetValue(int32 value)
|
||||
{
|
||||
if (value)
|
||||
_AddFlags(STATE_PRESSED);
|
||||
else
|
||||
_ClearFlags(STATE_PRESSED);
|
||||
}
|
||||
|
||||
// IsEnabled
|
||||
bool
|
||||
IconButton::IsEnabled() const
|
||||
{
|
||||
return _HasFlags(STATE_ENABLED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
IconButton::SetEnabled(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
_AddFlags(STATE_ENABLED);
|
||||
else
|
||||
_ClearFlags(STATE_ENABLED | STATE_TRACKING | STATE_INSIDE);
|
||||
}
|
||||
|
||||
// _ConvertToRGB32
|
||||
BBitmap*
|
||||
IconButton::_ConvertToRGB32(const BBitmap* bitmap) const
|
||||
{
|
||||
BBitmap* convertedBitmap = new(nothrow) BBitmap(bitmap->Bounds(), B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
|
||||
if (convertedBitmap && convertedBitmap->IsValid()) {
|
||||
memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
|
||||
BView* helper = new BView(bitmap->Bounds(), "helper",
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
if (convertedBitmap->Lock()) {
|
||||
convertedBitmap->AddChild(helper);
|
||||
helper->SetDrawingMode(B_OP_OVER);
|
||||
helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
|
||||
helper->Sync();
|
||||
convertedBitmap->Unlock();
|
||||
}
|
||||
} else {
|
||||
delete convertedBitmap;
|
||||
convertedBitmap = NULL;
|
||||
}
|
||||
return convertedBitmap;
|
||||
}
|
||||
|
||||
// _MakeBitmaps
|
||||
status_t
|
||||
IconButton::_MakeBitmaps(const BBitmap* bitmap)
|
||||
{
|
||||
status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
|
||||
if (status >= B_OK) {
|
||||
// make our own versions of the bitmap
|
||||
BRect b(bitmap->Bounds());
|
||||
_DeleteBitmaps();
|
||||
color_space format = bitmap->ColorSpace();
|
||||
fNormalBitmap = new(nothrow) BBitmap(b, format);
|
||||
fDisabledBitmap = new(nothrow) BBitmap(b, format);
|
||||
fClickedBitmap = new(nothrow) BBitmap(b, format);
|
||||
fDisabledClickedBitmap = new(nothrow) BBitmap(b, format);
|
||||
if (IsValid()) {
|
||||
// copy bitmaps from file bitmap
|
||||
uint8* nBits = (uint8*)fNormalBitmap->Bits();
|
||||
uint8* dBits = (uint8*)fDisabledBitmap->Bits();
|
||||
uint8* cBits = (uint8*)fClickedBitmap->Bits();
|
||||
uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
|
||||
uint8* fBits = (uint8*)bitmap->Bits();
|
||||
int32 nbpr = fNormalBitmap->BytesPerRow();
|
||||
int32 fbpr = bitmap->BytesPerRow();
|
||||
int32 pixels = b.IntegerWidth() + 1;
|
||||
int32 lines = b.IntegerHeight() + 1;
|
||||
// nontransparent version:
|
||||
if (format == B_RGB32 || format == B_RGB32_BIG) {
|
||||
// iterate over color components
|
||||
for (int32 y = 0; y < lines; y++) {
|
||||
for (int32 x = 0; x < pixels; x++) {
|
||||
int32 nOffset = 4 * x;
|
||||
int32 fOffset = 4 * x;
|
||||
nBits[nOffset + 0] = fBits[fOffset + 0];
|
||||
nBits[nOffset + 1] = fBits[fOffset + 1];
|
||||
nBits[nOffset + 2] = fBits[fOffset + 2];
|
||||
nBits[nOffset + 3] = 255;
|
||||
// clicked bits are darker (lame method...)
|
||||
cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0] * 0.8);
|
||||
cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1] * 0.8);
|
||||
cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2] * 0.8);
|
||||
cBits[nOffset + 3] = 255;
|
||||
// disabled bits have less contrast (lame method...)
|
||||
uint8 grey = 216;
|
||||
float dist = (nBits[nOffset + 0] - grey) * 0.4;
|
||||
dBits[nOffset + 0] = (uint8)(grey + dist);
|
||||
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
||||
dBits[nOffset + 1] = (uint8)(grey + dist);
|
||||
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
||||
dBits[nOffset + 2] = (uint8)(grey + dist);
|
||||
dBits[nOffset + 3] = 255;
|
||||
// disabled bits have less contrast (lame method...)
|
||||
grey = 188;
|
||||
dist = (nBits[nOffset + 0] - grey) * 0.4;
|
||||
dcBits[nOffset + 0] = (uint8)(grey + dist);
|
||||
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
||||
dcBits[nOffset + 1] = (uint8)(grey + dist);
|
||||
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
||||
dcBits[nOffset + 2] = (uint8)(grey + dist);
|
||||
dcBits[nOffset + 3] = 255;
|
||||
}
|
||||
nBits += nbpr;
|
||||
dBits += nbpr;
|
||||
cBits += nbpr;
|
||||
dcBits += nbpr;
|
||||
fBits += fbpr;
|
||||
}
|
||||
// transparent version:
|
||||
} else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
|
||||
// iterate over color components
|
||||
for (int32 y = 0; y < lines; y++) {
|
||||
for (int32 x = 0; x < pixels; x++) {
|
||||
int32 nOffset = 4 * x;
|
||||
int32 fOffset = 4 * x;
|
||||
nBits[nOffset + 0] = fBits[fOffset + 0];
|
||||
nBits[nOffset + 1] = fBits[fOffset + 1];
|
||||
nBits[nOffset + 2] = fBits[fOffset + 2];
|
||||
nBits[nOffset + 3] = fBits[fOffset + 3];
|
||||
// clicked bits are darker (lame method...)
|
||||
cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
|
||||
cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
|
||||
cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
|
||||
cBits[nOffset + 3] = fBits[fOffset + 3];
|
||||
// disabled bits have less opacity
|
||||
dBits[nOffset + 0] = fBits[fOffset + 0];
|
||||
dBits[nOffset + 1] = fBits[fOffset + 1];
|
||||
dBits[nOffset + 2] = fBits[fOffset + 2];
|
||||
dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
|
||||
// disabled bits have less contrast (lame method...)
|
||||
dcBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
|
||||
dcBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
|
||||
dcBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
|
||||
dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.5);
|
||||
}
|
||||
nBits += nbpr;
|
||||
dBits += nbpr;
|
||||
cBits += nbpr;
|
||||
dcBits += nbpr;
|
||||
fBits += fbpr;
|
||||
}
|
||||
// unsupported format
|
||||
} else {
|
||||
printf("IconButton::_MakeBitmaps() - bitmap has unsupported colorspace\n");
|
||||
status = B_MISMATCHED_VALUES;
|
||||
_DeleteBitmaps();
|
||||
}
|
||||
} else {
|
||||
printf("IconButton::_MakeBitmaps() - error allocating local bitmaps\n");
|
||||
status = B_NO_MEMORY;
|
||||
_DeleteBitmaps();
|
||||
}
|
||||
} else
|
||||
printf("IconButton::_MakeBitmaps() - bitmap is not valid\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
// _DeleteBitmaps
|
||||
void
|
||||
IconButton::_DeleteBitmaps()
|
||||
{
|
||||
delete fNormalBitmap;
|
||||
fNormalBitmap = NULL;
|
||||
delete fDisabledBitmap;
|
||||
fDisabledBitmap = NULL;
|
||||
delete fClickedBitmap;
|
||||
fClickedBitmap = NULL;
|
||||
delete fDisabledClickedBitmap;
|
||||
fDisabledClickedBitmap = NULL;
|
||||
}
|
||||
|
||||
// _Update
|
||||
void
|
||||
IconButton::_Update()
|
||||
{
|
||||
if (LockLooper()) {
|
||||
Invalidate();
|
||||
UnlockLooper();
|
||||
}
|
||||
}
|
||||
|
||||
// _AddFlags
|
||||
void
|
||||
IconButton::_AddFlags(uint32 flags)
|
||||
{
|
||||
if (!(fButtonState & flags)) {
|
||||
fButtonState |= flags;
|
||||
_Update();
|
||||
}
|
||||
}
|
||||
|
||||
// _ClearFlags
|
||||
void
|
||||
IconButton::_ClearFlags(uint32 flags)
|
||||
{
|
||||
if (fButtonState & flags) {
|
||||
fButtonState &= ~flags;
|
||||
_Update();
|
||||
}
|
||||
}
|
||||
|
||||
// _HasFlags
|
||||
bool
|
||||
IconButton::_HasFlags(uint32 flags) const
|
||||
{
|
||||
return (fButtonState & flags);
|
||||
}
|
||||
|
||||
// _DrawFrame
|
||||
void
|
||||
IconButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
|
||||
rgb_color col3, rgb_color col4)
|
||||
{
|
||||
BeginLineArray(8);
|
||||
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
|
||||
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
|
||||
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
|
||||
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
|
||||
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
|
||||
EndLineArray();
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
/** gui class that loads an image from disk and shows it
|
||||
as clickable button */
|
||||
|
||||
// TODO: inherit from BControl?
|
||||
|
||||
#ifndef ICON_BUTTON_H
|
||||
#define ICON_BUTTON_H
|
||||
|
||||
#include <layout.h>
|
||||
|
||||
#include <Invoker.h>
|
||||
#include <String.h>
|
||||
#include <View.h>
|
||||
|
||||
class BBitmap;
|
||||
class BMimeType;
|
||||
|
||||
class IconButton : public MView, public BView, public BInvoker {
|
||||
public:
|
||||
IconButton(const char* name,
|
||||
uint32 id,
|
||||
const char* label = NULL,
|
||||
BMessage* message = NULL,
|
||||
BHandler* target = NULL);
|
||||
virtual ~IconButton();
|
||||
|
||||
// BHandler
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// BView
|
||||
virtual void AttachedToWindow();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* message);
|
||||
virtual void GetPreferredSize(float* width,
|
||||
float* height);
|
||||
|
||||
// BInvoker
|
||||
virtual status_t Invoke(BMessage* message = NULL);
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect rect);
|
||||
|
||||
// IconButton
|
||||
bool IsValid() const;
|
||||
|
||||
virtual int32 Value() const;
|
||||
virtual void SetValue(int32 value);
|
||||
|
||||
bool IsEnabled() const;
|
||||
void SetEnabled(bool enable);
|
||||
|
||||
void SetPressed(bool pressed);
|
||||
bool IsPressed() const;
|
||||
uint32 ID() const
|
||||
{ return fID; }
|
||||
|
||||
status_t SetIcon(const char* pathToBitmap);
|
||||
status_t SetIcon(const BBitmap* bitmap);
|
||||
status_t SetIcon(const BMimeType* fileType,
|
||||
bool small = true);
|
||||
status_t SetIcon(const unsigned char* bitsFromQuickRes,
|
||||
uint32 width, uint32 height,
|
||||
color_space format,
|
||||
bool convertToBW = false);
|
||||
void ClearIcon();
|
||||
|
||||
BBitmap* Bitmap() const; // caller has to delete the returned bitmap
|
||||
|
||||
virtual bool DrawBorder() const;
|
||||
virtual void DrawNormalBorder(BRect r, rgb_color background,
|
||||
rgb_color shadow,
|
||||
rgb_color darkShadow,
|
||||
rgb_color lightShadow,
|
||||
rgb_color light);
|
||||
virtual void DrawPressedBorder(BRect r, rgb_color background,
|
||||
rgb_color shadow,
|
||||
rgb_color darkShadow,
|
||||
rgb_color lightShadow,
|
||||
rgb_color light);
|
||||
|
||||
protected:
|
||||
enum {
|
||||
STATE_NONE = 0x0000,
|
||||
STATE_TRACKING = 0x0001,
|
||||
STATE_PRESSED = 0x0002,
|
||||
STATE_ENABLED = 0x0004,
|
||||
STATE_INSIDE = 0x0008,
|
||||
STATE_FORCE_PRESSED = 0x0010,
|
||||
};
|
||||
|
||||
void _AddFlags(uint32 flags);
|
||||
void _ClearFlags(uint32 flags);
|
||||
bool _HasFlags(uint32 flags) const;
|
||||
|
||||
void _DrawFrame(BRect frame,
|
||||
rgb_color col1,
|
||||
rgb_color col2,
|
||||
rgb_color col3,
|
||||
rgb_color col4);
|
||||
|
||||
// private:
|
||||
BBitmap* _ConvertToRGB32(const BBitmap* bitmap) const;
|
||||
status_t _MakeBitmaps(const BBitmap* bitmap);
|
||||
void _DeleteBitmaps();
|
||||
void _SendMessage() const;
|
||||
void _Update();
|
||||
|
||||
uint32 fButtonState;
|
||||
int32 fID;
|
||||
BBitmap* fNormalBitmap;
|
||||
BBitmap* fDisabledBitmap;
|
||||
BBitmap* fClickedBitmap;
|
||||
BBitmap* fDisabledClickedBitmap;
|
||||
BString fLabel;
|
||||
|
||||
BHandler* fTargetCache;
|
||||
};
|
||||
|
||||
#endif // ICON_BUTTON_H
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "IconOptionsControl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
#include "IconButton.h"
|
||||
|
||||
#define LABEL_DIST 8.0
|
||||
|
||||
// constructor
|
||||
IconOptionsControl::IconOptionsControl(const char* name,
|
||||
const char* label,
|
||||
BMessage* message,
|
||||
BHandler* target)
|
||||
: MView(),
|
||||
BControl(BRect(0.0, 0.0, 10.0, 10.0), name, label, message,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fTargetCache(target)
|
||||
{
|
||||
if (Label()) {
|
||||
labelwidth = StringWidth(Label()) + LABEL_DIST;
|
||||
} else {
|
||||
labelwidth = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
IconOptionsControl::~IconOptionsControl()
|
||||
{
|
||||
}
|
||||
|
||||
// layoutprefs
|
||||
minimax
|
||||
IconOptionsControl::layoutprefs()
|
||||
{
|
||||
// sanity checks
|
||||
if (rolemodel)
|
||||
labelwidth = rolemodel->LabelWidth();
|
||||
if (labelwidth < LabelWidth())
|
||||
labelwidth = LabelWidth();
|
||||
|
||||
mpm.mini.x = 0.0 + labelwidth + 5.0;
|
||||
mpm.mini.y = 0.0;
|
||||
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
minimax childPrefs = button->layoutprefs();
|
||||
mpm.mini.x += childPrefs.mini.x + 1;
|
||||
if (mpm.mini.y < childPrefs.mini.y + 1)
|
||||
mpm.mini.y = childPrefs.mini.y + 1;
|
||||
}
|
||||
|
||||
mpm.maxi.x = mpm.mini.x;
|
||||
mpm.maxi.y = mpm.mini.y;
|
||||
|
||||
mpm.weight = 1.0;
|
||||
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
IconOptionsControl::layout(BRect frame)
|
||||
{
|
||||
if (frame.Width() < mpm.mini.x + 1)
|
||||
frame.right = frame.left + mpm.mini.x + 1;
|
||||
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// LabelWidth
|
||||
float
|
||||
IconOptionsControl::LabelWidth()
|
||||
{
|
||||
float width = ceilf(StringWidth(Label()));
|
||||
if (width > 0.0)
|
||||
width += LABEL_DIST;
|
||||
return width;
|
||||
}
|
||||
|
||||
// SetLabel
|
||||
void
|
||||
IconOptionsControl::SetLabel(const char* label)
|
||||
{
|
||||
BControl::SetLabel(label);
|
||||
float width = LabelWidth();
|
||||
if (rolemodel)
|
||||
labelwidth = rolemodel->LabelWidth() > labelwidth ?
|
||||
rolemodel->LabelWidth() : labelwidth;
|
||||
|
||||
labelwidth = width > labelwidth ? width : labelwidth;
|
||||
|
||||
_TriggerRelayout();
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
IconOptionsControl::AttachedToWindow()
|
||||
{
|
||||
BControl::AttachedToWindow();
|
||||
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
}
|
||||
|
||||
// AllAttached
|
||||
void
|
||||
IconOptionsControl::AllAttached()
|
||||
{
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++)
|
||||
button->SetTarget(this);
|
||||
if (fTargetCache)
|
||||
SetTarget(fTargetCache);
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
IconOptionsControl::Draw(BRect updateRect)
|
||||
{
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
|
||||
if (Label()) {
|
||||
if (!IsEnabled())
|
||||
SetHighColor(tint_color(LowColor(), B_DISABLED_LABEL_TINT));
|
||||
else
|
||||
SetHighColor(tint_color(LowColor(), B_DARKEN_MAX_TINT));
|
||||
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
BPoint p(Bounds().LeftTop());
|
||||
p.y += floorf(Bounds().Height() / 2.0 + (fh.ascent + fh.descent) / 2.0) - 2.0;
|
||||
DrawString(Label(), p);
|
||||
}
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
IconOptionsControl::FrameResized(float width, float height)
|
||||
{
|
||||
_LayoutIcons(Bounds());
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
IconOptionsControl::SetValue(int32 value)
|
||||
{
|
||||
if (IconButton* valueButton = _FindIcon(value)) {
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
button->SetPressed(button == valueButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Value
|
||||
int32
|
||||
IconOptionsControl::Value() const
|
||||
{
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
if (button->IsPressed())
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
IconOptionsControl::SetEnabled(bool enable)
|
||||
{
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
button->SetEnabled(enable);
|
||||
}
|
||||
BControl::SetEnabled(enable);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
IconOptionsControl::MessageReceived(BMessage* message)
|
||||
{
|
||||
// catch a message from the attached IconButtons to
|
||||
// handle switching the pressed icon
|
||||
BView* source;
|
||||
if (message->FindPointer("be:source", (void**)&source) >= B_OK) {
|
||||
if (IconButton* sourceIcon = dynamic_cast<IconButton*>(source)) {
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
if (button == sourceIcon) {
|
||||
SetValue(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// forward the message
|
||||
Invoke(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
BControl::MessageReceived(message);
|
||||
}
|
||||
|
||||
// Invoke
|
||||
status_t
|
||||
IconOptionsControl::Invoke(BMessage* message)
|
||||
{
|
||||
return BInvoker::Invoke(message);
|
||||
}
|
||||
|
||||
// AddOption
|
||||
void
|
||||
IconOptionsControl::AddOption(IconButton* icon)
|
||||
{
|
||||
if (icon) {
|
||||
if (!_FindIcon(0)) {
|
||||
// first icon added, mark it
|
||||
icon->SetPressed(true);
|
||||
}
|
||||
AddChild(icon);
|
||||
icon->SetTarget(this);
|
||||
layoutprefs();
|
||||
_TriggerRelayout();
|
||||
}
|
||||
}
|
||||
|
||||
// _FindIcon
|
||||
IconButton*
|
||||
IconOptionsControl::_FindIcon(int32 index) const
|
||||
{
|
||||
if (BView* view = ChildAt(index))
|
||||
return dynamic_cast<IconButton*>(view);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// _TriggerRelayout
|
||||
void
|
||||
IconOptionsControl::_TriggerRelayout()
|
||||
{
|
||||
if (!Parent())
|
||||
return;
|
||||
|
||||
MView* mParent = dynamic_cast<MView*>(Parent());
|
||||
if (mParent) {
|
||||
if (BWindow* window = Window()) {
|
||||
window->PostMessage(M_RECALCULATE_SIZE);
|
||||
}
|
||||
} else {
|
||||
_LayoutIcons(Bounds());
|
||||
}
|
||||
}
|
||||
|
||||
// _LayoutIcons
|
||||
void
|
||||
IconOptionsControl::_LayoutIcons(BRect frame)
|
||||
{
|
||||
BPoint lt = frame.LeftTop();
|
||||
|
||||
// sanity checks
|
||||
if (rolemodel)
|
||||
labelwidth = rolemodel->LabelWidth();
|
||||
if (labelwidth < LabelWidth())
|
||||
labelwidth = LabelWidth();
|
||||
|
||||
lt.x += labelwidth;
|
||||
|
||||
for (int32 i = 0; IconButton* button = _FindIcon(i); i++) {
|
||||
if (i == 0) {
|
||||
lt.y = ceilf((frame.top + frame.bottom - button->mpm.mini.y) / 2.0);
|
||||
}
|
||||
button->MoveTo(lt);
|
||||
button->ResizeTo(button->mpm.mini.x, button->mpm.mini.y);
|
||||
lt = button->Frame().RightTop() + BPoint(1.0, 0.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef ICON_OPTIONS_CONTROL_H
|
||||
#define ICON_OPTIONS_CONTROL_H
|
||||
|
||||
#include <Control.h>
|
||||
#include <Invoker.h>
|
||||
|
||||
#include <MDividable.h>
|
||||
|
||||
class IconButton;
|
||||
|
||||
class IconOptionsControl : public MView,
|
||||
public MDividable,
|
||||
public BControl {
|
||||
public:
|
||||
IconOptionsControl(const char* name = NULL,
|
||||
const char* label = NULL,
|
||||
BMessage* message = NULL,
|
||||
BHandler* target = NULL);
|
||||
~IconOptionsControl();
|
||||
|
||||
// MView interface
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// MDividable interface
|
||||
virtual float LabelWidth();
|
||||
|
||||
// BControl interface
|
||||
virtual void AttachedToWindow();
|
||||
virtual void AllAttached();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void FrameResized(float width, float height);
|
||||
|
||||
virtual void SetLabel(const char* label);
|
||||
virtual void SetValue(int32 value);
|
||||
virtual int32 Value() const;
|
||||
virtual void SetEnabled(bool enable);
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// BInvoker interface
|
||||
virtual status_t Invoke(BMessage* message = NULL);
|
||||
|
||||
// IconOptionsControl
|
||||
void AddOption(IconButton* icon);
|
||||
|
||||
private:
|
||||
|
||||
IconButton* _FindIcon(int32 index) const;
|
||||
void _TriggerRelayout();
|
||||
void _LayoutIcons(BRect frame);
|
||||
|
||||
BHandler* fTargetCache;
|
||||
};
|
||||
|
||||
#endif // ICON_OPTIONS_CONTROL_H
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "InputTextView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <String.h>
|
||||
|
||||
// constructor
|
||||
InputTextView::InputTextView(BRect frame, const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags)
|
||||
: BTextView(frame, name, textRect, resizingMode, flags),
|
||||
fWasFocus(false)
|
||||
{
|
||||
SetWordWrap(false);
|
||||
}
|
||||
|
||||
// destructor
|
||||
InputTextView::~InputTextView()
|
||||
{
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
InputTextView::MouseDown(BPoint where)
|
||||
{
|
||||
// enforce the behaviour of a typical BTextControl
|
||||
// only let the BTextView handle mouse up/down when
|
||||
// it already had focus
|
||||
fWasFocus = IsFocus();
|
||||
if (fWasFocus) {
|
||||
BTextView::MouseDown(where);
|
||||
} else {
|
||||
// forward click
|
||||
if (BView* view = Parent()) {
|
||||
view->MouseDown(ConvertToParent(where));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
InputTextView::MouseUp(BPoint where)
|
||||
{
|
||||
// enforce the behaviour of a typical BTextControl
|
||||
// only let the BTextView handle mouse up/down when
|
||||
// it already had focus
|
||||
if (fWasFocus)
|
||||
BTextView::MouseUp(where);
|
||||
}
|
||||
|
||||
// KeyDown
|
||||
void
|
||||
InputTextView::KeyDown(const char* bytes, int32 numBytes)
|
||||
{
|
||||
bool handled = true;
|
||||
if (numBytes > 0) {
|
||||
switch (bytes[0]) {
|
||||
case B_ESCAPE:
|
||||
// revert any typing changes
|
||||
RevertChanges();
|
||||
break;
|
||||
case B_TAB:
|
||||
// skip BTextView implementation
|
||||
BView::KeyDown(bytes, numBytes);
|
||||
// fall through
|
||||
case B_RETURN:
|
||||
ApplyChanges();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!handled)
|
||||
BTextView::KeyDown(bytes, numBytes);
|
||||
}
|
||||
|
||||
// MakeFocus
|
||||
void
|
||||
InputTextView::MakeFocus(bool focus)
|
||||
{
|
||||
if (focus != IsFocus()) {
|
||||
if (BView* view = Parent())
|
||||
view->Invalidate();
|
||||
BTextView::MakeFocus(focus);
|
||||
if (focus)
|
||||
SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke
|
||||
status_t
|
||||
InputTextView::Invoke(BMessage* message)
|
||||
{
|
||||
if (!message)
|
||||
message = Message();
|
||||
|
||||
if (message) {
|
||||
BMessage copy(*message);
|
||||
copy.AddInt64("when", system_time());
|
||||
copy.AddPointer("source", (BView*)this);
|
||||
return BInvoker::Invoke(©);
|
||||
}
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Select
|
||||
void
|
||||
InputTextView::Select(int32 start, int32 finish)
|
||||
{
|
||||
BTextView::Select(start, finish);
|
||||
|
||||
_CheckTextRect();
|
||||
}
|
||||
|
||||
// InsertText
|
||||
void
|
||||
InputTextView::InsertText(const char* inText, int32 inLength, int32 inOffset,
|
||||
const text_run_array* inRuns)
|
||||
{
|
||||
BTextView::InsertText(inText, inLength, inOffset, inRuns);
|
||||
|
||||
_CheckTextRect();
|
||||
}
|
||||
|
||||
// DeleteText
|
||||
void
|
||||
InputTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
||||
{
|
||||
BTextView::DeleteText(fromOffset, toOffset);
|
||||
|
||||
_CheckTextRect();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _CheckTextRect
|
||||
void
|
||||
InputTextView::_CheckTextRect()
|
||||
{
|
||||
// update text rect and make sure
|
||||
// the cursor/selection is in view
|
||||
BRect textRect(TextRect());
|
||||
float width = ceilf(StringWidth(Text()) + 2.0);
|
||||
if (textRect.Width() != width) {
|
||||
textRect.right = textRect.left + width;
|
||||
SetTextRect(textRect);
|
||||
ScrollToSelection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef INPUT_TEXT_VIEW_H
|
||||
#define INPUT_TEXT_VIEW_H
|
||||
|
||||
#include <Invoker.h>
|
||||
#include <TextView.h>
|
||||
|
||||
class InputTextView : public BTextView,
|
||||
public BInvoker {
|
||||
public:
|
||||
InputTextView(BRect frame,
|
||||
const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags);
|
||||
virtual ~InputTextView();
|
||||
|
||||
// BTextView interface
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseUp(BPoint where);
|
||||
|
||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||
virtual void MakeFocus(bool focus);
|
||||
|
||||
// BInvoker interface
|
||||
virtual status_t Invoke(BMessage* message = NULL);
|
||||
|
||||
// InputTextView
|
||||
virtual void RevertChanges() = 0;
|
||||
virtual void ApplyChanges() = 0;
|
||||
|
||||
protected:
|
||||
// BTextView
|
||||
virtual void Select(int32 start, int32 finish);
|
||||
|
||||
virtual void InsertText(const char* inText,
|
||||
int32 inLength,
|
||||
int32 inOffset,
|
||||
const text_run_array* inRuns);
|
||||
virtual void DeleteText(int32 fromOffset,
|
||||
int32 toOffset);
|
||||
|
||||
void _CheckTextRect();
|
||||
|
||||
bool fWasFocus;
|
||||
};
|
||||
|
||||
#endif // INPUT_TEXT_VIEW_H
|
||||
|
||||
|
||||
@@ -0,0 +1,908 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ListViews.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Cursor.h>
|
||||
#include <Entry.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <Messenger.h>
|
||||
#include <ScrollBar.h>
|
||||
#include <ScrollView.h>
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "cursors.h"
|
||||
|
||||
#define MAX_DRAG_HEIGHT 200.0
|
||||
#define ALPHA 170
|
||||
#define TEXT_OFFSET 5.0
|
||||
|
||||
enum {
|
||||
MSG_TICK = 'tick',
|
||||
};
|
||||
|
||||
// SimpleItem class
|
||||
SimpleItem::SimpleItem( const char *name )
|
||||
: BStringItem( name )
|
||||
{
|
||||
}
|
||||
|
||||
SimpleItem::~SimpleItem()
|
||||
{
|
||||
}
|
||||
|
||||
// SimpleItem::DrawItem
|
||||
void
|
||||
SimpleItem::Draw(BView *owner, BRect frame, uint32 flags)
|
||||
{
|
||||
DrawBackground(owner, frame, flags);
|
||||
// label
|
||||
owner->SetHighColor( 0, 0, 0, 255 );
|
||||
font_height fh;
|
||||
owner->GetFontHeight( &fh );
|
||||
const char* text = Text();
|
||||
BString truncatedString( text );
|
||||
owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
|
||||
frame.Width() - TEXT_OFFSET - 4.0 );
|
||||
float height = frame.Height();
|
||||
float textHeight = fh.ascent + fh.descent;
|
||||
BPoint textPoint;
|
||||
textPoint.x = frame.left + TEXT_OFFSET;
|
||||
textPoint.y = frame.top
|
||||
+ ceilf(height / 2.0 - textHeight / 2.0
|
||||
+ fh.ascent);
|
||||
owner->DrawString(truncatedString.String(), textPoint);
|
||||
}
|
||||
|
||||
// SimpleItem::DrawBackground
|
||||
void
|
||||
SimpleItem::DrawBackground(BView *owner, BRect frame, uint32 flags)
|
||||
{
|
||||
// stroke a blue frame around the item if it's focused
|
||||
if (flags & FLAGS_FOCUSED) {
|
||||
owner->SetLowColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
owner->StrokeRect(frame, B_SOLID_LOW);
|
||||
frame.InsetBy(1.0, 1.0);
|
||||
}
|
||||
// figure out bg-color
|
||||
rgb_color color = (rgb_color){ 255, 255, 255, 255 };
|
||||
if ( flags & FLAGS_TINTED_LINE )
|
||||
color = tint_color( color, 1.06 );
|
||||
// background
|
||||
if ( IsSelected() )
|
||||
color = tint_color( color, B_DARKEN_2_TINT );
|
||||
owner->SetLowColor( color );
|
||||
owner->FillRect( frame, B_SOLID_LOW );
|
||||
}
|
||||
|
||||
// DragSortableListView class
|
||||
DragSortableListView::DragSortableListView(BRect frame, const char* name,
|
||||
list_view_type type, uint32 resizingMode,
|
||||
uint32 flags)
|
||||
: BListView(frame, name, type, resizingMode, flags),
|
||||
fDropRect(0.0, 0.0, -1.0, -1.0),
|
||||
fMouseWheelFilter(NULL),
|
||||
fScrollPulse(NULL),
|
||||
fDropIndex(-1),
|
||||
fLastClickedItem(NULL),
|
||||
fScrollView(NULL),
|
||||
fDragCommand(B_SIMPLE_DATA),
|
||||
fFocusedIndex(-1)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
}
|
||||
|
||||
DragSortableListView::~DragSortableListView()
|
||||
{
|
||||
// delete fMouseWheelFilter;
|
||||
delete fScrollPulse;
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
DragSortableListView::AttachedToWindow()
|
||||
{
|
||||
if (!fMouseWheelFilter)
|
||||
fMouseWheelFilter = new MouseWheelFilter(this);
|
||||
Window()->AddCommonFilter(fMouseWheelFilter);
|
||||
|
||||
BListView::AttachedToWindow();
|
||||
|
||||
// work arround a bug in BListView
|
||||
BRect bounds = Bounds();
|
||||
BListView::FrameResized(bounds.Width(), bounds.Height());
|
||||
}
|
||||
|
||||
// DetachedFromWindow
|
||||
void
|
||||
DragSortableListView::DetachedFromWindow()
|
||||
{
|
||||
// Window()->RemoveCommonFilter(fMouseWheelFilter);
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
DragSortableListView::FrameResized(float width, float height)
|
||||
{
|
||||
BListView::FrameResized(width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
// MakeFocus
|
||||
void
|
||||
DragSortableListView::MakeFocus(bool focused)
|
||||
{
|
||||
if (focused != IsFocus()) {
|
||||
Invalidate();
|
||||
BListView::MakeFocus(focused);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Draw
|
||||
void
|
||||
DragSortableListView::Draw( BRect updateRect )
|
||||
{
|
||||
int32 firstIndex = IndexOf(updateRect.LeftTop());
|
||||
int32 lastIndex = IndexOf(updateRect.RightBottom());
|
||||
if (firstIndex >= 0) {
|
||||
if (lastIndex < firstIndex)
|
||||
lastIndex = CountItems() - 1;
|
||||
// update rect contains items
|
||||
BRect r = updateRect;
|
||||
for (int32 i = firstIndex; i <= lastIndex; i++) {
|
||||
r = ItemFrame(i);
|
||||
DrawListItem(this, i, r);
|
||||
}
|
||||
updateRect.top = r.bottom + 1.0;
|
||||
if (updateRect.IsValid()) {
|
||||
SetLowColor(255, 255, 255, 255);
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
} else {
|
||||
SetLowColor(255, 255, 255, 255);
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
// drop anticipation indication
|
||||
if (fDropRect.IsValid()) {
|
||||
SetHighColor(255, 0, 0, 255);
|
||||
StrokeRect(fDropRect);
|
||||
}
|
||||
/* // focus indication
|
||||
if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
// ScrollTo
|
||||
void
|
||||
DragSortableListView::ScrollTo(BPoint where)
|
||||
{
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
BListView::ScrollTo(where);
|
||||
}
|
||||
|
||||
// TargetedByScrollView
|
||||
void
|
||||
DragSortableListView::TargetedByScrollView(BScrollView* scrollView)
|
||||
{
|
||||
fScrollView = scrollView;
|
||||
BListView::TargetedByScrollView(scrollView);
|
||||
}
|
||||
|
||||
// InitiateDrag
|
||||
bool
|
||||
DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
|
||||
{
|
||||
// supress drag&drop while an item is focused
|
||||
if (fFocusedIndex >= 0)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
BListItem* item = ItemAt( CurrentSelection( 0 ) );
|
||||
if ( !item ) {
|
||||
// workarround a timing problem
|
||||
Select( index );
|
||||
item = ItemAt( index );
|
||||
}
|
||||
if ( item ) {
|
||||
// create drag message
|
||||
BMessage msg( fDragCommand );
|
||||
MakeDragMessage( &msg );
|
||||
// figure out drag rect
|
||||
float width = Bounds().Width();
|
||||
BRect dragRect(0.0, 0.0, width, -1.0);
|
||||
// figure out, how many items fit into our bitmap
|
||||
int32 numItems;
|
||||
bool fade = false;
|
||||
for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
|
||||
dragRect.bottom += ceilf( item->Height() ) + 1.0;
|
||||
if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
|
||||
fade = true;
|
||||
dragRect.bottom = MAX_DRAG_HEIGHT;
|
||||
numItems++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
|
||||
if ( dragBitmap && dragBitmap->IsValid() ) {
|
||||
if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
|
||||
dragBitmap->AddChild( v );
|
||||
dragBitmap->Lock();
|
||||
BRect itemBounds( dragRect) ;
|
||||
itemBounds.bottom = 0.0;
|
||||
// let all selected items, that fit into our drag_bitmap, draw
|
||||
for ( int32 i = 0; i < numItems; i++ ) {
|
||||
int32 index = CurrentSelection( i );
|
||||
BListItem* item = ItemAt( index );
|
||||
itemBounds.bottom = itemBounds.top + ceilf( item->Height() );
|
||||
if ( itemBounds.bottom > dragRect.bottom )
|
||||
itemBounds.bottom = dragRect.bottom;
|
||||
DrawListItem( v, index, itemBounds );
|
||||
itemBounds.top = itemBounds.bottom + 1.0;
|
||||
}
|
||||
// make a black frame arround the edge
|
||||
v->SetHighColor( 0, 0, 0, 255 );
|
||||
v->StrokeRect( v->Bounds() );
|
||||
v->Sync();
|
||||
|
||||
uint8 *bits = (uint8 *)dragBitmap->Bits();
|
||||
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
|
||||
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
|
||||
int32 bpr = dragBitmap->BytesPerRow();
|
||||
|
||||
if (fade) {
|
||||
for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = (height - y) << 1;
|
||||
}
|
||||
} else {
|
||||
for ( int32 y = 0; y < height; y++, bits += bpr ) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
}
|
||||
dragBitmap->Unlock();
|
||||
}
|
||||
} else {
|
||||
delete dragBitmap;
|
||||
dragBitmap = NULL;
|
||||
}
|
||||
if (dragBitmap)
|
||||
DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
|
||||
else
|
||||
DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
|
||||
|
||||
_SetDragMessage(&msg);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// WindowActivated
|
||||
void
|
||||
DragSortableListView::WindowActivated( bool active )
|
||||
{
|
||||
// workarround for buggy focus indication of BScrollView
|
||||
if ( BView* view = Parent() )
|
||||
view->Invalidate();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
DragSortableListView::MessageReceived(BMessage* message)
|
||||
{
|
||||
if (message->what == fDragCommand) {
|
||||
DragSortableListView *list = NULL;
|
||||
if ( message->FindPointer( "list", (void **)&list ) == B_OK
|
||||
&& list == this ) {
|
||||
int32 count = CountItems();
|
||||
if ( fDropIndex < 0 || fDropIndex > count )
|
||||
fDropIndex = count;
|
||||
BList items;
|
||||
int32 index;
|
||||
for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
|
||||
if ( BListItem* item = ItemAt(index) )
|
||||
items.AddItem( (void*)item );
|
||||
if ( items.CountItems() > 0 ) {
|
||||
if ( modifiers() & B_SHIFT_KEY )
|
||||
CopyItems( items, fDropIndex );
|
||||
else
|
||||
MoveItems( items, fDropIndex );
|
||||
}
|
||||
fDropIndex = -1;
|
||||
}
|
||||
} else {
|
||||
switch ( message->what ) {
|
||||
case MSG_TICK: {
|
||||
float scrollV = 0.0;
|
||||
BRect rect(Bounds());
|
||||
BPoint point;
|
||||
uint32 buttons;
|
||||
GetMouse(&point, &buttons, false);
|
||||
if (rect.Contains(point)) {
|
||||
// calculate the vertical scrolling offset
|
||||
float hotDist = rect.Height() * SCROLL_AREA;
|
||||
if (point.y > rect.bottom - hotDist)
|
||||
scrollV = hotDist - (rect.bottom - point.y);
|
||||
else if (point.y < rect.top + hotDist)
|
||||
scrollV = (point.y - rect.top) - hotDist;
|
||||
}
|
||||
// scroll
|
||||
if (scrollV != 0.0 && fScrollView) {
|
||||
if (BScrollBar* scrollBar = fScrollView->ScrollBar(B_VERTICAL)) {
|
||||
float value = scrollBar->Value();
|
||||
scrollBar->SetValue(scrollBar->Value() + scrollV);
|
||||
if (scrollBar->Value() != value) {
|
||||
// update mouse position
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// case B_MODIFIERS_CHANGED:
|
||||
// ModifiersChanged();
|
||||
// break;
|
||||
case B_MOUSE_WHEEL_CHANGED: {
|
||||
BListView::MessageReceived( message );
|
||||
BPoint point;
|
||||
uint32 buttons;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BListView::MessageReceived( message );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyDown
|
||||
void
|
||||
DragSortableListView::KeyDown( const char* bytes, int32 numBytes )
|
||||
{
|
||||
if ( numBytes < 1 )
|
||||
return;
|
||||
|
||||
if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
|
||||
RemoveSelected();
|
||||
|
||||
BListView::KeyDown( bytes, numBytes );
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
DragSortableListView::MouseDown( BPoint where )
|
||||
{
|
||||
int32 clicks = 1;
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
||||
int32 clickedIndex = -1;
|
||||
for (int32 i = 0; BListItem* item = ItemAt(i); i++) {
|
||||
if (ItemFrame(i).Contains(where)) {
|
||||
if (clicks == 2) {
|
||||
// only do something if user clicked the same item twice
|
||||
if (fLastClickedItem == item)
|
||||
DoubleClicked(i);
|
||||
} else {
|
||||
// remember last clicked item
|
||||
fLastClickedItem = item;
|
||||
}
|
||||
clickedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (clickedIndex == -1)
|
||||
fLastClickedItem = NULL;
|
||||
|
||||
BListItem* item = ItemAt(clickedIndex);
|
||||
if (ListType() == B_MULTIPLE_SELECTION_LIST
|
||||
&& item && (buttons & B_SECONDARY_MOUSE_BUTTON)) {
|
||||
if (item->IsSelected())
|
||||
Deselect(clickedIndex);
|
||||
else
|
||||
Select(clickedIndex, true);
|
||||
} else {
|
||||
BListView::MouseDown(where);
|
||||
}
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
|
||||
{
|
||||
if (msg && AcceptDragMessage(msg)) {
|
||||
switch (transit) {
|
||||
case B_ENTERED_VIEW:
|
||||
case B_INSIDE_VIEW: {
|
||||
// remember drag message
|
||||
// this is needed to react on modifier changes
|
||||
_SetDragMessage(msg);
|
||||
// set drop target through virtual function
|
||||
SetDropTargetRect(msg, where);
|
||||
// go into autoscrolling mode
|
||||
BRect r = Bounds();
|
||||
r.InsetBy(0.0, r.Height() * SCROLL_AREA);
|
||||
SetAutoScrolling(!r.Contains(where));
|
||||
break;
|
||||
}
|
||||
case B_EXITED_VIEW:
|
||||
// forget drag message
|
||||
_SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
// fall through
|
||||
case B_OUTSIDE_VIEW:
|
||||
_RemoveDropAnticipationRect();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_RemoveDropAnticipationRect();
|
||||
BListView::MouseMoved(where, transit, msg);
|
||||
_SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
|
||||
BCursor cursor(B_HAND_CURSOR);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
fLastMousePos = where;
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
DragSortableListView::MouseUp( BPoint where )
|
||||
{
|
||||
// remove drop mark
|
||||
_SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
|
||||
SetAutoScrolling(false);
|
||||
// be sure to forget drag message
|
||||
_SetDragMessage(NULL);
|
||||
BListView::MouseUp( where );
|
||||
|
||||
BCursor cursor(B_HAND_CURSOR);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
|
||||
// DrawItem
|
||||
void
|
||||
DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
|
||||
{
|
||||
DrawListItem( this, IndexOf( item ), itemFrame );
|
||||
/* if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
// MouseWheelChanged
|
||||
bool
|
||||
DragSortableListView::MouseWheelChanged(float x, float y)
|
||||
{
|
||||
BPoint where;
|
||||
uint32 buttons;
|
||||
GetMouse(&where, &buttons, false);
|
||||
if (Bounds().Contains(where))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetDragCommand
|
||||
void
|
||||
DragSortableListView::SetDragCommand(uint32 command)
|
||||
{
|
||||
fDragCommand = command;
|
||||
}
|
||||
|
||||
// ModifiersChaned
|
||||
void
|
||||
DragSortableListView::ModifiersChanged()
|
||||
{
|
||||
SetDropTargetRect(&fDragMessageCopy, fLastMousePos);
|
||||
}
|
||||
|
||||
// SetItemFocused
|
||||
void
|
||||
DragSortableListView::SetItemFocused(int32 index)
|
||||
{
|
||||
InvalidateItem(fFocusedIndex);
|
||||
InvalidateItem(index);
|
||||
fFocusedIndex = index;
|
||||
}
|
||||
|
||||
// AcceptDragMessage
|
||||
bool
|
||||
DragSortableListView::AcceptDragMessage(const BMessage* message) const
|
||||
{
|
||||
return message->what == fDragCommand;
|
||||
}
|
||||
|
||||
// SetDropTargetRect
|
||||
void
|
||||
DragSortableListView::SetDropTargetRect(const BMessage* message, BPoint where)
|
||||
|
||||
{
|
||||
if (AcceptDragMessage(message)) {
|
||||
bool copy = modifiers() & B_SHIFT_KEY;
|
||||
bool replaceAll = !message->HasPointer("list") && !copy;
|
||||
BRect r = Bounds();
|
||||
if (replaceAll) {
|
||||
r.bottom--; // compensate for scrollbar offset
|
||||
_SetDropAnticipationRect(r);
|
||||
fDropIndex = -1;
|
||||
} else {
|
||||
// offset where by half of item height
|
||||
r = ItemFrame(0);
|
||||
where.y += r.Height() / 2.0;
|
||||
|
||||
int32 index = IndexOf(where);
|
||||
if (index < 0)
|
||||
index = CountItems();
|
||||
_SetDropIndex(index);
|
||||
|
||||
const uchar* cursorData = copy ? kCopyCursor : B_HAND_CURSOR;
|
||||
BCursor cursor(cursorData);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAutoScrolling
|
||||
void
|
||||
DragSortableListView::SetAutoScrolling(bool enable)
|
||||
{
|
||||
if (fScrollPulse && enable)
|
||||
return;
|
||||
if (enable) {
|
||||
BMessenger messenger(this, Window());
|
||||
BMessage message(MSG_TICK);
|
||||
fScrollPulse = new BMessageRunner(messenger, &message, 40000LL);
|
||||
} else {
|
||||
delete fScrollPulse;
|
||||
fScrollPulse = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// DoesAutoScrolling
|
||||
bool
|
||||
DragSortableListView::DoesAutoScrolling() const
|
||||
{
|
||||
return fScrollPulse;
|
||||
}
|
||||
|
||||
// ScrollTo
|
||||
void
|
||||
DragSortableListView::ScrollTo(int32 index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index >= CountItems())
|
||||
index = CountItems() - 1;
|
||||
|
||||
if (BListItem* item = ItemAt(index)) {
|
||||
BRect itemFrame = ItemFrame(index);
|
||||
BRect bounds = Bounds();
|
||||
if (itemFrame.top < bounds.top) {
|
||||
ScrollTo(itemFrame.LeftTop());
|
||||
} else if (itemFrame.bottom > bounds.bottom) {
|
||||
ScrollTo(BPoint(0.0, itemFrame.bottom - bounds.Height()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MoveItems
|
||||
void
|
||||
DragSortableListView::MoveItems( BList& items, int32 index )
|
||||
{
|
||||
DeselectAll();
|
||||
// we remove the items while we look at them, the insertion index is decreased
|
||||
// when the items index is lower, so that we insert at the right spot after
|
||||
// removal
|
||||
BList removedItems;
|
||||
int32 count = items.CountItems();
|
||||
for ( int32 i = 0; i < count; i++ )
|
||||
{
|
||||
BListItem* item = (BListItem*)items.ItemAt( i );
|
||||
int32 removeIndex = IndexOf( item );
|
||||
if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) )
|
||||
{
|
||||
if ( removeIndex < index )
|
||||
index--;
|
||||
}
|
||||
// else ??? -> blow up
|
||||
}
|
||||
for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
|
||||
{
|
||||
if ( AddItem( item, index ) )
|
||||
{
|
||||
// after we're done, the newly inserted items will be selected
|
||||
Select( index, true );
|
||||
// next items will be inserted after this one
|
||||
index++;
|
||||
}
|
||||
else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// CopyItems
|
||||
void
|
||||
DragSortableListView::CopyItems( BList& items, int32 index )
|
||||
{
|
||||
DeselectAll();
|
||||
// by inserting the items after we copied all items first, we avoid
|
||||
// cloning an item we already inserted and messing everything up
|
||||
// in other words, don't touch the list before we know which items
|
||||
// need to be cloned
|
||||
BList clonedItems;
|
||||
int32 count = items.CountItems();
|
||||
for ( int32 i = 0; i < count; i++ )
|
||||
{
|
||||
BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) );
|
||||
if ( item && !clonedItems.AddItem( (void*)item ) )
|
||||
delete item;
|
||||
}
|
||||
for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
|
||||
{
|
||||
if ( AddItem( item, index ) )
|
||||
{
|
||||
// after we're done, the newly inserted items will be selected
|
||||
Select( index, true );
|
||||
// next items will be inserted after this one
|
||||
index++;
|
||||
}
|
||||
else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveItemList
|
||||
void
|
||||
DragSortableListView::RemoveItemList( BList& items )
|
||||
{
|
||||
int32 count = items.CountItems();
|
||||
for ( int32 i = 0; i < count; i++ )
|
||||
{
|
||||
BListItem* item = (BListItem*)items.ItemAt( i );
|
||||
if ( RemoveItem( item ) )
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveSelected
|
||||
void
|
||||
DragSortableListView::RemoveSelected()
|
||||
{
|
||||
// if (fFocusedIndex >= 0)
|
||||
// return;
|
||||
|
||||
BList items;
|
||||
for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
|
||||
items.AddItem( (void*)item );
|
||||
RemoveItemList( items );
|
||||
}
|
||||
|
||||
// CountSelectedItems
|
||||
int32
|
||||
DragSortableListView::CountSelectedItems() const
|
||||
{
|
||||
int32 count = 0;
|
||||
while ( CurrentSelection( count ) >= 0 )
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
// SelectAll
|
||||
void
|
||||
DragSortableListView::SelectAll()
|
||||
{
|
||||
Select(0, CountItems() - 1);
|
||||
}
|
||||
|
||||
// DeleteItem
|
||||
bool
|
||||
DragSortableListView::DeleteItem(int32 index)
|
||||
{
|
||||
BListItem* item = ItemAt(index);
|
||||
if (item && RemoveItem(item)) {
|
||||
delete item;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// _SetDropAnticipationRect
|
||||
void
|
||||
DragSortableListView::_SetDropAnticipationRect(BRect r)
|
||||
{
|
||||
if (fDropRect != r) {
|
||||
if (fDropRect.IsValid())
|
||||
Invalidate(fDropRect);
|
||||
fDropRect = r;
|
||||
if (fDropRect.IsValid())
|
||||
Invalidate(fDropRect);
|
||||
}
|
||||
}
|
||||
|
||||
// _SetDropIndex
|
||||
void
|
||||
DragSortableListView::_SetDropIndex(int32 index)
|
||||
{
|
||||
if (fDropIndex != index) {
|
||||
fDropIndex = index;
|
||||
if (fDropIndex >= 0) {
|
||||
int32 count = CountItems();
|
||||
if (fDropIndex == count) {
|
||||
BRect r;
|
||||
if (BListItem* item = ItemAt(count - 1)) {
|
||||
r = ItemFrame(count - 1);
|
||||
r.top = r.bottom;
|
||||
r.bottom = r.top + 1.0;
|
||||
} else {
|
||||
r = Bounds();
|
||||
r.bottom--; // compensate for scrollbars moved slightly out of window
|
||||
}
|
||||
_SetDropAnticipationRect(r);
|
||||
} else {
|
||||
BRect r = ItemFrame(fDropIndex);
|
||||
r.top--;
|
||||
r.bottom = r.top + 1.0;
|
||||
_SetDropAnticipationRect(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _RemoveDropAnticipationRect
|
||||
void
|
||||
DragSortableListView::_RemoveDropAnticipationRect()
|
||||
{
|
||||
_SetDropAnticipationRect(BRect(0.0, 0.0, -1.0, -1.0));
|
||||
// _SetDropIndex(-1);
|
||||
}
|
||||
|
||||
// _SetDragMessage
|
||||
void
|
||||
DragSortableListView::_SetDragMessage(const BMessage* message)
|
||||
{
|
||||
if (message)
|
||||
fDragMessageCopy = *message;
|
||||
else
|
||||
fDragMessageCopy.what = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SimpleListView class
|
||||
SimpleListView::SimpleListView( BRect frame, BMessage* selectionChangeMessage )
|
||||
: DragSortableListView( frame, "playlist listview",
|
||||
B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE
|
||||
| B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ),
|
||||
fSelectionChangeMessage( selectionChangeMessage )
|
||||
{
|
||||
}
|
||||
|
||||
// SimpleListView class
|
||||
SimpleListView::SimpleListView( BRect frame, const char* name,
|
||||
BMessage* selectionChangeMessage,
|
||||
list_view_type type,
|
||||
uint32 resizingMode, uint32 flags )
|
||||
: DragSortableListView( frame, name, type, resizingMode, flags ),
|
||||
fSelectionChangeMessage( selectionChangeMessage )
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
SimpleListView::~SimpleListView()
|
||||
{
|
||||
delete fSelectionChangeMessage;
|
||||
}
|
||||
|
||||
// layoutprefs
|
||||
minimax
|
||||
SimpleListView::layoutprefs()
|
||||
{
|
||||
mpm.mini.x = 30.0;
|
||||
mpm.maxi.x = 10000.0;
|
||||
mpm.mini.y = 50.0;
|
||||
mpm.maxi.y = 10000.0;
|
||||
mpm.weight = 1.0;
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
SimpleListView::layout(BRect frame)
|
||||
{
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
SimpleListView::MessageReceived( BMessage* message)
|
||||
{
|
||||
switch ( message->what ) {
|
||||
default:
|
||||
DragSortableListView::MessageReceived( message );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionChanged
|
||||
void
|
||||
SimpleListView::SelectionChanged()
|
||||
{
|
||||
BLooper* looper = Looper();
|
||||
if (fSelectionChangeMessage && looper) {
|
||||
BMessage message(*fSelectionChangeMessage);
|
||||
looper->PostMessage(&message);
|
||||
}
|
||||
}
|
||||
|
||||
// CloneItem
|
||||
BListItem*
|
||||
SimpleListView::CloneItem(int32 atIndex) const
|
||||
{
|
||||
BListItem* clone = NULL;
|
||||
if (SimpleItem* item = dynamic_cast<SimpleItem*>(ItemAt(atIndex)))
|
||||
clone = new SimpleItem(item->Text());
|
||||
return clone;
|
||||
}
|
||||
|
||||
// DrawListItem
|
||||
void
|
||||
SimpleListView::DrawListItem(BView* owner, int32 index, BRect frame) const
|
||||
{
|
||||
if (SimpleItem* item = dynamic_cast<SimpleItem*>(ItemAt(index))) {
|
||||
uint32 flags = FLAGS_NONE;
|
||||
if (index == fFocusedIndex)
|
||||
flags |= FLAGS_FOCUSED;
|
||||
if (index % 2)
|
||||
flags |= FLAGS_TINTED_LINE;
|
||||
item->Draw(owner, frame, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// MakeDragMessage
|
||||
void
|
||||
SimpleListView::MakeDragMessage(BMessage* message) const
|
||||
{
|
||||
if (message) {
|
||||
message->AddPointer( "list", (void*)dynamic_cast<const DragSortableListView*>(this));
|
||||
int32 index;
|
||||
for (int32 i = 0; (index = CurrentSelection(i)) >= 0; i++)
|
||||
message->AddInt32( "index", index );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef LIST_VIEWS_H
|
||||
#define LIST_VIEWS_H
|
||||
|
||||
#include <ListItem.h>
|
||||
#include <ListView.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include <layout.h>
|
||||
|
||||
#include "MouseWheelFilter.h"
|
||||
|
||||
enum
|
||||
{
|
||||
FLAGS_NONE = 0x00,
|
||||
FLAGS_TINTED_LINE = 0x01,
|
||||
FLAGS_FOCUSED = 0x02,
|
||||
};
|
||||
|
||||
// portion of the listviews height that triggers autoscrolling
|
||||
// when the mouse is over it with a dragmessage
|
||||
#define SCROLL_AREA 0.1
|
||||
|
||||
class BMessageRunner;
|
||||
class BMessageFilter;
|
||||
class InterfaceWindow;
|
||||
class BScrollView;
|
||||
|
||||
// SimpleItem
|
||||
class SimpleItem : public BStringItem
|
||||
{
|
||||
public:
|
||||
SimpleItem(const char* name);
|
||||
virtual ~SimpleItem();
|
||||
|
||||
virtual void Draw(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
virtual void DrawBackground(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
|
||||
// let the item know what's going on
|
||||
/* virtual void AttachedToListView(SimpleListView* owner);
|
||||
virtual void DetachedFromListView(SimpleListView* owner);
|
||||
|
||||
virtual void SetItemFrame(BRect frame);*/
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
// DragSortableListView
|
||||
class DragSortableListView : public MouseWheelTarget,
|
||||
public BListView {
|
||||
public:
|
||||
DragSortableListView( BRect frame,
|
||||
const char* name,
|
||||
list_view_type type
|
||||
= B_SINGLE_SELECTION_LIST,
|
||||
uint32 resizingMode
|
||||
= B_FOLLOW_LEFT
|
||||
| B_FOLLOW_TOP,
|
||||
uint32 flags
|
||||
= B_WILL_DRAW
|
||||
| B_NAVIGABLE
|
||||
| B_FRAME_EVENTS );
|
||||
virtual ~DragSortableListView();
|
||||
|
||||
// BListView
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void FrameResized(float width, float height);
|
||||
// virtual void MakeFocus(bool focused);
|
||||
virtual void Draw( BRect updateRect );
|
||||
virtual void ScrollTo(BPoint where);
|
||||
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||
virtual bool InitiateDrag( BPoint point, int32 index,
|
||||
bool wasSelected );
|
||||
virtual void MessageReceived( BMessage* message );
|
||||
virtual void KeyDown( const char* bytes, int32 numBytes );
|
||||
virtual void MouseDown( BPoint where );
|
||||
virtual void MouseMoved( BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage );
|
||||
virtual void MouseUp( BPoint where );
|
||||
virtual void WindowActivated( bool active );
|
||||
virtual void DrawItem( BListItem *item, BRect itemFrame,
|
||||
bool complete = false);
|
||||
|
||||
// MouseWheelTarget
|
||||
virtual bool MouseWheelChanged(float x, float y);
|
||||
|
||||
// DragSortableListView
|
||||
virtual void SetDragCommand(uint32 command);
|
||||
virtual void ModifiersChanged(); // called by window
|
||||
virtual void DoubleClicked(int32 index) {}
|
||||
|
||||
virtual void SetItemFocused(int32 index);
|
||||
|
||||
virtual bool AcceptDragMessage(const BMessage* message) const;
|
||||
virtual void SetDropTargetRect(const BMessage* message,
|
||||
BPoint where);
|
||||
|
||||
// autoscrolling
|
||||
void SetAutoScrolling(bool enable);
|
||||
bool DoesAutoScrolling() const;
|
||||
BScrollView* ScrollView() const
|
||||
{ return fScrollView; }
|
||||
void ScrollTo(int32 index);
|
||||
|
||||
virtual void MoveItems(BList& items, int32 toIndex);
|
||||
virtual void CopyItems(BList& items, int32 toIndex);
|
||||
virtual void RemoveItemList(BList& indices);
|
||||
void RemoveSelected(); // uses RemoveItemList()
|
||||
int32 CountSelectedItems() const;
|
||||
void SelectAll();
|
||||
virtual bool DeleteItem(int32 index);
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const = 0;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const = 0;
|
||||
virtual void MakeDragMessage(BMessage* message) const = 0;
|
||||
|
||||
private:
|
||||
void _RemoveDropAnticipationRect();
|
||||
void _SetDragMessage(const BMessage* message);
|
||||
|
||||
BRect fDropRect;
|
||||
BMessage fDragMessageCopy;
|
||||
BMessageFilter* fMouseWheelFilter;
|
||||
BMessageRunner* fScrollPulse;
|
||||
BPoint fLastMousePos;
|
||||
|
||||
protected:
|
||||
void _SetDropAnticipationRect(BRect r);
|
||||
void _SetDropIndex(int32 index);
|
||||
|
||||
int32 fDropIndex;
|
||||
BListItem* fLastClickedItem;
|
||||
BScrollView* fScrollView;
|
||||
uint32 fDragCommand;
|
||||
int32 fFocusedIndex;
|
||||
};
|
||||
|
||||
// SimpleListView
|
||||
class SimpleListView : public MView, public DragSortableListView {
|
||||
public:
|
||||
SimpleListView( BRect frame,
|
||||
BMessage* selectionChangeMessage = NULL );
|
||||
SimpleListView( BRect frame,
|
||||
const char* name,
|
||||
BMessage* selectionChangeMessage = NULL,
|
||||
list_view_type type
|
||||
= B_MULTIPLE_SELECTION_LIST,
|
||||
uint32 resizingMode
|
||||
= B_FOLLOW_ALL_SIDES,
|
||||
uint32 flags
|
||||
= B_WILL_DRAW | B_NAVIGABLE
|
||||
| B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE );
|
||||
~SimpleListView();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// BListView
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void SelectionChanged();
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const;
|
||||
virtual void MakeDragMessage(BMessage* message) const;
|
||||
|
||||
private:
|
||||
|
||||
BMessage* fSelectionChangeMessage;
|
||||
};
|
||||
|
||||
#endif // LIST_VIEWS_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef MOUSE_WHEEL_FILTER_H
|
||||
#define MOUSE_WHEEL_FILTER_H
|
||||
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
|
||||
class MouseWheelTarget {
|
||||
public:
|
||||
MouseWheelTarget()
|
||||
{
|
||||
}
|
||||
virtual ~MouseWheelTarget()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool MouseWheelChanged(float x, float y) = 0;
|
||||
};
|
||||
|
||||
class MouseWheelFilter : public BMessageFilter {
|
||||
public:
|
||||
MouseWheelFilter(MouseWheelTarget* target)
|
||||
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
||||
fTarget(target),
|
||||
fTargetHandler(dynamic_cast<BHandler*>(fTarget))
|
||||
{
|
||||
}
|
||||
virtual ~MouseWheelFilter()
|
||||
{
|
||||
}
|
||||
virtual filter_result Filter(BMessage* message, BHandler** target)
|
||||
{
|
||||
filter_result result = B_DISPATCH_MESSAGE;
|
||||
switch (message->what) {
|
||||
case B_MOUSE_WHEEL_CHANGED: {
|
||||
float x;
|
||||
float y;
|
||||
if (message->FindFloat("be:wheel_delta_x", &x) >= B_OK
|
||||
&& message->FindFloat("be:wheel_delta_y", &y) >= B_OK) {
|
||||
if (fTarget->MouseWheelChanged(x, y))
|
||||
//result = B_SKIP_MESSAGE;
|
||||
*target = fTargetHandler;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
MouseWheelTarget* fTarget;
|
||||
BHandler* fTargetHandler;
|
||||
};
|
||||
|
||||
#endif // MOUSE_WHEEL_FILTER_H
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "NummericalTextView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <String.h>
|
||||
|
||||
// constructor
|
||||
NummericalTextView::NummericalTextView(BRect frame, const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags)
|
||||
: InputTextView(frame, name, textRect, resizingMode, flags)
|
||||
{
|
||||
for (uint32 i = 0; i < '0'; i++) {
|
||||
DisallowChar(i);
|
||||
}
|
||||
for (uint32 i = '9' + 1; i < 255; i++) {
|
||||
DisallowChar(i);
|
||||
}
|
||||
AllowChar('-');
|
||||
}
|
||||
|
||||
// destructor
|
||||
NummericalTextView::~NummericalTextView()
|
||||
{
|
||||
}
|
||||
|
||||
// Invoke
|
||||
status_t
|
||||
NummericalTextView::Invoke(BMessage* message)
|
||||
{
|
||||
if (!message)
|
||||
message = Message();
|
||||
|
||||
if (message) {
|
||||
BMessage copy(*message);
|
||||
copy.AddInt32("be:value", IntValue());
|
||||
copy.AddFloat("float value", FloatValue());
|
||||
return InputTextView::Invoke(©);
|
||||
}
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RevertChanges
|
||||
void
|
||||
NummericalTextView::RevertChanges()
|
||||
{
|
||||
if (fFloatMode)
|
||||
SetValue(fFloatValueCache);
|
||||
else
|
||||
SetValue(fIntValueCache);
|
||||
}
|
||||
|
||||
// ApplyChanges
|
||||
void
|
||||
NummericalTextView::ApplyChanges()
|
||||
{
|
||||
int32 i = atoi(Text());
|
||||
float f = atof(Text());
|
||||
|
||||
if ((fFloatMode && f != fFloatValueCache) ||
|
||||
(!fFloatMode && i != fIntValueCache)) {
|
||||
Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// SetFloatMode
|
||||
void
|
||||
NummericalTextView::SetFloatMode(bool floatingPoint)
|
||||
{
|
||||
fFloatMode = floatingPoint;
|
||||
if (floatingPoint)
|
||||
AllowChar('.');
|
||||
else
|
||||
DisallowChar('.');
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
NummericalTextView::SetValue(int32 value)
|
||||
{
|
||||
BString helper;
|
||||
helper << value;
|
||||
SetText(helper.String());
|
||||
|
||||
// update caches
|
||||
IntValue();
|
||||
FloatValue();
|
||||
|
||||
if (IsFocus())
|
||||
SelectAll();
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
NummericalTextView::SetValue(float value)
|
||||
{
|
||||
BString helper;
|
||||
helper << value;
|
||||
SetText(helper.String());
|
||||
|
||||
// update caches
|
||||
IntValue();
|
||||
FloatValue();
|
||||
|
||||
if (IsFocus())
|
||||
SelectAll();
|
||||
}
|
||||
|
||||
// IntValue
|
||||
int32
|
||||
NummericalTextView::IntValue() const
|
||||
{
|
||||
fIntValueCache = atoi(Text());
|
||||
return fIntValueCache;
|
||||
}
|
||||
|
||||
// FloatValue
|
||||
float
|
||||
NummericalTextView::FloatValue() const
|
||||
{
|
||||
fFloatValueCache = atof(Text());
|
||||
return fFloatValueCache;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Select
|
||||
void
|
||||
NummericalTextView::Select(int32 start, int32 finish)
|
||||
{
|
||||
InputTextView::Select(start, finish);
|
||||
|
||||
_CheckMinusAllowed();
|
||||
_CheckDotAllowed();
|
||||
}
|
||||
|
||||
// InsertText
|
||||
void
|
||||
NummericalTextView::InsertText(const char* inText, int32 inLength, int32 inOffset,
|
||||
const text_run_array* inRuns)
|
||||
{
|
||||
InputTextView::InsertText(inText, inLength, inOffset, inRuns);
|
||||
|
||||
_CheckMinusAllowed();
|
||||
_CheckDotAllowed();
|
||||
}
|
||||
|
||||
// DeleteText
|
||||
void
|
||||
NummericalTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
||||
{
|
||||
InputTextView::DeleteText(fromOffset, toOffset);
|
||||
|
||||
_CheckMinusAllowed();
|
||||
_CheckDotAllowed();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _ToggleAllowChar
|
||||
void
|
||||
NummericalTextView::_ToggleAllowChar(char c)
|
||||
{
|
||||
const char* text = Text();
|
||||
if (text) {
|
||||
bool found = false;
|
||||
int32 selectionStart;
|
||||
int32 selectionEnd;
|
||||
GetSelection(&selectionStart, &selectionEnd);
|
||||
int32 pos = 0;
|
||||
while (text[pos]) {
|
||||
// skip selection
|
||||
if (selectionStart < selectionEnd
|
||||
&& pos == selectionStart) {
|
||||
pos = selectionEnd;
|
||||
}
|
||||
if (text[pos] == c) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (found)
|
||||
DisallowChar(c);
|
||||
else
|
||||
AllowChar(c);
|
||||
}
|
||||
}
|
||||
|
||||
// _CheckMinusAllowed
|
||||
void
|
||||
NummericalTextView::_CheckMinusAllowed()
|
||||
{
|
||||
_ToggleAllowChar('-');
|
||||
}
|
||||
|
||||
// _CheckDotAllowed
|
||||
void
|
||||
NummericalTextView::_CheckDotAllowed()
|
||||
{
|
||||
if (fFloatMode) {
|
||||
_ToggleAllowChar('.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef NUMMERICAL_TEXT_VIEW_H
|
||||
#define NUMMERICAL_TEXT_VIEW_H
|
||||
|
||||
#include "InputTextView.h"
|
||||
|
||||
class NummericalTextView : public InputTextView {
|
||||
public:
|
||||
NummericalTextView(BRect frame,
|
||||
const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags);
|
||||
virtual ~NummericalTextView();
|
||||
|
||||
// BInvoker interface
|
||||
virtual status_t Invoke(BMessage* message = NULL);
|
||||
|
||||
// InputTextView interface
|
||||
virtual void RevertChanges();
|
||||
virtual void ApplyChanges();
|
||||
|
||||
// NummericalTextView
|
||||
void SetFloatMode(bool floatingPoint);
|
||||
|
||||
void SetValue(int32 value);
|
||||
void SetValue(float value);
|
||||
int32 IntValue() const;
|
||||
float FloatValue() const;
|
||||
|
||||
protected:
|
||||
// BTextView
|
||||
virtual void Select(int32 start, int32 finish);
|
||||
|
||||
virtual void InsertText(const char* inText,
|
||||
int32 inLength,
|
||||
int32 inOffset,
|
||||
const text_run_array* inRuns);
|
||||
virtual void DeleteText(int32 fromOffset,
|
||||
int32 toOffset);
|
||||
|
||||
// NummericalTextView
|
||||
void _ToggleAllowChar(char c);
|
||||
void _CheckMinusAllowed();
|
||||
void _CheckDotAllowed();
|
||||
|
||||
bool fFloatMode;
|
||||
|
||||
mutable int32 fIntValueCache;
|
||||
mutable float fFloatValueCache;
|
||||
};
|
||||
|
||||
#endif // NUMMERICAL_TEXT_VIEW_H
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "StringTextView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// constructor
|
||||
StringTextView::StringTextView(BRect frame, const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags)
|
||||
: InputTextView(frame, name, textRect, resizingMode, flags),
|
||||
fStringCache("")
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
StringTextView::~StringTextView()
|
||||
{
|
||||
}
|
||||
|
||||
// Invoke
|
||||
status_t
|
||||
StringTextView::Invoke(BMessage* message)
|
||||
{
|
||||
if (!message)
|
||||
message = Message();
|
||||
|
||||
if (message) {
|
||||
BMessage copy(*message);
|
||||
copy.AddString("value", Value());
|
||||
return InputTextView::Invoke(©);
|
||||
}
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RevertChanges
|
||||
void
|
||||
StringTextView::RevertChanges()
|
||||
{
|
||||
SetValue(fStringCache.String());
|
||||
}
|
||||
|
||||
// ApplyChanges
|
||||
void
|
||||
StringTextView::ApplyChanges()
|
||||
{
|
||||
if (fStringCache != Text()) {
|
||||
Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
StringTextView::SetValue(const char* string)
|
||||
{
|
||||
SetText(string);
|
||||
|
||||
// update cache
|
||||
Value();
|
||||
|
||||
if (IsFocus())
|
||||
SelectAll();
|
||||
}
|
||||
|
||||
// Value
|
||||
const char*
|
||||
StringTextView::Value() const
|
||||
{
|
||||
fStringCache = Text();
|
||||
return fStringCache.String();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef STRING_TEXT_VIEW_H
|
||||
#define STRING_TEXT_VIEW_H
|
||||
|
||||
#include "InputTextView.h"
|
||||
|
||||
#include <String.h>
|
||||
|
||||
class StringTextView : public InputTextView {
|
||||
public:
|
||||
StringTextView(BRect frame,
|
||||
const char* name,
|
||||
BRect textRect,
|
||||
uint32 resizingMode,
|
||||
uint32 flags);
|
||||
virtual ~StringTextView();
|
||||
|
||||
// BInvoker interface
|
||||
virtual status_t Invoke(BMessage* message = NULL);
|
||||
|
||||
// InputTextView interface
|
||||
virtual void RevertChanges();
|
||||
virtual void ApplyChanges();
|
||||
|
||||
// StringTextView
|
||||
void SetValue(const char* string);
|
||||
const char* Value() const;
|
||||
|
||||
protected:
|
||||
mutable BString fStringCache;
|
||||
};
|
||||
|
||||
#endif // STRING_TEXT_VIEW_H
|
||||
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "SwatchView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Cursor.h>
|
||||
#include <Looper.h>
|
||||
#include <Message.h>
|
||||
#include <TypeConstants.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "cursors.h"
|
||||
#include "support.h"
|
||||
#include "support_ui.h"
|
||||
|
||||
#define DRAG_INIT_DIST 10.0
|
||||
|
||||
// constructor
|
||||
SwatchView::SwatchView(const char* name, BMessage* message,
|
||||
BHandler* target, rgb_color color,
|
||||
float width, float height)
|
||||
: BView(BRect(0.0, 0.0, 23.0, 17.0), name,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW),
|
||||
fColor(color),
|
||||
fTrackingStart(-1.0, -1.0),
|
||||
fActive(false),
|
||||
fDropInvokes(false),
|
||||
fClickMessage(message),
|
||||
fDroppedMessage(NULL),
|
||||
fTarget(target),
|
||||
fWidth(width),
|
||||
fHeight(height)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
SetHighColor(fColor);
|
||||
}
|
||||
|
||||
// destructor
|
||||
SwatchView::~SwatchView()
|
||||
{
|
||||
delete fClickMessage;
|
||||
delete fDroppedMessage;
|
||||
}
|
||||
|
||||
// layoutprefs
|
||||
minimax
|
||||
SwatchView::layoutprefs()
|
||||
{
|
||||
if (fWidth > 6.0 && fHeight > 6.0) {
|
||||
mpm.mini.x = mpm.maxi.x = fWidth;
|
||||
mpm.mini.y = mpm.maxi.y = fHeight;
|
||||
} else {
|
||||
mpm.mini.x = 6.0;
|
||||
mpm.maxi.x = 10000.0;
|
||||
mpm.mini.y = 6.0;
|
||||
mpm.maxi.y = 10000.0;
|
||||
}
|
||||
mpm.weight = 1.0;
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
SwatchView::layout(BRect frame)
|
||||
{
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
SwatchView::Draw(BRect updateRect)
|
||||
{
|
||||
// rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
// rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
// rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
// rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT);
|
||||
// rgb_color lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
rgb_color colorLight = tint_color(fColor, B_LIGHTEN_2_TINT);
|
||||
rgb_color colorShadow = tint_color(fColor, B_DARKEN_2_TINT);
|
||||
BRect r(Bounds());
|
||||
// _StrokeRect(r, background, background);
|
||||
// r.InsetBy(1.0, 1.0);
|
||||
/* _StrokeRect(r, lightShadow, light);
|
||||
r.InsetBy(1.0, 1.0);
|
||||
_StrokeRect(r, darkShadow, shadow);
|
||||
r.InsetBy(1.0, 1.0);*/
|
||||
_StrokeRect(r, colorLight, colorShadow);
|
||||
r.InsetBy(1.0, 1.0);
|
||||
FillRect(r);
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
SwatchView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case B_PASTE: {
|
||||
rgb_color color;
|
||||
if (restore_color_from_message(message,
|
||||
color) >= B_OK) {
|
||||
SetColor(color);
|
||||
_Invoke(fDroppedMessage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
SwatchView::MouseDown(BPoint where)
|
||||
{
|
||||
if (Bounds().Contains(where))
|
||||
fTrackingStart = where;
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
SwatchView::MouseUp(BPoint where)
|
||||
{
|
||||
if (Bounds().Contains(where)
|
||||
&& Bounds().Contains(fTrackingStart))
|
||||
_Invoke(fClickMessage);
|
||||
fTrackingStart.x = -1.0;
|
||||
fTrackingStart.y = -1.0;
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
SwatchView::MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage)
|
||||
{
|
||||
if (transit == B_ENTERED_VIEW) {
|
||||
BCursor cursor(kDropperCursor);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
if (Bounds().Contains(fTrackingStart)) {
|
||||
if (point_point_distance(where, fTrackingStart)
|
||||
> DRAG_INIT_DIST || transit == B_EXITED_VIEW) {
|
||||
_DragColor();
|
||||
fTrackingStart.x = -1.0;
|
||||
fTrackingStart.y = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetColor
|
||||
void
|
||||
SwatchView::SetColor(rgb_color color)
|
||||
{
|
||||
fColor = color;
|
||||
SetHighColor(fColor);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// SetClickedMessage
|
||||
void
|
||||
SwatchView::SetClickedMessage(BMessage* message)
|
||||
{
|
||||
delete fClickMessage;
|
||||
fClickMessage = message;
|
||||
}
|
||||
|
||||
// SetDroppedMessage
|
||||
void
|
||||
SwatchView::SetDroppedMessage(BMessage* message)
|
||||
{
|
||||
delete fDroppedMessage;
|
||||
fDroppedMessage = message;
|
||||
}
|
||||
|
||||
// _Invoke
|
||||
void
|
||||
SwatchView::_Invoke(const BMessage* _message)
|
||||
{
|
||||
if (_message) {
|
||||
BHandler* target = fTarget ? fTarget
|
||||
: dynamic_cast<BHandler*>(Window());
|
||||
BLooper* looper;
|
||||
if (target && (looper = target->Looper())) {
|
||||
BMessage message(*_message);
|
||||
message.AddPointer("be:source", (void*)this);
|
||||
message.AddInt64("be:when", system_time());
|
||||
message.AddBool("begin", true);
|
||||
store_color_in_message(&message, fColor);
|
||||
looper->PostMessage(&message, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _StrokeRect
|
||||
void
|
||||
SwatchView::_StrokeRect(BRect r, rgb_color leftTop,
|
||||
rgb_color rightBottom)
|
||||
{
|
||||
BeginLineArray(4);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), leftTop);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), leftTop);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), rightBottom);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), rightBottom);
|
||||
EndLineArray();
|
||||
}
|
||||
|
||||
// _DragColor
|
||||
void
|
||||
SwatchView::_DragColor()
|
||||
{
|
||||
BBitmap *bitmap = new BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_RGB32);
|
||||
BMessage message = make_color_drop_message(fColor, bitmap);
|
||||
|
||||
DragMessage(&message, bitmap, B_OP_ALPHA, BPoint(9.0, 9.0));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SWATCH_VIEW_H
|
||||
#define SWATCH_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include <layout.h>
|
||||
|
||||
enum {
|
||||
MSG_COLOR_DROP = 'PSTE',
|
||||
};
|
||||
|
||||
class SwatchView : public MView, public BView {
|
||||
public:
|
||||
SwatchView(const char* name,
|
||||
BMessage* message,
|
||||
BHandler* target,
|
||||
rgb_color color,
|
||||
float width = 24.0,
|
||||
float height = 24.0);
|
||||
virtual ~SwatchView();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// BView
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
|
||||
// SwatchView
|
||||
void SetColor(rgb_color color);
|
||||
rgb_color Color() const
|
||||
{ return fColor; }
|
||||
|
||||
void SetClickedMessage(BMessage* message);
|
||||
void SetDroppedMessage(BMessage* message);
|
||||
|
||||
private:
|
||||
void _Invoke(const BMessage* message);
|
||||
void _StrokeRect(BRect frame, rgb_color leftTop,
|
||||
rgb_color rightBottom);
|
||||
void _DragColor();
|
||||
|
||||
rgb_color fColor;
|
||||
BPoint fTrackingStart;
|
||||
bool fActive;
|
||||
bool fDropInvokes;
|
||||
|
||||
BMessage* fClickMessage;
|
||||
BMessage* fDroppedMessage;
|
||||
BHandler* fTarget;
|
||||
|
||||
float fWidth;
|
||||
float fHeight;
|
||||
};
|
||||
|
||||
#endif // SWATCH_VIEW_H
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef CURSORS_H
|
||||
#define CURSORS_H
|
||||
|
||||
const unsigned char kEmptyCursor[] = { 16, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
|
||||
const unsigned char kDropperCursor[] = { 16, 1, 14, 1,
|
||||
0x00, 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0xff,
|
||||
0x00, 0x7e, 0x00, 0xb8, 0x01, 0x18, 0x03, 0x28,
|
||||
0x04, 0x40, 0x0c, 0x80, 0x11, 0x00, 0x32, 0x00,
|
||||
0x44, 0x00, 0x48, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0xff,
|
||||
0x00, 0x7e, 0x00, 0xf8, 0x01, 0xf8, 0x03, 0xe8,
|
||||
0x07, 0xc0, 0x0f, 0x80, 0x1f, 0x00, 0x3e, 0x00,
|
||||
0x7c, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kHandCursor[] = { 16, 1, 8, 9,
|
||||
0x01, 0x80, 0x1a, 0x70, 0x26, 0x48, 0x26, 0x4a,
|
||||
0x12, 0x4d, 0x12, 0x49, 0x68, 0x09, 0x98, 0x01,
|
||||
0x88, 0x02, 0x40, 0x02, 0x20, 0x02, 0x20, 0x04,
|
||||
0x10, 0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08,
|
||||
|
||||
0x01, 0x80, 0x1b, 0xf0, 0x3f, 0xf8, 0x3f, 0xfa,
|
||||
0x1f, 0xff, 0x1f, 0xff, 0x6f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfc,
|
||||
0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8 };
|
||||
|
||||
const unsigned char kCopyCursor[] = { 16, 1, 1, 1,
|
||||
0x00, 0x00, 0x70, 0x00, 0x48, 0x00, 0x48, 0x00,
|
||||
0x27, 0xc0, 0x24, 0xb8, 0x12, 0x54, 0x10, 0x02,
|
||||
0x79, 0xe2, 0x99, 0x22, 0x85, 0x7a, 0x61, 0x4a,
|
||||
0x19, 0xca, 0x04, 0x4a, 0x02, 0x78, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x70, 0x00, 0x78, 0x00, 0x78, 0x00,
|
||||
0x3f, 0xc0, 0x3f, 0xf8, 0x1f, 0xfc, 0x1f, 0xfe,
|
||||
0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe,
|
||||
0x1f, 0xfe, 0x07, 0xfe, 0x03, 0xf8, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kStopCursor[] = { 16, 1, 8, 9,
|
||||
0x07, 0xe0, 0x18, 0x18, 0x20, 0x04, 0x47, 0xe2,
|
||||
0x48, 0x42, 0x90, 0x89, 0x91, 0x19, 0x92, 0x29,
|
||||
0x94, 0x49, 0x98, 0x89, 0x91, 0x09, 0x42, 0x12,
|
||||
0x47, 0xe2, 0x20, 0x04, 0x18, 0x18, 0x07, 0xe0,
|
||||
|
||||
0x07, 0xe0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe,
|
||||
0x78, 0x7e, 0xf0, 0xff, 0xf1, 0xff, 0xf3, 0xef,
|
||||
0xf7, 0xcf, 0xff, 0x8f, 0xff, 0x0f, 0x7e, 0x1e,
|
||||
0x7f, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x07, 0xe0 };
|
||||
|
||||
const unsigned char kGrabCursor[] = { 16, 1, 8, 9,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0d, 0xb0, 0x12, 0x4c, 0x10, 0x0a, 0x08, 0x02,
|
||||
0x18, 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x04,
|
||||
0x10, 0x04, 0x08, 0x08, 0x04, 0x08, 0x04, 0x08,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0d, 0xb0, 0x1f, 0xfc, 0x1f, 0xfe, 0x0f, 0xfe,
|
||||
0x1f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfe, 0x3f, 0xfc,
|
||||
0x1f, 0xfc, 0x0f, 0xf8, 0x07, 0xf8, 0x07, 0xf8 };
|
||||
|
||||
const unsigned char kFillBucketCursor[] = { 16, 1, 15, 2,
|
||||
0x00, 0xe0, 0x01, 0x10, 0x01, 0x90, 0x03, 0x50,
|
||||
0x0d, 0x30, 0x39, 0x10, 0x71, 0x08, 0xe2, 0x84,
|
||||
0xa1, 0x02, 0xb0, 0x01, 0xa8, 0x01, 0xa4, 0x02,
|
||||
0xa2, 0x04, 0xa1, 0x08, 0x60, 0x90, 0x20, 0x60,
|
||||
|
||||
0x00, 0xe0, 0x01, 0x10, 0x01, 0x90, 0x03, 0xd0,
|
||||
0x0f, 0xf0, 0x3f, 0xf0, 0x7f, 0xf8, 0xff, 0xfc,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xef, 0xff, 0xe7, 0xfe,
|
||||
0xe3, 0xfc, 0xe1, 0xf8, 0x60, 0xf0, 0x20, 0x60 };
|
||||
|
||||
// ----------- Transformation cursors
|
||||
|
||||
const unsigned char kMoveCursor[] = { 16, 1, 8, 8,
|
||||
0x01, 0x80, 0x02, 0x40, 0x04, 0x20, 0x08, 0x10,
|
||||
0x1e, 0x78, 0x2a, 0x54, 0x4e, 0x72, 0x80, 0x01,
|
||||
0x80, 0x01, 0x4e, 0x72, 0x2a, 0x54, 0x1e, 0x78,
|
||||
0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80,
|
||||
|
||||
0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0,
|
||||
0x1f, 0xf8, 0x3b, 0xdc, 0x7f, 0xfe, 0xff, 0xff,
|
||||
0xff, 0xff, 0x7f, 0xfe, 0x3b, 0xdc, 0x1f, 0xf8,
|
||||
0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80 };
|
||||
|
||||
const unsigned char kLeftRightCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x28, 0x14, 0x4f, 0xf2, 0x80, 0x01,
|
||||
0x80, 0x01, 0x4f, 0xf2, 0x28, 0x14, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x38, 0x1c, 0x7f, 0xfe, 0xff, 0xff,
|
||||
0xff, 0xff, 0x7f, 0xfe, 0x38, 0x1c, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kUpDownCursor[] = { 16, 1, 8, 8,
|
||||
0x01, 0x80, 0x02, 0x40, 0x04, 0x20, 0x08, 0x10,
|
||||
0x0e, 0x70, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40,
|
||||
0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x0e, 0x70,
|
||||
0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01, 0x80,
|
||||
|
||||
0x01, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0,
|
||||
0x0f, 0xf0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0,
|
||||
0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x0f, 0xf0,
|
||||
0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80 };
|
||||
|
||||
const unsigned char kLeftTopRightBottomCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x21, 0x00,
|
||||
0x22, 0x00, 0x21, 0x00, 0x28, 0x80, 0x34, 0x40,
|
||||
0x02, 0x2c, 0x01, 0x14, 0x00, 0x84, 0x00, 0x44,
|
||||
0x00, 0x84, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00,
|
||||
0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x80, 0x37, 0xc0,
|
||||
0x03, 0xec, 0x01, 0xfc, 0x00, 0xfc, 0x00, 0x7c,
|
||||
0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kLeftBottomRightTopCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x84,
|
||||
0x00, 0x44, 0x00, 0x84, 0x01, 0x14, 0x02, 0x2c,
|
||||
0x34, 0x40, 0x28, 0x80, 0x21, 0x00, 0x22, 0x00,
|
||||
0x21, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc,
|
||||
0x00, 0x7c, 0x00, 0xfc, 0x01, 0xfc, 0x03, 0xec,
|
||||
0x37, 0xc0, 0x3f, 0x80, 0x3f, 0x00, 0x3e, 0x00,
|
||||
0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kRotateLCursor[] = { 16, 1, 8, 8,
|
||||
0x01, 0x80, 0x03, 0x40, 0x0c, 0x20, 0x10, 0x10,
|
||||
0x23, 0x20, 0x25, 0x40, 0x49, 0x80, 0x48, 0x00,
|
||||
0x48, 0x00, 0x49, 0x80, 0x25, 0x40, 0x23, 0x20,
|
||||
0x10, 0x10, 0x0c, 0x20, 0x03, 0x40, 0x01, 0x80,
|
||||
|
||||
0x01, 0x80, 0x03, 0xc0, 0x0f, 0xe0, 0x1f, 0xf0,
|
||||
0x3f, 0xe0, 0x3d, 0xc0, 0x79, 0x80, 0x78, 0x00,
|
||||
0x78, 0x00, 0x79, 0x80, 0x3d, 0xc0, 0x3f, 0xe0,
|
||||
0x1f, 0xf0, 0x0f, 0xe0, 0x03, 0xc0, 0x01, 0x80 };
|
||||
|
||||
const unsigned char kRotateLBCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x3f, 0x00, 0x21, 0x00, 0x11, 0x00,
|
||||
0x21, 0x00, 0x25, 0x00, 0x4b, 0x00, 0x48, 0x00,
|
||||
0x48, 0x7e, 0x48, 0x42, 0x24, 0x22, 0x23, 0xc2,
|
||||
0x10, 0x0a, 0x0c, 0x36, 0x03, 0xc0, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x1f, 0x00,
|
||||
0x3f, 0x00, 0x3f, 0x00, 0x7b, 0x00, 0x78, 0x00,
|
||||
0x78, 0x7e, 0x78, 0x7e, 0x3c, 0x3e, 0x3f, 0xfe,
|
||||
0x1f, 0xfe, 0x0f, 0xf6, 0x03, 0xc0, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kRotateBCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x10, 0x08, 0x28, 0x14, 0x44, 0x22,
|
||||
0x82, 0x41, 0xce, 0x73, 0x48, 0x12, 0x24, 0x24,
|
||||
0x23, 0xc4, 0x10, 0x08, 0x0c, 0x30, 0x03, 0xc0,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x10, 0x08, 0x38, 0x1c, 0x7c, 0x3e,
|
||||
0xfe, 0x7f, 0xfe, 0x7f, 0x78, 0x1e, 0x3c, 0x3c,
|
||||
0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x03, 0xc0 };
|
||||
|
||||
const unsigned char kRotateRBCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x00, 0x84, 0x00, 0x88,
|
||||
0x00, 0x84, 0x00, 0xa4, 0x00, 0xd2, 0x00, 0x12,
|
||||
0x7e, 0x12, 0x42, 0x12, 0x44, 0x24, 0x43, 0xc4,
|
||||
0x50, 0x08, 0x6c, 0x30, 0x03, 0xc0, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xf8,
|
||||
0x00, 0xfc, 0x00, 0xfc, 0x00, 0xde, 0x00, 0x1e,
|
||||
0x7e, 0x1e, 0x7e, 0x1e, 0x7c, 0x3c, 0x7f, 0xfc,
|
||||
0x7f, 0xf8, 0x6f, 0xf0, 0x03, 0xc0, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kRotateRCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0xc0, 0x01, 0x60, 0x02, 0x18, 0x04, 0x04,
|
||||
0x02, 0x62, 0x01, 0x52, 0x00, 0xc9, 0x00, 0x09,
|
||||
0x00, 0x09, 0x00, 0xc9, 0x01, 0x52, 0x02, 0x62,
|
||||
0x04, 0x04, 0x02, 0x18, 0x01, 0x60, 0x00, 0xc0,
|
||||
|
||||
0x00, 0xc0, 0x01, 0xe0, 0x03, 0xf8, 0x07, 0xfc,
|
||||
0x03, 0xfe, 0x01, 0xde, 0x00, 0xcf, 0x00, 0x0f,
|
||||
0x00, 0x0f, 0x00, 0xcf, 0x01, 0xde, 0x03, 0xfe,
|
||||
0x07, 0xfc, 0x03, 0xf8, 0x01, 0xe0, 0x00, 0xc0 };
|
||||
|
||||
const unsigned char kRotateRTCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x03, 0xc0, 0x6c, 0x30, 0x50, 0x08,
|
||||
0x43, 0xc4, 0x44, 0x24, 0x42, 0x12, 0x7e, 0x12,
|
||||
0x00, 0x12, 0x00, 0xd2, 0x00, 0xa4, 0x00, 0x84,
|
||||
0x00, 0x88, 0x00, 0x84, 0x00, 0xfc, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x03, 0xc0, 0x6f, 0xf0, 0x7f, 0xf8,
|
||||
0x7f, 0xfc, 0x7c, 0x3c, 0x7e, 0x1e, 0x7e, 0x1e,
|
||||
0x00, 0x1e, 0x00, 0xde, 0x00, 0xfc, 0x00, 0xfc,
|
||||
0x00, 0xf8, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kRotateTCursor[] = { 16, 1, 8, 8,
|
||||
0x03, 0xc0, 0x0c, 0x30, 0x10, 0x08, 0x23, 0xc4,
|
||||
0x24, 0x24, 0x48, 0x12, 0xce, 0x73, 0x82, 0x41,
|
||||
0x44, 0x22, 0x28, 0x14, 0x10, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x03, 0xc0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc,
|
||||
0x3c, 0x3c, 0x78, 0x1e, 0xfe, 0x7f, 0xfe, 0x7f,
|
||||
0x7c, 0x3e, 0x38, 0x1c, 0x10, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kRotateLTCursor[] = { 16, 1, 8, 8,
|
||||
0x00, 0x00, 0x03, 0xc0, 0x0c, 0x36, 0x10, 0x0a,
|
||||
0x23, 0xc2, 0x24, 0x22, 0x48, 0x42, 0x48, 0x7e,
|
||||
0x48, 0x00, 0x4b, 0x00, 0x25, 0x00, 0x21, 0x00,
|
||||
0x11, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x03, 0xc0, 0x0f, 0xf6, 0x1f, 0xfe,
|
||||
0x3f, 0xfe, 0x3c, 0x3e, 0x78, 0x7e, 0x78, 0x7e,
|
||||
0x78, 0x00, 0x7b, 0x00, 0x3f, 0x00, 0x3f, 0x00,
|
||||
0x1f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00 };
|
||||
|
||||
// ------------- Path cursors
|
||||
|
||||
const unsigned char kPathNewCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x20, 0x08, 0x50, 0x09, 0x54,
|
||||
0x08, 0x88, 0x03, 0x06, 0x04, 0x01, 0x03, 0x06,
|
||||
0x00, 0x88, 0x01, 0x54, 0x00, 0x50, 0x00, 0x20,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0xa0, 0x1c, 0x70, 0x1d, 0x74,
|
||||
0x1c, 0xf8, 0x03, 0xfe, 0x07, 0xff, 0x03, 0xfe,
|
||||
0x00, 0xf8, 0x01, 0x74, 0x00, 0x70, 0x00, 0x20 };
|
||||
|
||||
const unsigned char kPathAddCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x78,
|
||||
0x08, 0x48, 0x01, 0xce, 0x01, 0x02, 0x01, 0x02,
|
||||
0x01, 0xce, 0x00, 0x48, 0x00, 0x78, 0x00, 0x00,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1c, 0x78,
|
||||
0x1c, 0x78, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe,
|
||||
0x01, 0xfe, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kPathRemoveCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
|
||||
0x08, 0x00, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02,
|
||||
0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1c, 0x00,
|
||||
0x1c, 0x00, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe,
|
||||
0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kPathInsertCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x09, 0xf0,
|
||||
0x09, 0x10, 0x01, 0x10, 0x00, 0xa0, 0x00, 0x40,
|
||||
0x1f, 0x1f, 0x11, 0x11, 0x1f, 0x1f, 0x00, 0x00,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1d, 0xf0,
|
||||
0x1d, 0xf0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
|
||||
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kPathMoveCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x20, 0x08, 0x50, 0x08, 0x88,
|
||||
0x09, 0x74, 0x02, 0x8a, 0x04, 0x89, 0x02, 0x8a,
|
||||
0x01, 0x74, 0x00, 0x88, 0x00, 0x50, 0x00, 0x20,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0xa0, 0x1c, 0x70, 0x1c, 0xf8,
|
||||
0x1d, 0x74, 0x03, 0x8e, 0x07, 0x8f, 0x03, 0x8e,
|
||||
0x01, 0x74, 0x00, 0xf8, 0x00, 0x70, 0x00, 0x20 };
|
||||
|
||||
const unsigned char kPathCloseCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x70, 0x08, 0x88,
|
||||
0x09, 0x04, 0x02, 0x72, 0x02, 0x52, 0x02, 0x72,
|
||||
0x01, 0x04, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x70, 0x1c, 0xf8,
|
||||
0x1d, 0xfc, 0x03, 0xfe, 0x03, 0xde, 0x03, 0xfe,
|
||||
0x01, 0xfc, 0x00, 0xf8, 0x00, 0x70, 0x00, 0x00 };
|
||||
|
||||
const unsigned char kPathSharpCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
|
||||
0x08, 0x00, 0x01, 0x8c, 0x02, 0x52, 0x02, 0x22,
|
||||
0x01, 0x04, 0x00, 0x88, 0x00, 0x50, 0x00, 0x20,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1c, 0x00,
|
||||
0x1c, 0x00, 0x01, 0x8c, 0x03, 0xde, 0x03, 0xfe,
|
||||
0x01, 0xfc, 0x00, 0xf8, 0x00, 0x70, 0x00, 0x20 };
|
||||
|
||||
const unsigned char kPathSelectCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
|
||||
0x09, 0x55, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
|
||||
0x01, 0x01, 0x00, 0x00, 0x01, 0x55, 0x00, 0x00,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1c, 0x00,
|
||||
0x1d, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x00, 0x00 };
|
||||
|
||||
// -------------------
|
||||
|
||||
const unsigned char kEllipseCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x78, 0x09, 0x86,
|
||||
0x09, 0x02, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
|
||||
0x02, 0x01, 0x01, 0x02, 0x01, 0x86, 0x00, 0x78,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x78, 0x1d, 0xfe,
|
||||
0x1d, 0xfe, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff,
|
||||
0x03, 0xff, 0x01, 0xfe, 0x01, 0xfe, 0x00, 0x78 };
|
||||
|
||||
const unsigned char kRectCursor[] = { 16, 1, 4, 4,
|
||||
0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0xe3, 0x80, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00,
|
||||
0x0b, 0xff, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
|
||||
0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x03, 0xff,
|
||||
|
||||
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0xe3, 0x80,
|
||||
0xe3, 0x80, 0xe3, 0x80, 0x1c, 0x00, 0x1c, 0x00,
|
||||
0x1f, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff,
|
||||
0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff };
|
||||
|
||||
#endif // CURSORS_H
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <InterfaceDefs.h>
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
|
||||
class EscapeFilter : public BMessageFilter {
|
||||
public:
|
||||
EscapeFilter(Panel* target)
|
||||
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
||||
fPanel(target)
|
||||
{
|
||||
}
|
||||
virtual ~EscapeFilter()
|
||||
{
|
||||
}
|
||||
virtual filter_result Filter(BMessage* message, BHandler** target)
|
||||
{
|
||||
filter_result result = B_DISPATCH_MESSAGE;
|
||||
switch (message->what) {
|
||||
case B_KEY_DOWN:
|
||||
case B_UNMAPPED_KEY_DOWN: {
|
||||
uint32 key;
|
||||
if (message->FindInt32("raw_char", (int32*)&key) >= B_OK) {
|
||||
if (key == B_ESCAPE) {
|
||||
result = B_SKIP_MESSAGE;
|
||||
fPanel->Cancel();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
Panel* fPanel;
|
||||
};
|
||||
|
||||
// constructor
|
||||
Panel::Panel(BRect frame, const char* title,
|
||||
window_type type, uint32 flags,
|
||||
uint32 workspace)
|
||||
: BWindow(frame, title, type, flags, workspace)
|
||||
{
|
||||
_InstallFilter();
|
||||
}
|
||||
|
||||
// constructor
|
||||
Panel::Panel(BRect frame, const char* title,
|
||||
window_look look, window_feel feel,
|
||||
uint32 flags, uint32 workspace)
|
||||
: BWindow(frame, title, look, feel, flags, workspace)
|
||||
{
|
||||
_InstallFilter();
|
||||
}
|
||||
|
||||
// destructor
|
||||
Panel::~Panel()
|
||||
{
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
Panel::Cancel()
|
||||
{
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
}
|
||||
|
||||
// _InstallFilter
|
||||
void
|
||||
Panel::_InstallFilter()
|
||||
{
|
||||
AddCommonFilter(new EscapeFilter(this));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef PANEL_H
|
||||
#define PANEL_H
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class Panel : public BWindow {
|
||||
public:
|
||||
Panel(BRect frame,
|
||||
const char* title,
|
||||
window_type type,
|
||||
uint32 flags,
|
||||
uint32 workspace = B_CURRENT_WORKSPACE);
|
||||
Panel(BRect frame,
|
||||
const char* title,
|
||||
window_look look,
|
||||
window_feel feel,
|
||||
uint32 flags,
|
||||
uint32 workspace = B_CURRENT_WORKSPACE);
|
||||
virtual ~Panel();
|
||||
|
||||
// Panel
|
||||
virtual void Cancel();
|
||||
|
||||
private:
|
||||
void _InstallFilter();
|
||||
|
||||
};
|
||||
|
||||
#endif // PANEL_H
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "InputSlider.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
|
||||
#include "NummericalTextView.h"
|
||||
|
||||
|
||||
// MouseDownFilter
|
||||
|
||||
class NumericInputFilter : public BMessageFilter {
|
||||
public:
|
||||
NumericInputFilter(InputSlider* slider);
|
||||
|
||||
virtual filter_result Filter(BMessage*, BHandler** target);
|
||||
|
||||
private:
|
||||
InputSlider* fSlider;
|
||||
};
|
||||
|
||||
// constructor
|
||||
NumericInputFilter::NumericInputFilter(InputSlider* slider)
|
||||
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
||||
fSlider(slider)
|
||||
{
|
||||
}
|
||||
|
||||
// Filter
|
||||
filter_result
|
||||
NumericInputFilter::Filter(BMessage* msg, BHandler** target)
|
||||
{
|
||||
filter_result result = B_DISPATCH_MESSAGE;
|
||||
switch (msg->what)
|
||||
{
|
||||
case B_KEY_DOWN:
|
||||
case B_KEY_UP:
|
||||
{
|
||||
msg->PrintToStream();
|
||||
const char *string;
|
||||
if (msg->FindString("bytes", &string) == B_OK) {
|
||||
while (*string != 0) {
|
||||
if (*string < '0' || *string > '9') {
|
||||
|
||||
if (*string != '-') {
|
||||
result = B_SKIP_MESSAGE;
|
||||
}
|
||||
}
|
||||
string++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
if (fWindow) {
|
||||
if (BView* view = dynamic_cast<BView*>(*target)) {
|
||||
BPoint point;
|
||||
if (message->FindPoint("where", &point) == B_OK) {
|
||||
if (!fWindow->Frame().Contains(view->ConvertToScreen(point)))
|
||||
*target = fWindow;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
return result;
|
||||
}
|
||||
|
||||
// constructor
|
||||
InputSlider::InputSlider(const char* name, const char* label,
|
||||
BMessage* model, BHandler* target,
|
||||
int32 min, int32 max, int32 value,
|
||||
const char* formatString)
|
||||
: PopupSlider(name, label, model, target, min, max, value, formatString),
|
||||
fTextView(new NummericalTextView(BRect(0, 0 , 20, 20),
|
||||
"input",
|
||||
BRect(5, 5, 15, 15),
|
||||
B_FOLLOW_NONE,
|
||||
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE))
|
||||
//fTextViewFilter(dynamic_cast<BMessageFilter*>(new NumericInputFilter(this)))
|
||||
{
|
||||
// prepare fTextView
|
||||
fTextView->SetWordWrap(false);
|
||||
fTextView->SetViewColor(255,255,255,0);
|
||||
fTextView->SetValue(Value());
|
||||
//fTextView->AddFilter(fTextViewFilter);
|
||||
AddChild(fTextView);
|
||||
}
|
||||
|
||||
// destructor
|
||||
InputSlider::~InputSlider()
|
||||
{
|
||||
//delete fTextViewFilter;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
InputSlider::layout(BRect frame)
|
||||
{
|
||||
PopupSlider::layout(frame);
|
||||
|
||||
frame = SliderFrame();
|
||||
|
||||
frame.right -= 10.0;
|
||||
frame.InsetBy(2, 2);
|
||||
|
||||
fTextView->MoveTo(frame.LeftTop());
|
||||
fTextView->ResizeTo(frame.Width(), frame.Height());
|
||||
|
||||
BRect textRect(fTextView->Bounds());
|
||||
textRect.InsetBy(1, 1);
|
||||
fTextView->SetTextRect(textRect);
|
||||
|
||||
fTextView->SetAlignment(B_ALIGN_CENTER);
|
||||
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
InputSlider::MouseDown(BPoint where)
|
||||
{
|
||||
if (fTextView->Frame().Contains(where))
|
||||
return;
|
||||
|
||||
fTextView->MakeFocus(true);
|
||||
|
||||
if (SliderFrame().Contains(where)) {
|
||||
SetValue(fTextView->IntValue());
|
||||
PopupSlider::MouseDown(where);
|
||||
}
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
InputSlider::SetEnabled(bool enable)
|
||||
{
|
||||
PopupSlider::SetEnabled(enable);
|
||||
|
||||
// fTextView->SetEnabled(enable);
|
||||
}
|
||||
|
||||
// ValueChanged
|
||||
void
|
||||
InputSlider::ValueChanged(int32 newValue)
|
||||
{
|
||||
PopupSlider::ValueChanged(newValue);
|
||||
|
||||
// change fTextView's value
|
||||
if (LockLooper()) {
|
||||
fTextView->SetValue(Value());
|
||||
UnlockLooper();
|
||||
}
|
||||
}
|
||||
|
||||
// DrawSlider
|
||||
void
|
||||
InputSlider::DrawSlider(BRect frame, bool enabled)
|
||||
{
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color lightShadow;
|
||||
rgb_color midShadow;
|
||||
rgb_color darkShadow;
|
||||
rgb_color light;
|
||||
if (enabled) {
|
||||
lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
midShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||
light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
} else {
|
||||
lightShadow = background;
|
||||
midShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
light = tint_color(background, B_LIGHTEN_1_TINT);
|
||||
}
|
||||
|
||||
// frame around text view
|
||||
BRect r(frame);
|
||||
BeginLineArray(16);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), lightShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), lightShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), light);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), light);
|
||||
|
||||
r = fTextView->Frame().InsetByCopy(-1, -1);
|
||||
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), darkShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), darkShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), background);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), background);
|
||||
|
||||
r.left = r.right + 1;
|
||||
r.right = frame.right - 1;
|
||||
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top + 1.0), midShadow);
|
||||
AddLine(BPoint(r.left, r.top),
|
||||
BPoint(r.right, r.top), darkShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), midShadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), midShadow);
|
||||
|
||||
r.InsetBy(1, 1);
|
||||
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), light);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), light);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), lightShadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), lightShadow);
|
||||
EndLineArray();
|
||||
|
||||
r.InsetBy(1, 1);
|
||||
SetLowColor(background);
|
||||
FillRect(r, B_SOLID_LOW);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef INPUT_SLIDER_H
|
||||
#define INPUT_SLIDER_H
|
||||
|
||||
#include "PopupSlider.h"
|
||||
|
||||
class NummericalTextView;
|
||||
class BMessageFilter;
|
||||
|
||||
class InputSlider : public PopupSlider {
|
||||
public:
|
||||
InputSlider(const char* name = NULL,
|
||||
const char* label = NULL,
|
||||
BMessage* model = NULL,
|
||||
BHandler* target = NULL,
|
||||
int32 min = 0,
|
||||
int32 max = 100,
|
||||
int32 value = 0,
|
||||
const char* formatString = "%ld");
|
||||
virtual ~InputSlider();
|
||||
|
||||
// MView
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// BView
|
||||
virtual void MouseDown(BPoint where);
|
||||
|
||||
// PopupSlider
|
||||
void SetEnabled(bool enabled);
|
||||
// override this to take some action
|
||||
virtual void ValueChanged(int32 newValue);
|
||||
virtual void DrawSlider(BRect frame, bool enabled);
|
||||
|
||||
private:
|
||||
|
||||
NummericalTextView* fTextView;
|
||||
BMessageFilter* fTextViewFilter;
|
||||
};
|
||||
|
||||
#endif // INPUT_SLIDER_H
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PopupControl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <Screen.h>
|
||||
|
||||
#include "PopupView.h"
|
||||
#include "PopupWindow.h"
|
||||
|
||||
// constructor
|
||||
PopupControl::PopupControl(const char* name, PopupView* child)
|
||||
: BView(BRect(0.0f, 0.0f, 10.0f, 10.0f),
|
||||
name, B_FOLLOW_NONE, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
||||
fPopupWindow(NULL),
|
||||
fPopupChild(child),
|
||||
fHPopupAlignment(0.5),
|
||||
fVPopupAlignment(0.5)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
PopupControl::~PopupControl()
|
||||
{
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
PopupControl::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_POPUP_SHOWN:
|
||||
PopupShown();
|
||||
break;
|
||||
case MSG_POPUP_HIDDEN:
|
||||
bool canceled;
|
||||
if (message->FindBool("canceled", &canceled) != B_OK)
|
||||
canceled = true;
|
||||
PopupHidden(canceled);
|
||||
HidePopup();
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SetPopupLocation
|
||||
void
|
||||
PopupControl::SetPopupAlignment(float hPopupAlignment, float vPopupAlignment)
|
||||
{
|
||||
fHPopupAlignment = hPopupAlignment;
|
||||
fVPopupAlignment = vPopupAlignment;
|
||||
}
|
||||
|
||||
// SetPopupLocation
|
||||
//
|
||||
// overrides Alignment
|
||||
void
|
||||
PopupControl::SetPopupLocation(BPoint leftTop)
|
||||
{
|
||||
fPopupLeftTop = leftTop;
|
||||
fHPopupAlignment = -1.0;
|
||||
fVPopupAlignment = -1.0;
|
||||
}
|
||||
|
||||
// ShowPopup
|
||||
void
|
||||
PopupControl::ShowPopup(BPoint* offset)
|
||||
{
|
||||
if (!fPopupWindow) {
|
||||
fPopupWindow = new PopupWindow(fPopupChild, this);
|
||||
fPopupWindow->RecalcSize();
|
||||
BRect frame(fPopupWindow->Frame());
|
||||
|
||||
BPoint leftLocation;
|
||||
if (fHPopupAlignment >= 0.0 && fVPopupAlignment >= 0.0) {
|
||||
leftLocation = ConvertToScreen(Bounds().LeftTop());
|
||||
leftLocation.x -= fPopupWindow->Frame().Width() + 1.0;
|
||||
leftLocation.y -= fPopupWindow->Frame().Height() + 1.0;
|
||||
float totalWidth = Bounds().Width() + fPopupWindow->Frame().Width();
|
||||
float totalHeight = Bounds().Height() + fPopupWindow->Frame().Height();
|
||||
leftLocation.x += fHPopupAlignment * totalWidth;
|
||||
leftLocation.y += fHPopupAlignment * totalHeight;
|
||||
} else
|
||||
leftLocation = ConvertToScreen(fPopupLeftTop);
|
||||
|
||||
frame.OffsetTo(leftLocation);
|
||||
BScreen screen(fPopupWindow);
|
||||
BRect dest(screen.Frame());
|
||||
// check if too big
|
||||
if (frame.Width() > dest.Width())
|
||||
frame.right = frame.left + dest.Width();
|
||||
if (frame.Height() > dest.Height())
|
||||
frame.bottom = frame.top + dest.Height();
|
||||
// check if out of screen
|
||||
float hOffset = 0.0;
|
||||
float vOffset = 0.0;
|
||||
if (frame.bottom > dest.bottom)
|
||||
vOffset = dest.bottom - frame.bottom;
|
||||
if (frame.top < dest.top)
|
||||
vOffset = dest.top - frame.top;
|
||||
if (frame.right > dest.right)
|
||||
hOffset = dest.right - frame.right;
|
||||
if (frame.left < dest.left)
|
||||
hOffset = dest.left - frame.left;
|
||||
// finally move/resize our popup window
|
||||
frame.OffsetBy(hOffset, vOffset);
|
||||
if (offset) {
|
||||
offset->x += hOffset;
|
||||
offset->y += vOffset;
|
||||
}
|
||||
fPopupWindow->MoveTo(frame.LeftTop());
|
||||
fPopupWindow->ResizeTo(frame.Width(), frame.Height());
|
||||
fPopupWindow->Show();
|
||||
}
|
||||
}
|
||||
|
||||
// HidePopup
|
||||
void
|
||||
PopupControl::HidePopup()
|
||||
{
|
||||
if (fPopupWindow) {
|
||||
fPopupWindow->Lock();
|
||||
fPopupChild->SetPopupWindow(NULL);
|
||||
fPopupWindow->RemoveChild(fPopupChild);
|
||||
fPopupWindow->Quit();
|
||||
fPopupWindow = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// PopupShown
|
||||
void
|
||||
PopupControl::PopupShown()
|
||||
{
|
||||
}
|
||||
|
||||
// PopupHidden
|
||||
void
|
||||
PopupControl::PopupHidden(bool canceled)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef POPUP_CONTROL_H
|
||||
#define POPUP_CONTROL_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include <layout.h>
|
||||
|
||||
class PopupView;
|
||||
class PopupWindow;
|
||||
|
||||
class PopupControl : public MView, public BView {
|
||||
public:
|
||||
PopupControl(const char* name,
|
||||
PopupView* child);
|
||||
virtual ~PopupControl();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs() = 0;
|
||||
virtual BRect layout(BRect frame) = 0;
|
||||
|
||||
// BHandler
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// PopupControl
|
||||
void SetPopupAlignment(float hPopupAlignment,
|
||||
float vPopupAlignment);
|
||||
void SetPopupLocation(BPoint leftTop);
|
||||
|
||||
// "offset" will be modified if the popup
|
||||
// window had to be moved in order to
|
||||
// show entirely on screen
|
||||
virtual void ShowPopup(BPoint* offset = NULL);
|
||||
virtual void HidePopup();
|
||||
|
||||
virtual void PopupShown();
|
||||
virtual void PopupHidden(bool canceled);
|
||||
|
||||
private:
|
||||
PopupWindow* fPopupWindow;
|
||||
PopupView* fPopupChild;
|
||||
float fHPopupAlignment;
|
||||
float fVPopupAlignment;
|
||||
BPoint fPopupLeftTop;
|
||||
};
|
||||
|
||||
|
||||
#endif // POPUP_CONTROL_H
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PopupSlider.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include <MDividable.h>
|
||||
#include <MWindow.h>
|
||||
|
||||
#include "SliderView.h"
|
||||
|
||||
// constructor
|
||||
PopupSlider::PopupSlider(const char* name, const char* label,
|
||||
BMessage* model, BHandler* target,
|
||||
int32 min, int32 max, int32 value,
|
||||
const char* formatString)
|
||||
: PopupControl(name, fSlider = new SliderView(this, min, max, value,
|
||||
formatString)),
|
||||
MDividable(),
|
||||
fModel(model),
|
||||
fPressModel(NULL),
|
||||
fReleaseModel(NULL),
|
||||
fTarget(target),
|
||||
fLabel(label),
|
||||
fSliderButtonRect(0.0, 0.0, -1.0, -1.0),
|
||||
fEnabled(true),
|
||||
fTracking(false)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
}
|
||||
|
||||
// destructor
|
||||
PopupSlider::~PopupSlider()
|
||||
{
|
||||
delete fModel;
|
||||
if (BWindow* window = fSlider->Window()) {
|
||||
window->Lock();
|
||||
window->RemoveChild(fSlider);
|
||||
window->Unlock();
|
||||
}
|
||||
delete fSlider;
|
||||
}
|
||||
|
||||
// layoutprefs
|
||||
minimax
|
||||
PopupSlider::layoutprefs()
|
||||
{
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
font_height fh;
|
||||
font.GetHeight(&fh);
|
||||
float labelHeight = 2.0 + ceilf(fh.ascent + fh.descent) + 2.0;
|
||||
float sliderWidth, sliderHeight;
|
||||
SliderView::GetSliderButtonDimensions(Max(), FormatString(), &font,
|
||||
sliderWidth, sliderHeight);
|
||||
|
||||
float height = labelHeight > sliderHeight + 2.0 ?
|
||||
labelHeight : sliderHeight + 2.0;
|
||||
|
||||
float minLabelWidth = LabelWidth();
|
||||
if (rolemodel)
|
||||
labelwidth = rolemodel->LabelWidth();
|
||||
labelwidth = minLabelWidth > labelwidth ? minLabelWidth : labelwidth;
|
||||
|
||||
fSliderButtonRect.left = labelwidth;
|
||||
fSliderButtonRect.right = fSliderButtonRect.left + sliderWidth + 2.0;
|
||||
fSliderButtonRect.top = floorf(height / 2.0 - (sliderHeight + 2.0) / 2.0);
|
||||
fSliderButtonRect.bottom = fSliderButtonRect.top + sliderHeight + 2.0;
|
||||
|
||||
fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
|
||||
fSliderButtonRect.top);
|
||||
|
||||
mpm.mini.x = labelwidth + fSliderButtonRect.Width() + 1.0;
|
||||
mpm.maxi.x = 10000.0;
|
||||
mpm.mini.y = mpm.maxi.y = height + 1.0;
|
||||
|
||||
mpm.weight = 1.0;
|
||||
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
PopupSlider::layout(BRect frame)
|
||||
{
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
|
||||
fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
|
||||
fSliderButtonRect.top);
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
PopupSlider::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
PopupControl::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
PopupSlider::AttachedToWindow()
|
||||
{
|
||||
fSliderButtonRect.OffsetTo(Bounds().right - fSliderButtonRect.Width(),
|
||||
fSliderButtonRect.top);
|
||||
PopupControl::AttachedToWindow();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
PopupSlider::Draw(BRect updateRect)
|
||||
{
|
||||
bool enabled = IsEnabled();
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color black;
|
||||
if (enabled) {
|
||||
black = tint_color(background, B_DARKEN_MAX_TINT);
|
||||
} else {
|
||||
black = tint_color(background, B_DISABLED_LABEL_TINT);
|
||||
}
|
||||
// draw label
|
||||
BRect r(Bounds());
|
||||
r.right = fSliderButtonRect.left - 1.0;
|
||||
font_height fh;
|
||||
GetFontHeight(&fh);
|
||||
BPoint textPoint(0.0, (r.top + r.bottom) / 2.0 + fh.ascent / 2.0);
|
||||
SetLowColor(background);
|
||||
SetHighColor(black);
|
||||
FillRect(r, B_SOLID_LOW);
|
||||
DrawString(fLabel.String(), textPoint);
|
||||
// draw slider button
|
||||
DrawSlider(fSliderButtonRect, enabled);
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
PopupSlider::MouseDown(BPoint where)
|
||||
{
|
||||
if (fEnabled && fSliderButtonRect.Contains(where) &&
|
||||
!fSlider->LockLooper()) {
|
||||
|
||||
SetPopupLocation(BPoint(fSliderButtonRect.left + 1.0
|
||||
- fSlider->ButtonOffset(),
|
||||
-5.0));
|
||||
where.x -= fSliderButtonRect.left + 1.0;
|
||||
fSlider->SetDragOffset(where.x);
|
||||
// just to be on the safe side (avoid a dead lock)
|
||||
fTracking = true;
|
||||
ShowPopup(&where);
|
||||
// fSlider->SetDragOffset(where.x);
|
||||
}
|
||||
}
|
||||
|
||||
// PopupShown
|
||||
void
|
||||
PopupSlider::PopupShown()
|
||||
{
|
||||
TriggerValueChanged(fPressModel);
|
||||
fTracking = true;
|
||||
}
|
||||
|
||||
// PopupHidden
|
||||
void
|
||||
PopupSlider::PopupHidden(bool canceled)
|
||||
{
|
||||
TriggerValueChanged(fReleaseModel);
|
||||
fTracking = false;
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
PopupSlider::SetValue(int32 value)
|
||||
{
|
||||
if (!fTracking) {
|
||||
/* if (fSlider->LockLooper()) {
|
||||
fSlider->SetValue(value);
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
if (value != Value()) {
|
||||
fSlider->SetValue(value);
|
||||
if (LockLooperWithTimeout(0) >= B_OK) {
|
||||
Invalidate();
|
||||
UnlockLooper();
|
||||
}
|
||||
}
|
||||
} else
|
||||
ValueChanged(value);
|
||||
}
|
||||
|
||||
// Value
|
||||
int32
|
||||
PopupSlider::Value() const
|
||||
{
|
||||
int32 value = 0;
|
||||
/* if (fSlider->LockLooper()) {
|
||||
value = fSlider->Value();
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
value = fSlider->Value();
|
||||
return value;
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
PopupSlider::SetEnabled(bool enable)
|
||||
{
|
||||
if (enable != fEnabled) {
|
||||
fEnabled = enable;
|
||||
if (LockLooper()) {
|
||||
Invalidate();
|
||||
UnlockLooper();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
bool
|
||||
PopupSlider::IsEnabled() const
|
||||
{
|
||||
return fEnabled;
|
||||
}
|
||||
|
||||
// TriggerValueChanged
|
||||
void
|
||||
PopupSlider::TriggerValueChanged(const BMessage* message) const
|
||||
{
|
||||
if (message && fTarget) {
|
||||
BMessage msg(*message);
|
||||
msg.AddInt64("be:when", system_time());
|
||||
msg.AddInt32("be:value", Value());
|
||||
msg.AddPointer("be:source", (void*)this);
|
||||
if (BLooper* looper = fTarget->Looper())
|
||||
looper->PostMessage(&msg, fTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// IsTracking
|
||||
bool
|
||||
PopupSlider::IsTracking() const
|
||||
{
|
||||
return fTracking;
|
||||
}
|
||||
|
||||
// ValueChanged
|
||||
void
|
||||
PopupSlider::ValueChanged(int32 newValue)
|
||||
{
|
||||
TriggerValueChanged(fModel);
|
||||
}
|
||||
|
||||
// DrawSlider
|
||||
void
|
||||
PopupSlider::DrawSlider(BRect frame, bool enabled)
|
||||
{
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color lightShadow;
|
||||
rgb_color darkShadow;
|
||||
if (enabled) {
|
||||
lightShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||
} else {
|
||||
lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
darkShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
}
|
||||
|
||||
BeginLineArray(4);
|
||||
AddLine(BPoint(frame.left, frame.bottom),
|
||||
BPoint(frame.left, frame.top), lightShadow);
|
||||
AddLine(BPoint(frame.left + 1.0, frame.top),
|
||||
BPoint(frame.right, frame.top), lightShadow);
|
||||
AddLine(BPoint(frame.right, frame.top + 1.0),
|
||||
BPoint(frame.right, frame.bottom), darkShadow);
|
||||
AddLine(BPoint(frame.right - 1.0, frame.bottom),
|
||||
BPoint(frame.left + 1.0, frame.bottom), darkShadow);
|
||||
EndLineArray();
|
||||
|
||||
frame.InsetBy(1.0, 1.0);
|
||||
SliderView::DrawSliderButton(this, frame, Value(), FormatString(), enabled);
|
||||
}
|
||||
|
||||
// Scale
|
||||
float
|
||||
PopupSlider::Scale(float ratio) const
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
// DeScale
|
||||
float
|
||||
PopupSlider::DeScale(float ratio) const
|
||||
{
|
||||
return ratio;
|
||||
}
|
||||
|
||||
// SetMessage
|
||||
void
|
||||
PopupSlider::SetMessage(BMessage* message)
|
||||
{
|
||||
delete fModel;
|
||||
fModel = message;
|
||||
}
|
||||
|
||||
// SetPressedMessage
|
||||
void
|
||||
PopupSlider::SetPressedMessage(BMessage* message)
|
||||
{
|
||||
delete fPressModel;
|
||||
fPressModel = message;
|
||||
}
|
||||
|
||||
// SetReleasedMessage
|
||||
void
|
||||
PopupSlider::SetReleasedMessage(BMessage* message)
|
||||
{
|
||||
delete fReleaseModel;
|
||||
fReleaseModel = message;
|
||||
}
|
||||
|
||||
// SetMin
|
||||
void
|
||||
PopupSlider::SetMin(int32 min)
|
||||
{
|
||||
/* if (fSlider->LockLooper()) {
|
||||
fSlider->SetMin(min);
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
fSlider->SetMin(min);
|
||||
}
|
||||
|
||||
// Min
|
||||
int32
|
||||
PopupSlider::Min() const
|
||||
{
|
||||
int32 value = 0;
|
||||
/* if (fSlider->LockLooper()) {
|
||||
value = fSlider->Min();
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
value = fSlider->Min();
|
||||
return value;
|
||||
}
|
||||
|
||||
// SetMax
|
||||
void
|
||||
PopupSlider::SetMax(int32 max)
|
||||
{
|
||||
/* if (fSlider->LockLooper()) {
|
||||
fSlider->SetMax(max);
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
fSlider->SetMax(max);
|
||||
}
|
||||
|
||||
// Max
|
||||
int32
|
||||
PopupSlider::Max() const
|
||||
{
|
||||
int32 value = 0;
|
||||
/* if (fSlider->LockLooper()) {
|
||||
value = fSlider->Max();
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
value = fSlider->Max();
|
||||
return value;
|
||||
}
|
||||
|
||||
// SetLabel
|
||||
void
|
||||
PopupSlider::SetLabel(const char* label)
|
||||
{
|
||||
fLabel.SetTo(label);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Label
|
||||
const char*
|
||||
PopupSlider::Label() const
|
||||
{
|
||||
return fLabel.String();
|
||||
}
|
||||
|
||||
// LabelWidth
|
||||
float
|
||||
PopupSlider::LabelWidth()
|
||||
{
|
||||
return _MinLabelWidth();
|
||||
}
|
||||
|
||||
// StringForValue
|
||||
const char*
|
||||
PopupSlider::StringForValue(int32 value)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// MaxValueStringWidth
|
||||
float
|
||||
PopupSlider::MaxValueStringWidth()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// SetFormatString
|
||||
void
|
||||
PopupSlider::SetFormatString(const char* formatString)
|
||||
{
|
||||
/* if (fSlider->LockLooper()) {
|
||||
fSlider->SetFormatString(formatString);
|
||||
fSlider->UnlockLooper();
|
||||
} else*/
|
||||
fSlider->SetFormatString(formatString);
|
||||
}
|
||||
|
||||
// FormatString
|
||||
const char*
|
||||
PopupSlider::FormatString() const
|
||||
{
|
||||
return fSlider->FormatString();
|
||||
}
|
||||
|
||||
// _MinLabelWidth
|
||||
float
|
||||
PopupSlider::_MinLabelWidth() const
|
||||
{
|
||||
return ceilf(StringWidth(fLabel.String())) + 5.0;
|
||||
}
|
||||
|
||||
/*
|
||||
// StringForValue
|
||||
const char*
|
||||
PercentSlider::StringForValue(int32 value)
|
||||
{
|
||||
BString string;
|
||||
string << (value * 100) / Max() << "%";
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef POPUP_SLIDER_H
|
||||
#define POPUP_SLIDER_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "MDividable.h"
|
||||
|
||||
#include "PopupControl.h"
|
||||
|
||||
class MDividable;
|
||||
class SliderView;
|
||||
|
||||
class PopupSlider : public PopupControl,
|
||||
public MDividable {
|
||||
public:
|
||||
PopupSlider(const char* name = NULL,
|
||||
const char* label = NULL,
|
||||
BMessage* model = NULL,
|
||||
BHandler* target = NULL,
|
||||
int32 min = 0,
|
||||
int32 max = 100,
|
||||
int32 value = 0,
|
||||
const char* formatString = "%ld");
|
||||
virtual ~PopupSlider();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// BHandler
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// BView
|
||||
virtual void AttachedToWindow();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MouseDown(BPoint where);
|
||||
|
||||
// PopupControl
|
||||
virtual void PopupShown();
|
||||
virtual void PopupHidden(bool canceled);
|
||||
|
||||
// PopupSlider
|
||||
void SetValue(int32 value);
|
||||
int32 Value() const;
|
||||
void SetEnabled(bool enabled);
|
||||
bool IsEnabled() const;
|
||||
void TriggerValueChanged(const BMessage* message) const;
|
||||
bool IsTracking() const;
|
||||
// override this to take some action
|
||||
virtual void ValueChanged(int32 newValue);
|
||||
virtual void DrawSlider(BRect frame, bool enabled);
|
||||
virtual float Scale(float ratio) const;
|
||||
virtual float DeScale(float ratio) const;
|
||||
|
||||
void SetMessage(BMessage* message);
|
||||
const BMessage* Message() const
|
||||
{ return fModel; }
|
||||
void SetPressedMessage(BMessage* message);
|
||||
void SetReleasedMessage(BMessage* message);
|
||||
|
||||
virtual void SetMin(int32 min);
|
||||
int32 Min() const;
|
||||
|
||||
virtual void SetMax(int32 max);
|
||||
int32 Max() const;
|
||||
|
||||
virtual void SetLabel(const char* label);
|
||||
const char* Label() const;
|
||||
|
||||
// support for MDividable
|
||||
virtual float LabelWidth();
|
||||
|
||||
// TODO: change design to implement these features:
|
||||
// you can override this function
|
||||
// to have costum value strings
|
||||
virtual const char* StringForValue(int32 value);
|
||||
// but you should override this
|
||||
// as well to make sure the width
|
||||
// of the slider is calculated properly
|
||||
virtual float MaxValueStringWidth();
|
||||
|
||||
virtual void SetFormatString(const char* formatString);
|
||||
const char* FormatString() const;
|
||||
|
||||
protected:
|
||||
BRect SliderFrame() const
|
||||
{ return fSliderButtonRect; }
|
||||
|
||||
|
||||
private:
|
||||
float _MinLabelWidth() const;
|
||||
|
||||
SliderView* fSlider;
|
||||
BMessage* fModel;
|
||||
BMessage* fPressModel;
|
||||
BMessage* fReleaseModel;
|
||||
BHandler* fTarget;
|
||||
BString fLabel;
|
||||
BRect fSliderButtonRect;
|
||||
bool fEnabled;
|
||||
bool fTracking;
|
||||
};
|
||||
/*
|
||||
class PercentSlider : public PopupSlider {
|
||||
public:
|
||||
|
||||
virtual const char* StringForValue(int32 value);
|
||||
virtual float MaxValueStringWidth();
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
#endif // POPUP_SLIDER_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "PopupView.h"
|
||||
|
||||
#include "PopupWindow.h"
|
||||
|
||||
// constructor
|
||||
PopupView::PopupView(const char* name)
|
||||
: BView(BRect(0.0, 0.0, 10.0, 10.0), name,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW),
|
||||
fWindow(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
PopupView::~PopupView()
|
||||
{
|
||||
}
|
||||
|
||||
// SetPopupWindow
|
||||
void
|
||||
PopupView::SetPopupWindow(PopupWindow* window)
|
||||
{
|
||||
fWindow = window;
|
||||
if (fWindow)
|
||||
SetEventMask(B_POINTER_EVENTS);
|
||||
else
|
||||
SetEventMask(0);
|
||||
}
|
||||
|
||||
// PopupDown
|
||||
void
|
||||
PopupView::PopupDone(bool canceled)
|
||||
{
|
||||
if (fWindow)
|
||||
fWindow->PopupDone(canceled);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef POPUP_VIEW_H
|
||||
#define POPUP_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include <layout.h>
|
||||
|
||||
class PopupWindow;
|
||||
|
||||
class PopupView : public MView, public BView {
|
||||
public:
|
||||
PopupView(const char* name);
|
||||
virtual ~PopupView();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs() = 0;
|
||||
virtual BRect layout(BRect frame) = 0;
|
||||
|
||||
virtual void SetPopupWindow(PopupWindow* window);
|
||||
|
||||
virtual void PopupDone(bool canceled);
|
||||
|
||||
private:
|
||||
PopupWindow* fWindow;
|
||||
};
|
||||
|
||||
|
||||
#endif // POPUP_CONTROL_H
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include <AppDefs.h>
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <View.h>
|
||||
|
||||
#include "PopupControl.h"
|
||||
#include "PopupView.h"
|
||||
|
||||
#include "PopupWindow.h"
|
||||
|
||||
// MouseDownFilter
|
||||
|
||||
class MouseDownFilter : public BMessageFilter {
|
||||
public:
|
||||
MouseDownFilter(BWindow* window);
|
||||
|
||||
virtual filter_result Filter(BMessage*, BHandler** target);
|
||||
|
||||
private:
|
||||
BWindow* fWindow;
|
||||
};
|
||||
|
||||
// constructor
|
||||
MouseDownFilter::MouseDownFilter(BWindow* window)
|
||||
: BMessageFilter(B_MOUSE_DOWN),
|
||||
fWindow(window)
|
||||
{
|
||||
}
|
||||
|
||||
// Filter
|
||||
filter_result
|
||||
MouseDownFilter::Filter(BMessage* message, BHandler** target)
|
||||
{
|
||||
if (fWindow) {
|
||||
if (BView* view = dynamic_cast<BView*>(*target)) {
|
||||
BPoint point;
|
||||
if (message->FindPoint("where", &point) == B_OK) {
|
||||
if (!fWindow->Frame().Contains(view->ConvertToScreen(point)))
|
||||
*target = fWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_DISPATCH_MESSAGE;
|
||||
}
|
||||
|
||||
|
||||
// PopupWindow
|
||||
|
||||
// constructor
|
||||
PopupWindow::PopupWindow(PopupView* child, PopupControl* control)
|
||||
: MWindow(BRect(0.0, 0.0, 10.0, 10.0), "popup",
|
||||
B_NO_BORDER_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL,
|
||||
B_ASYNCHRONOUS_CONTROLS),
|
||||
fCanceled(true),
|
||||
fControl(control)
|
||||
{
|
||||
AddChild(child);
|
||||
child->SetPopupWindow(this);
|
||||
AddCommonFilter(new MouseDownFilter(this));
|
||||
}
|
||||
|
||||
// destructor
|
||||
PopupWindow::~PopupWindow()
|
||||
{
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
PopupWindow::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case B_MOUSE_DOWN:
|
||||
fCanceled = true;
|
||||
Hide();
|
||||
break;
|
||||
default:
|
||||
MWindow::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Show
|
||||
void
|
||||
PopupWindow::Show()
|
||||
{
|
||||
if (BLooper *looper = fControl->Looper())
|
||||
looper->PostMessage(MSG_POPUP_SHOWN, fControl);
|
||||
MWindow::Show();
|
||||
}
|
||||
|
||||
// Hide
|
||||
void
|
||||
PopupWindow::Hide()
|
||||
{
|
||||
if (BLooper *looper = fControl->Looper()) {
|
||||
BMessage msg(MSG_POPUP_HIDDEN);
|
||||
msg.AddBool("canceled", fCanceled);
|
||||
looper->PostMessage(&msg, fControl);
|
||||
}
|
||||
MWindow::Hide();
|
||||
}
|
||||
|
||||
// QuitRequested
|
||||
bool
|
||||
PopupWindow::QuitRequested()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// PopupDone
|
||||
void
|
||||
PopupWindow::PopupDone(bool canceled)
|
||||
{
|
||||
fCanceled = canceled;
|
||||
Hide();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef POPUP_WINDOW_H
|
||||
#define POPUP_WINDOW_H
|
||||
|
||||
#include <MWindow.h>
|
||||
|
||||
enum {
|
||||
MSG_POPUP_SHOWN = 'push',
|
||||
MSG_POPUP_HIDDEN = 'puhi',
|
||||
};
|
||||
|
||||
class PopupControl;
|
||||
class PopupView;
|
||||
|
||||
class PopupWindow : public MWindow {
|
||||
public:
|
||||
PopupWindow(PopupView* child,
|
||||
PopupControl* control);
|
||||
virtual ~PopupWindow();
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// MWindow
|
||||
virtual void Show();
|
||||
virtual void Hide();
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual void PopupDone(bool canceled = true);
|
||||
|
||||
private:
|
||||
bool fCanceled;
|
||||
PopupControl* fControl;
|
||||
};
|
||||
|
||||
|
||||
#endif // POPUP_CONTROL_H
|
||||
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "SliderView.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "PopupSlider.h"
|
||||
|
||||
// constructor
|
||||
SliderView::SliderView(PopupSlider* target,
|
||||
int32 min, int32 max, int32 value,
|
||||
const char* formatString)
|
||||
: PopupView("slider"),
|
||||
fTarget(target),
|
||||
fFormatString(formatString),
|
||||
fMin(min),
|
||||
fMax(max),
|
||||
fValue(value),
|
||||
fButtonRect(0.0, 0.0, -1.0, -1.0),
|
||||
fDragOffset(0.0)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
if (Max() < Min())
|
||||
SetMax(Min());
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
float buttonWidth, buttonHeight;
|
||||
GetSliderButtonDimensions(Max(), FormatString(), &font,
|
||||
buttonWidth, buttonHeight);
|
||||
|
||||
fButtonRect.right = fButtonRect.left + buttonWidth;
|
||||
fButtonRect.bottom = fButtonRect.top + buttonHeight;
|
||||
float size = Max() - Min();
|
||||
if (size > 200)
|
||||
size = 200;
|
||||
ResizeTo(6.0 + fButtonRect.Width() + size + 6.0,
|
||||
6.0 + fButtonRect.Height() + 6.0);
|
||||
}
|
||||
|
||||
// destructor
|
||||
SliderView::~SliderView()
|
||||
{
|
||||
}
|
||||
|
||||
// minimax
|
||||
minimax
|
||||
SliderView::layoutprefs()
|
||||
{
|
||||
mpm.mini.x = mpm.maxi.x = Bounds().Width() + 1.0;
|
||||
mpm.mini.y = mpm.maxi.y = Bounds().Height() + 1.0;
|
||||
|
||||
mpm.weight = 1.0;
|
||||
|
||||
return mpm;
|
||||
}
|
||||
|
||||
// layout
|
||||
BRect
|
||||
SliderView::layout(BRect frame)
|
||||
{
|
||||
MoveTo(frame.LeftTop());
|
||||
ResizeTo(frame.Width(), frame.Height());
|
||||
return Frame();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
SliderView::Draw(BRect updateRect)
|
||||
{
|
||||
fButtonRect.OffsetTo(ButtonOffset(), 6.0);
|
||||
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
rgb_color lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
|
||||
rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||
|
||||
BRect r(Bounds());
|
||||
BeginLineArray(24);
|
||||
// outer dark line
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), lightShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), lightShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), darkShadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), darkShadow);
|
||||
// second line (raised)
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), light);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), light);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), shadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), shadow);
|
||||
// third line (normal)
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), background);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), background);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), background);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), background);
|
||||
// fourth line (normal)
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), background);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), background);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), background);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), background);
|
||||
// fifth line (depressed)
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), lightShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), lightShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), light);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), light);
|
||||
// fifth line (strongly depressed)
|
||||
r.InsetBy(1.0, 1.0);
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), darkShadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), darkShadow);
|
||||
AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), shadow);
|
||||
AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), shadow);
|
||||
EndLineArray();
|
||||
|
||||
r.InsetBy(1.0, 1.0);
|
||||
SetLowColor(lightShadow);
|
||||
BRect leftOfButton(r.left + 1.0, r.top + 1.0, fButtonRect.left - 2.0, r.bottom);
|
||||
if (leftOfButton.IsValid())
|
||||
FillRect(leftOfButton, B_SOLID_LOW);
|
||||
BRect rightOfButton(fButtonRect.right + 2.0, r.top + 1.0,
|
||||
r.right, r.bottom);
|
||||
if (rightOfButton.IsValid())
|
||||
FillRect(rightOfButton, B_SOLID_LOW);
|
||||
|
||||
// inner shadow and knob out lines
|
||||
BeginLineArray(5);
|
||||
// shadow
|
||||
AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), shadow);
|
||||
AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), shadow);
|
||||
// at knob
|
||||
if (fButtonRect.left == 6.0)
|
||||
AddLine(BPoint(fButtonRect.left - 1.0, r.top),
|
||||
BPoint(fButtonRect.left - 1.0, r.bottom), darkShadow);
|
||||
else
|
||||
AddLine(BPoint(fButtonRect.left - 1.0, r.top),
|
||||
BPoint(fButtonRect.left - 1.0, r.bottom), shadow);
|
||||
AddLine(BPoint(fButtonRect.left, fButtonRect.bottom + 1.0),
|
||||
BPoint(fButtonRect.right + 1.0, fButtonRect.bottom + 1.0), darkShadow);
|
||||
AddLine(BPoint(fButtonRect.right + 1.0, fButtonRect.bottom),
|
||||
BPoint(fButtonRect.right + 1.0, fButtonRect.top), darkShadow);
|
||||
EndLineArray();
|
||||
|
||||
|
||||
DrawSliderButton(this, fButtonRect, fValue, fFormatString.String(), fTarget->IsEnabled());
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
SliderView::MouseUp(BPoint where)
|
||||
{
|
||||
PopupDone(false);
|
||||
fTarget->TriggerValueChanged(fTarget->Message());
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
SliderView::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
|
||||
{
|
||||
uint32 buttons = 0;
|
||||
if (BMessage* message = Window()->CurrentMessage()) {
|
||||
if (message->FindInt32("buttons", (int32*)&buttons) < B_OK)
|
||||
buttons = 0;
|
||||
}
|
||||
|
||||
if (buttons == 0) {
|
||||
MouseUp(where);
|
||||
return;
|
||||
}
|
||||
|
||||
SetValue(_ValueAt(where.x - fDragOffset - 6.0));
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
SliderView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
default:
|
||||
PopupView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
SliderView::SetValue(int32 value)
|
||||
{
|
||||
if (value < fMin)
|
||||
value = fMin;
|
||||
if (value > fMax)
|
||||
value = fMax;
|
||||
if (value != fValue) {
|
||||
fValue = value;
|
||||
fTarget->SetValue(value);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Value
|
||||
int32
|
||||
SliderView::Value() const
|
||||
{
|
||||
return fValue;
|
||||
}
|
||||
|
||||
// SetMin
|
||||
void
|
||||
SliderView::SetMin(int32 min)
|
||||
{
|
||||
if (min != fMax) {
|
||||
fMin = min;
|
||||
if (fValue < fMin)
|
||||
SetValue(fMin);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Min
|
||||
int32
|
||||
SliderView::Min() const
|
||||
{
|
||||
return fMin;
|
||||
}
|
||||
|
||||
// SetMax
|
||||
void
|
||||
SliderView::SetMax(int32 max)
|
||||
{
|
||||
if (max != fMax) {
|
||||
fMax = max;
|
||||
if (fValue > fMax)
|
||||
SetValue(fMax);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Max
|
||||
int32
|
||||
SliderView::Max() const
|
||||
{
|
||||
return fMax;
|
||||
}
|
||||
|
||||
// SetFormatString
|
||||
void
|
||||
SliderView::SetFormatString(const char* formatString)
|
||||
{
|
||||
// TODO: check if formatString contains "%ld"
|
||||
fFormatString.SetTo(formatString);
|
||||
}
|
||||
|
||||
// FormatString
|
||||
const char*
|
||||
SliderView::FormatString() const
|
||||
{
|
||||
return fFormatString.String();
|
||||
}
|
||||
|
||||
// SetDragOffset
|
||||
void
|
||||
SliderView::SetDragOffset(float offset)
|
||||
{
|
||||
fDragOffset = offset;
|
||||
}
|
||||
|
||||
// ButtonOffset
|
||||
float
|
||||
SliderView::ButtonOffset()
|
||||
{
|
||||
// float range = Bounds().Width() - 12.0 - fButtonRect.Width() + 1.0;
|
||||
// return 6.0 + range / (float)(fMax - fMin + 1) * (float)(fValue - fMin);
|
||||
float ratio = fTarget->DeScale((float)(fValue - fMin) / (float)(fMax - fMin));
|
||||
return 6.0 + ratio * (Bounds().Width() - 12.0 - fButtonRect.Width());
|
||||
}
|
||||
|
||||
// GetSliderButtonDimensions
|
||||
void
|
||||
SliderView::GetSliderButtonDimensions(int32 max, const char* formatString,
|
||||
BFont* font,
|
||||
float& width, float& height)
|
||||
{
|
||||
if (font) {
|
||||
char label[256];
|
||||
sprintf(label, formatString, max);
|
||||
font_height fh;
|
||||
font->GetHeight(&fh);
|
||||
// 4 pixels room on each side,
|
||||
// 1 pixel room at top and bottom
|
||||
width = 5.0 + ceilf(font->StringWidth(label)) + 5.0;
|
||||
height = 2.0 + ceilf(fh.ascent + fh.descent) + 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
// DrawSliderButton
|
||||
void
|
||||
SliderView::DrawSliderButton(BView* v, BRect r, int32 value,
|
||||
const char* formatString, bool enabled)
|
||||
{
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color light;
|
||||
rgb_color shadow;
|
||||
rgb_color button;
|
||||
rgb_color black;
|
||||
if (enabled) {
|
||||
light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||
shadow = tint_color(background, B_DARKEN_1_TINT);
|
||||
button = tint_color(background, B_LIGHTEN_1_TINT);
|
||||
black = tint_color(background, B_DARKEN_MAX_TINT);
|
||||
} else {
|
||||
light = tint_color(background, B_LIGHTEN_1_TINT);
|
||||
shadow = tint_color(background, 1.1);
|
||||
button = tint_color(background, 0.8);
|
||||
black = tint_color(background, B_DISABLED_LABEL_TINT);
|
||||
}
|
||||
// border
|
||||
v->BeginLineArray(4);
|
||||
v->AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), light);
|
||||
v->AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), light);
|
||||
v->AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), shadow);
|
||||
v->AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), shadow);
|
||||
v->EndLineArray();
|
||||
// background & label
|
||||
r.InsetBy(1.0, 1.0);
|
||||
char label[256];
|
||||
sprintf(label, formatString, value);
|
||||
float width = v->StringWidth(label);
|
||||
font_height fh;
|
||||
v->GetFontHeight(&fh);
|
||||
BPoint textPoint((r.left + r.right) / 2.0 - width / 2.0,
|
||||
(r.top + r.bottom) / 2.0 + fh.ascent / 2.0);
|
||||
v->SetHighColor(black);
|
||||
v->SetLowColor(button);
|
||||
v->FillRect(r, B_SOLID_LOW);
|
||||
v->DrawString(label, textPoint);
|
||||
}
|
||||
|
||||
// _ValueAt
|
||||
int32
|
||||
SliderView::_ValueAt(float h)
|
||||
{
|
||||
/* return fMin + (int32)(((float)(fMax - fMin + 1) * h) /
|
||||
(Bounds().Width() - fButtonRect.Width() - 12.0));*/
|
||||
float ratio = h / (Bounds().Width() - fButtonRect.Width() - 12.0);
|
||||
if (ratio < 0.0)
|
||||
ratio = 0.0;
|
||||
if (ratio > 1.0)
|
||||
ratio = 1.0;
|
||||
ratio = fTarget->Scale(ratio);
|
||||
return fMin + (int32)((fMax - fMin + 1) * ratio);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SLIDER_VIEW_H
|
||||
#define SLIDER_VIEW_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "PopupView.h"
|
||||
|
||||
class BFont;
|
||||
class PopupSlider;
|
||||
|
||||
class SliderView : public PopupView {
|
||||
public:
|
||||
SliderView(PopupSlider* target,
|
||||
int32 min,
|
||||
int32 max,
|
||||
int32 value,
|
||||
const char* formatString);
|
||||
virtual ~SliderView();
|
||||
|
||||
// MView
|
||||
virtual minimax layoutprefs();
|
||||
virtual BRect layout(BRect frame);
|
||||
|
||||
// BView
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* message);
|
||||
virtual void MouseUp(BPoint where);
|
||||
|
||||
// BHandler
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// SliderView
|
||||
void SetValue(int32 value);
|
||||
int32 Value() const;
|
||||
void SetMin(int32 min);
|
||||
int32 Min() const;
|
||||
void SetMax(int32 max);
|
||||
int32 Max() const;
|
||||
|
||||
void SetFormatString(const char* formatString);
|
||||
const char* FormatString() const;
|
||||
|
||||
void SetDragOffset(float offset);
|
||||
|
||||
float ButtonOffset();
|
||||
|
||||
static void GetSliderButtonDimensions(int32 max,
|
||||
const char* formatString,
|
||||
BFont* font,
|
||||
float& width,
|
||||
float& height);
|
||||
static void DrawSliderButton(BView* into, BRect frame,
|
||||
int32 value,
|
||||
const char* formatString,
|
||||
bool enabled);
|
||||
|
||||
|
||||
private:
|
||||
int32 _ValueAt(float h);
|
||||
|
||||
PopupSlider* fTarget;
|
||||
BString fFormatString;
|
||||
|
||||
int32 fMin;
|
||||
int32 fMax;
|
||||
int32 fValue;
|
||||
|
||||
BRect fButtonRect;
|
||||
float fDragOffset;
|
||||
};
|
||||
|
||||
|
||||
#endif // SLIDER_VIEW_H
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
const int32 sBitmapWidth = 14;
|
||||
const int32 sBitmapHeight = 14;
|
||||
const color_space sColorSpace = B_RGBA32;
|
||||
|
||||
|
||||
const unsigned char sScrollCornerNormalBits [] = {
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0x94,0x95,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,
|
||||
0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,0xde,0xd6,0xde,0xff,0xd5,0xda,0xd5,0xff,0xd5,0xda,0xd5,0xff,0xde,0xd6,0xde,0xff,0xd5,0xda,0xd5,0xff,0xde,0xd6,0xde,0xff,0xd5,0xda,0xd5,0xff,0xd5,0xd6,0xd5,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x99,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,
|
||||
0xde,0xd6,0xde,0xff,0xd5,0xda,0xd5,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0xd5,0xd6,0xd5,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0xde,0xd6,0xde,0xff,0xbd,0xc2,0xbd,0xff,0x9c,0x99,0x9c,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,0xc5,0xbe,0xc5,0xff,0x6a,0x71,0x6a,0xff,
|
||||
0x8b,0x85,0x8b,0xff,0x83,0x85,0x83,0xff,0xc5,0xc6,0xc5,0xff,0xd5,0xd6,0xd5,0xff,0xde,0xda,0xde,0xff,0xc5,0xca,0xc5,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x95,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xbd,0xc2,0xbd,0xff,0x73,0x71,0x73,0xff,0xff,0xff,0xff,0xff,0xee,0xea,0xee,0xff,0xc5,0xca,0xc5,0xff,
|
||||
0x83,0x85,0x83,0xff,0xee,0xea,0xee,0xff,0xd5,0xd6,0xd5,0xff,0xde,0xda,0xde,0xff,0xbd,0xc2,0xbd,0xff,0x94,0x95,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0x73,0x6d,0x73,0xff,0xff,0xff,0xff,0xff,0xe6,0xe6,0xe6,0xff,0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,0xbd,0xba,0xbd,0xff,0x83,0x81,0x83,0xff,
|
||||
0xe6,0xea,0xe6,0xff,0xde,0xda,0xde,0xff,0xbd,0xc2,0xbd,0xff,0x94,0x95,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0x83,0x81,0x83,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0xd5,0xd6,0xd5,0xff,0xc5,0xc2,0xc5,0xff,0x7b,0x7d,0x7b,0xff,0xff,0xff,0xff,0xff,0xcd,0xca,0xcd,0xff,
|
||||
0xc5,0xc2,0xc5,0xff,0x94,0x99,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xda,0xd5,0xff,0x83,0x81,0x83,0xff,0xee,0xee,0xee,0xff,0xde,0xde,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xd5,0xd2,0xd5,0xff,0xbd,0xc2,0xbd,0xff,0x62,0x65,0x62,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x95,0x94,0xff,
|
||||
0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xb4,0xb6,0xb4,0xff,0x83,0x85,0x83,0xff,0xe6,0xe2,0xe6,0xff,0xcd,0xd2,0xcd,0xff,0xc5,0xc2,0xc5,0xff,0x62,0x65,0x62,0xff,0xff,0xfa,0xff,0xff,0xee,0xee,0xee,0xff,0xd5,0xd6,0xd5,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x99,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,
|
||||
0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,0xb4,0xb6,0xb4,0xff,0x83,0x81,0x83,0xff,0x73,0x71,0x73,0xff,0x62,0x65,0x62,0xff,0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xda,0xd5,0xff,0xcd,0xca,0xcd,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x95,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xd5,0xda,0xd5,0xff,
|
||||
0xde,0xd6,0xde,0xff,0xcd,0xce,0xcd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe6,0xea,0xe6,0xff,0xde,0xda,0xde,0xff,0xc5,0xca,0xc5,0xff,0xd5,0xd6,0xd5,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x99,0x94,0xff,0xff,0xff,0xff,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,0xc5,0xca,0xc5,0xff,0xde,0xda,0xde,0xff,0xd5,0xd6,0xd5,0xff,
|
||||
0xcd,0xca,0xcd,0xff,0xd5,0xda,0xd5,0xff,0xd5,0xd6,0xd5,0xff,0xcd,0xca,0xcd,0xff,0xd5,0xda,0xd5,0xff,0xcd,0xca,0xcd,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x95,0x94,0xff,0xde,0xda,0xde,0xff,0xbd,0xc2,0xbd,0xff,0xc5,0xc2,0xc5,0xff,0xbd,0xc2,0xbd,0xff,0xc5,0xc2,0xc5,0xff,0xc5,0xc2,0xc5,0xff,0xbd,0xc2,0xbd,0xff,0xc5,0xc2,0xc5,0xff,
|
||||
0xbd,0xc2,0xbd,0xff,0xc5,0xc2,0xc5,0xff,0xc5,0xc2,0xc5,0xff,0xbd,0xc2,0xbd,0xff,0xc5,0xc2,0xc5,0xff,0x94,0x95,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x95,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x99,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x95,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x99,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x95,0x94,0xff,
|
||||
0x9c,0x99,0x9c,0xff,0x94,0x99,0x94,0xff,0x9c,0x99,0x9c,0xff,0x94,0x95,0x94,0xff
|
||||
};
|
||||
|
||||
const unsigned char sScrollCornerPushedBits [] = {
|
||||
0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0x90,0x90,0x90,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,
|
||||
0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,
|
||||
0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xab,0xab,0xab,0xff,0x97,0x97,0x97,0xff,0x59,0x59,0x59,0xff,
|
||||
0x69,0x69,0x69,0xff,0x69,0x69,0x69,0xff,0x9a,0x9a,0x9a,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xab,0xab,0xab,0xff,0x97,0x97,0x97,0xff,0x59,0x59,0x59,0xff,0xc9,0xc9,0xc9,0xff,0xb8,0xb8,0xb8,0xff,0xa0,0xa0,0xa0,0xff,
|
||||
0x69,0x69,0x69,0xff,0xb8,0xb8,0xb8,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0x59,0x59,0x59,0xff,0xc9,0xc9,0xc9,0xff,0xb3,0xb3,0xb3,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0x93,0x93,0x93,0xff,0x66,0x66,0x66,0xff,
|
||||
0xb8,0xb8,0xb8,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0x69,0x69,0x69,0xff,0xc9,0xc9,0xc9,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0x9a,0x9a,0x9a,0xff,0x62,0x62,0x62,0xff,0xc9,0xc9,0xc9,0xff,0xb0,0xb0,0xb0,0xff,
|
||||
0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xab,0xab,0xab,0xff,0xab,0xab,0xab,0xff,0x69,0x69,0x69,0xff,0xba,0xba,0xba,0xff,0xad,0xad,0xad,0xff,0xaa,0xaa,0xaa,0xff,0xa5,0xa5,0xa5,0xff,0x9a,0x9a,0x9a,0xff,0x4f,0x4f,0x4f,0xff,0xc9,0xc9,0xc9,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,
|
||||
0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xab,0xab,0xab,0xff,0x8f,0x8f,0x8f,0xff,0x69,0x69,0x69,0xff,0xb1,0xb1,0xb1,0xff,0xa5,0xa5,0xa5,0xff,0x9a,0x9a,0x9a,0xff,0x4f,0x4f,0x4f,0xff,0xc6,0xc6,0xc6,0xff,0xb9,0xb9,0xb9,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,
|
||||
0xab,0xab,0xab,0xff,0xaa,0xaa,0xaa,0xff,0x8f,0x8f,0x8f,0xff,0x66,0x66,0x66,0xff,0x58,0x58,0x58,0xff,0x4f,0x4f,0x4f,0xff,0xc6,0xc6,0xc6,0xff,0xc9,0xc9,0xc9,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,
|
||||
0xaa,0xaa,0xaa,0xff,0xa2,0xa2,0xa2,0xff,0xc9,0xc9,0xc9,0xff,0xc9,0xc9,0xc9,0xff,0xb9,0xb9,0xb9,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xaa,0xaa,0xaa,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,
|
||||
0xb0,0xb0,0xb0,0xff,0xaa,0xaa,0xaa,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xaa,0xaa,0xaa,0xff,0xb0,0xb0,0xb0,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x90,0x90,0x90,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,
|
||||
0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0xce,0xce,0xce,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,
|
||||
0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff
|
||||
};
|
||||
|
||||
const unsigned char sScrollCornerDisabledBits [] = {
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd8,0xd8,0xd8,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,
|
||||
0xc7,0xc7,0xc7,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,
|
||||
0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc7,0xc7,0xc7,0xff,0xc7,0xc7,0xc7,0xff,0xc7,0xc7,0xc7,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,
|
||||
0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xf0,0xf0,0xf0,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0xd8,0xd8,0xd8,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,
|
||||
0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0xc2,0xc2,0xc2,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,
|
||||
0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff,0x98,0x98,0x98,0xff
|
||||
};
|
||||
|
||||
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ScrollView.h"
|
||||
|
||||
#include <algobase.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Message.h>
|
||||
#include <ScrollBar.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "Scrollable.h"
|
||||
#include "ScrollCornerBitmaps.h"
|
||||
|
||||
|
||||
// InternalScrollBar
|
||||
|
||||
class InternalScrollBar : public BScrollBar {
|
||||
public:
|
||||
InternalScrollBar(ScrollView* scrollView,
|
||||
BRect frame,
|
||||
orientation posture);
|
||||
virtual ~InternalScrollBar();
|
||||
|
||||
virtual void ValueChanged(float value);
|
||||
|
||||
private:
|
||||
ScrollView* fScrollView;
|
||||
};
|
||||
|
||||
// constructor
|
||||
InternalScrollBar::InternalScrollBar(ScrollView* scrollView, BRect frame,
|
||||
orientation posture)
|
||||
: BScrollBar(frame, NULL, NULL, 0, 0, posture),
|
||||
fScrollView(scrollView)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
InternalScrollBar::~InternalScrollBar()
|
||||
{
|
||||
}
|
||||
|
||||
// ValueChanged
|
||||
void
|
||||
InternalScrollBar::ValueChanged(float value)
|
||||
{
|
||||
// Notify our parent scroll view. Note: the value already has changed,
|
||||
// so that we can't check, if it really has changed.
|
||||
if (fScrollView)
|
||||
fScrollView->_ScrollValueChanged(this, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ScrollCorner
|
||||
|
||||
class ScrollCorner : public BView {
|
||||
public:
|
||||
ScrollCorner(ScrollView* scrollView);
|
||||
virtual ~ScrollCorner();
|
||||
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void MouseUp(BPoint point);
|
||||
virtual void MouseMoved(BPoint point, uint32 transit,
|
||||
const BMessage* message);
|
||||
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void WindowActivated(bool active);
|
||||
|
||||
void SetActive(bool active);
|
||||
inline bool IsActive() const
|
||||
{ return fState & STATE_ACTIVE; }
|
||||
|
||||
private:
|
||||
ScrollView* fScrollView;
|
||||
uint32 fState;
|
||||
BPoint fStartPoint;
|
||||
BPoint fStartScrollOffset;
|
||||
BBitmap* fBitmaps[3];
|
||||
|
||||
inline bool IsEnabled() const
|
||||
{ return ((fState & STATE_ENABLED) ==
|
||||
STATE_ENABLED); }
|
||||
|
||||
void SetDragging(bool dragging);
|
||||
inline bool IsDragging() const
|
||||
{ return (fState & STATE_DRAGGING); }
|
||||
|
||||
enum {
|
||||
STATE_DRAGGING = 0x01,
|
||||
STATE_WINDOW_ACTIVE = 0x02,
|
||||
STATE_ACTIVE = 0x04,
|
||||
STATE_ENABLED = STATE_WINDOW_ACTIVE | STATE_ACTIVE,
|
||||
};
|
||||
};
|
||||
|
||||
// constructor
|
||||
ScrollCorner::ScrollCorner(ScrollView* scrollView)
|
||||
: BView(BRect(0.0, 0.0, B_V_SCROLL_BAR_WIDTH - 1.0f, B_H_SCROLL_BAR_HEIGHT - 1.0f), NULL,
|
||||
0, B_WILL_DRAW),
|
||||
fScrollView(scrollView),
|
||||
fState(0),
|
||||
fStartPoint(0, 0),
|
||||
fStartScrollOffset(0, 0)
|
||||
{
|
||||
//printf("ScrollCorner::ScrollCorner(%p)\n", scrollView);
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
//printf("setting up bitmap 0\n");
|
||||
fBitmaps[0] = new BBitmap(BRect(0.0f, 0.0f, sBitmapWidth, sBitmapHeight), sColorSpace);
|
||||
// fBitmaps[0]->SetBits((void *)sScrollCornerNormalBits, fBitmaps[0]->BitsLength(), 0L, sColorSpace);
|
||||
char *bits = (char *)fBitmaps[0]->Bits();
|
||||
int32 bpr = fBitmaps[0]->BytesPerRow();
|
||||
for (int i = 0; i <= sBitmapHeight; i++, bits += bpr)
|
||||
memcpy(bits, &sScrollCornerNormalBits[i * sBitmapHeight * 4], sBitmapWidth * 4);
|
||||
|
||||
//printf("setting up bitmap 1\n");
|
||||
fBitmaps[1] = new BBitmap(BRect(0.0f, 0.0f, sBitmapWidth, sBitmapHeight), sColorSpace);
|
||||
// fBitmaps[1]->SetBits((void *)sScrollCornerPushedBits, fBitmaps[1]->BitsLength(), 0L, sColorSpace);
|
||||
bits = (char *)fBitmaps[1]->Bits();
|
||||
bpr = fBitmaps[1]->BytesPerRow();
|
||||
for (int i = 0; i <= sBitmapHeight; i++, bits += bpr)
|
||||
memcpy(bits, &sScrollCornerPushedBits[i * sBitmapHeight * 4], sBitmapWidth * 4);
|
||||
|
||||
//printf("setting up bitmap 2\n");
|
||||
fBitmaps[2] = new BBitmap(BRect(0.0f, 0.0f, sBitmapWidth, sBitmapHeight), sColorSpace);
|
||||
// fBitmaps[2]->SetBits((void *)sScrollCornerDisabledBits, fBitmaps[2]->BitsLength(), 0L, sColorSpace);
|
||||
bits = (char *)fBitmaps[2]->Bits();
|
||||
bpr = fBitmaps[2]->BytesPerRow();
|
||||
for (int i = 0; i <= sBitmapHeight; i++, bits += bpr)
|
||||
memcpy(bits, &sScrollCornerDisabledBits[i * sBitmapHeight * 4], sBitmapWidth * 4);
|
||||
}
|
||||
|
||||
// destructor
|
||||
ScrollCorner::~ScrollCorner()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
delete fBitmaps[i];
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
ScrollCorner::MouseDown(BPoint point)
|
||||
{
|
||||
BView::MouseDown(point);
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32 *)&buttons);
|
||||
if (buttons & B_PRIMARY_MOUSE_BUTTON) {
|
||||
SetMouseEventMask(B_POINTER_EVENTS);
|
||||
if (fScrollView && IsEnabled() && Bounds().Contains(point)) {
|
||||
SetDragging(true);
|
||||
fStartPoint = point;
|
||||
fStartScrollOffset = fScrollView->ScrollOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
ScrollCorner::MouseUp(BPoint point)
|
||||
{
|
||||
BView::MouseUp(point);
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32 *)&buttons);
|
||||
if (!(buttons & B_PRIMARY_MOUSE_BUTTON))
|
||||
SetDragging(false);
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
ScrollCorner::MouseMoved(BPoint point, uint32 transit, const BMessage* message)
|
||||
{
|
||||
BView::MouseMoved(point, transit, message);
|
||||
if (IsDragging()) {
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32 *)&buttons);
|
||||
// This is a work-around for a BeOS bug: We sometimes don't get a
|
||||
// MouseUp(), but fortunately it seems, that within the last
|
||||
// MouseMoved() the button is not longer pressed.
|
||||
if (buttons & B_PRIMARY_MOUSE_BUTTON) {
|
||||
BPoint diff = point - fStartPoint;
|
||||
if (fScrollView) {
|
||||
fScrollView->_ScrollCornerValueChanged(fStartScrollOffset
|
||||
- diff);
|
||||
// + diff);
|
||||
}
|
||||
} else
|
||||
SetDragging(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
ScrollCorner::Draw(BRect updateRect)
|
||||
{
|
||||
if (IsEnabled()) {
|
||||
if (IsDragging())
|
||||
DrawBitmap(fBitmaps[1], BPoint(0.0f, 0.0f));
|
||||
else
|
||||
DrawBitmap(fBitmaps[0], BPoint(0.0f, 0.0f));
|
||||
}
|
||||
else
|
||||
DrawBitmap(fBitmaps[2], BPoint(0.0f, 0.0f));
|
||||
}
|
||||
|
||||
// WindowActivated
|
||||
void
|
||||
ScrollCorner::WindowActivated(bool active)
|
||||
{
|
||||
if (active != (fState & STATE_WINDOW_ACTIVE)) {
|
||||
bool enabled = IsEnabled();
|
||||
if (active)
|
||||
fState |= STATE_WINDOW_ACTIVE;
|
||||
else
|
||||
fState &= ~STATE_WINDOW_ACTIVE;
|
||||
if (enabled != IsEnabled())
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// SetActive
|
||||
void
|
||||
ScrollCorner::SetActive(bool active)
|
||||
{
|
||||
if (active != IsActive()) {
|
||||
bool enabled = IsEnabled();
|
||||
if (active)
|
||||
fState |= STATE_ACTIVE;
|
||||
else
|
||||
fState &= ~STATE_ACTIVE;
|
||||
if (enabled != IsEnabled())
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// SetDragging
|
||||
void
|
||||
ScrollCorner::SetDragging(bool dragging)
|
||||
{
|
||||
if (dragging != IsDragging()) {
|
||||
if (dragging)
|
||||
fState |= STATE_DRAGGING;
|
||||
else
|
||||
fState &= ~STATE_DRAGGING;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ScrollView
|
||||
|
||||
// constructor
|
||||
ScrollView::ScrollView(BView* child, uint32 scrollingFlags, BRect frame,
|
||||
const char *name, uint32 resizingMode, uint32 flags)
|
||||
: BView(frame, name, resizingMode, flags | B_FRAME_EVENTS | B_WILL_DRAW
|
||||
| B_FULL_UPDATE_ON_RESIZE),
|
||||
Scroller(),
|
||||
fChild(NULL),
|
||||
fScrollingFlags(scrollingFlags),
|
||||
fHScrollBar(NULL),
|
||||
fVScrollBar(NULL),
|
||||
fScrollCorner(NULL),
|
||||
fHVisible(true),
|
||||
fVVisible(true),
|
||||
fCornerVisible(true),
|
||||
fWindowActive(false),
|
||||
fChildFocused(false),
|
||||
fHSmallStep(1),
|
||||
fVSmallStep(1)
|
||||
{
|
||||
// Set transparent view color -- our area is completely covered by
|
||||
// our children.
|
||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||
// create scroll bars
|
||||
if (fScrollingFlags & (SCROLL_HORIZONTAL | SCROLL_HORIZONTAL_MAGIC)) {
|
||||
fHScrollBar = new InternalScrollBar(this,
|
||||
BRect(0.0, 0.0, 100.0, B_H_SCROLL_BAR_HEIGHT), B_HORIZONTAL);
|
||||
AddChild(fHScrollBar);
|
||||
}
|
||||
if (fScrollingFlags & (SCROLL_VERTICAL | SCROLL_VERTICAL_MAGIC)) {
|
||||
fVScrollBar = new InternalScrollBar(this,
|
||||
BRect(0.0, 0.0, B_V_SCROLL_BAR_WIDTH, 100.0), B_VERTICAL);
|
||||
AddChild(fVScrollBar);
|
||||
}
|
||||
// Create a scroll corner, if we can scroll into both direction.
|
||||
if (fHScrollBar && fVScrollBar) {
|
||||
fScrollCorner = new ScrollCorner(this);
|
||||
AddChild(fScrollCorner);
|
||||
}
|
||||
// add child
|
||||
if (child) {
|
||||
fChild = child;
|
||||
AddChild(child);
|
||||
if (Scrollable* scrollable = dynamic_cast<Scrollable*>(child))
|
||||
SetScrollTarget(scrollable);
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
ScrollView::~ScrollView()
|
||||
{
|
||||
}
|
||||
|
||||
// AllAttached
|
||||
void
|
||||
ScrollView::AllAttached()
|
||||
{
|
||||
// do a first layout
|
||||
_Layout(_UpdateScrollBarVisibility());
|
||||
}
|
||||
|
||||
// Draw
|
||||
void ScrollView::Draw(BRect updateRect)
|
||||
{
|
||||
rgb_color keyboardFocus = keyboard_navigation_color();
|
||||
rgb_color light = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||
B_LIGHTEN_MAX_TINT);
|
||||
rgb_color shadow = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||
B_DARKEN_1_TINT);
|
||||
rgb_color darkShadow = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||
B_DARKEN_2_TINT);
|
||||
rgb_color darkerShadow = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||
B_DARKEN_3_TINT);
|
||||
float left = Bounds().left, right = Bounds().right;
|
||||
float top = Bounds().top, bottom = Bounds().bottom;
|
||||
if (fChildFocused && fWindowActive) {
|
||||
BeginLineArray(4);
|
||||
AddLine(BPoint(left, bottom),
|
||||
BPoint(left, top), keyboardFocus);
|
||||
AddLine(BPoint(left + 1.0, top),
|
||||
BPoint(right, top), keyboardFocus);
|
||||
AddLine(BPoint(right, top + 1.0),
|
||||
BPoint(right, bottom), keyboardFocus);
|
||||
AddLine(BPoint(right - 1.0, bottom),
|
||||
BPoint(left + 1.0, bottom), keyboardFocus);
|
||||
EndLineArray();
|
||||
} else {
|
||||
BeginLineArray(4);
|
||||
AddLine(BPoint(left, bottom),
|
||||
BPoint(left, top), shadow);
|
||||
AddLine(BPoint(left + 1.0, top),
|
||||
BPoint(right, top), shadow);
|
||||
AddLine(BPoint(right, top + 1.0),
|
||||
BPoint(right, bottom), light);
|
||||
AddLine(BPoint(right - 1.0, bottom),
|
||||
BPoint(left + 1.0, bottom), light);
|
||||
EndLineArray();
|
||||
}
|
||||
// The right and bottom lines will be hidden if the scroll views are
|
||||
// visible. But that doesn't harm.
|
||||
BRect innerRect(_InnerRect());
|
||||
left = innerRect.left;
|
||||
top = innerRect.top;
|
||||
right = innerRect.right;
|
||||
bottom = innerRect.bottom;
|
||||
BeginLineArray(4);
|
||||
AddLine(BPoint(left, bottom),
|
||||
BPoint(left, top), darkerShadow);
|
||||
AddLine(BPoint(left + 1.0, top),
|
||||
BPoint(right, top), darkShadow);
|
||||
AddLine(BPoint(right, top + 1.0),
|
||||
BPoint(right, bottom), darkShadow);
|
||||
AddLine(BPoint(right - 1.0, bottom),
|
||||
BPoint(left + 1.0, bottom), darkShadow);
|
||||
EndLineArray();
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
ScrollView::FrameResized(float width, float height)
|
||||
{
|
||||
_Layout(0);
|
||||
}
|
||||
|
||||
// WindowActivated
|
||||
void ScrollView::WindowActivated(bool activated)
|
||||
{
|
||||
fWindowActive = activated;
|
||||
if (fChildFocused)
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// ScrollingFlags
|
||||
uint32
|
||||
ScrollView::ScrollingFlags() const
|
||||
{
|
||||
return fScrollingFlags;
|
||||
}
|
||||
|
||||
// SetVisibleRectIsChildBounds
|
||||
void
|
||||
ScrollView::SetVisibleRectIsChildBounds(bool flag)
|
||||
{
|
||||
if (flag != VisibleRectIsChildBounds()) {
|
||||
if (flag)
|
||||
fScrollingFlags |= SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS;
|
||||
else
|
||||
fScrollingFlags &= ~SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS;
|
||||
if (fChild && _UpdateScrollBarVisibility())
|
||||
_Layout(0);
|
||||
}
|
||||
}
|
||||
|
||||
// VisibleRectIsChildBounds
|
||||
bool
|
||||
ScrollView::VisibleRectIsChildBounds() const
|
||||
{
|
||||
return (fScrollingFlags & SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS);
|
||||
}
|
||||
|
||||
// Child
|
||||
BView*
|
||||
ScrollView::Child() const
|
||||
{
|
||||
return fChild;
|
||||
}
|
||||
|
||||
// ChildFocusChanged
|
||||
//
|
||||
// To be called by the scroll child, when its has got or lost the focus.
|
||||
// We need this to know, when to draw the blue focus frame.
|
||||
void
|
||||
ScrollView::ChildFocusChanged(bool focused)
|
||||
{
|
||||
if (fChildFocused != focused) {
|
||||
fChildFocused = focused;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// HScrollBar
|
||||
BScrollBar*
|
||||
ScrollView::HScrollBar() const
|
||||
{
|
||||
return fHScrollBar;
|
||||
}
|
||||
|
||||
// VScrollBar
|
||||
BScrollBar*
|
||||
ScrollView::VScrollBar() const
|
||||
{
|
||||
return fVScrollBar;
|
||||
}
|
||||
|
||||
// HVScrollCorner
|
||||
BView*
|
||||
ScrollView::HVScrollCorner() const
|
||||
{
|
||||
return fScrollCorner;
|
||||
}
|
||||
|
||||
// SetHSmallStep
|
||||
void
|
||||
ScrollView::SetHSmallStep(float hStep)
|
||||
{
|
||||
SetSmallSteps(hStep, fVSmallStep);
|
||||
}
|
||||
|
||||
// SetVSmallStep
|
||||
void
|
||||
ScrollView::SetVSmallStep(float vStep)
|
||||
{
|
||||
SetSmallSteps(fHSmallStep, vStep);
|
||||
}
|
||||
|
||||
// SetSmallSteps
|
||||
void
|
||||
ScrollView::SetSmallSteps(float hStep, float vStep)
|
||||
{
|
||||
if (fHSmallStep != hStep || fVSmallStep != vStep) {
|
||||
fHSmallStep = hStep;
|
||||
fVSmallStep = vStep;
|
||||
_UpdateScrollBars();
|
||||
}
|
||||
}
|
||||
|
||||
// GetSmallSteps
|
||||
void
|
||||
ScrollView::GetSmallSteps(float* hStep, float* vStep) const
|
||||
{
|
||||
*hStep = fHSmallStep;
|
||||
*vStep = fVSmallStep;
|
||||
}
|
||||
|
||||
// HSmallStep
|
||||
float
|
||||
ScrollView::HSmallStep() const
|
||||
{
|
||||
return fHSmallStep;
|
||||
}
|
||||
|
||||
// VSmallStep
|
||||
float
|
||||
ScrollView::VSmallStep() const
|
||||
{
|
||||
return fVSmallStep;
|
||||
}
|
||||
|
||||
// DataRectChanged
|
||||
void
|
||||
ScrollView::DataRectChanged(BRect /*oldDataRect*/, BRect /*newDataRect*/)
|
||||
{
|
||||
if (ScrollTarget()) {
|
||||
if (_UpdateScrollBarVisibility())
|
||||
_Layout(0);
|
||||
else
|
||||
_UpdateScrollBars();
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollOffsetChanged
|
||||
void
|
||||
ScrollView::ScrollOffsetChanged(BPoint /*oldOffset*/, BPoint newOffset)
|
||||
{
|
||||
if (fHScrollBar && fHScrollBar->Value() != newOffset.x)
|
||||
fHScrollBar->SetValue(newOffset.x);
|
||||
if (fVScrollBar && fVScrollBar->Value() != newOffset.y)
|
||||
fVScrollBar->SetValue(newOffset.y);
|
||||
}
|
||||
|
||||
// VisibleSizeChanged
|
||||
void
|
||||
ScrollView::VisibleSizeChanged(float /*oldWidth*/, float /*oldHeight*/,
|
||||
float /*newWidth*/, float /*newHeight*/)
|
||||
{
|
||||
if (ScrollTarget()) {
|
||||
if (_UpdateScrollBarVisibility())
|
||||
_Layout(0);
|
||||
else
|
||||
_UpdateScrollBars();
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollTargetChanged
|
||||
void
|
||||
ScrollView::ScrollTargetChanged(Scrollable* /*oldTarget*/,
|
||||
Scrollable* newTarget)
|
||||
{
|
||||
/* // remove the old child
|
||||
if (fChild)
|
||||
RemoveChild(fChild);
|
||||
// add the new child
|
||||
BView* view = dynamic_cast<BView*>(newTarget);
|
||||
fChild = view;
|
||||
if (view)
|
||||
AddChild(view);
|
||||
else if (newTarget) // set the scroll target to NULL, if it isn't a BView
|
||||
SetScrollTarget(NULL);
|
||||
*/
|
||||
}
|
||||
|
||||
// _ScrollValueChanged
|
||||
void
|
||||
ScrollView::_ScrollValueChanged(InternalScrollBar* scrollBar, float value)
|
||||
{
|
||||
switch (scrollBar->Orientation()) {
|
||||
case B_HORIZONTAL:
|
||||
if (fHScrollBar)
|
||||
SetScrollOffset(BPoint(value, ScrollOffset().y));
|
||||
break;
|
||||
case B_VERTICAL:
|
||||
if (fVScrollBar)
|
||||
SetScrollOffset(BPoint(ScrollOffset().x, value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// _ScrollCornerValueChanged
|
||||
void
|
||||
ScrollView::_ScrollCornerValueChanged(BPoint offset)
|
||||
{
|
||||
// The logic in Scrollable::SetScrollOffset() handles offsets, that
|
||||
// are out of range.
|
||||
SetScrollOffset(offset);
|
||||
}
|
||||
|
||||
// _Layout
|
||||
//
|
||||
// Relayouts all children (fChild, scroll bars).
|
||||
// flags indicates which scrollbars' visibility has changed.
|
||||
// May be overridden to do a custom layout -- the SCROLL_*_MAGIC must
|
||||
// be disabled in this case, or strange things happen.
|
||||
void
|
||||
ScrollView::_Layout(uint32 flags)
|
||||
{
|
||||
bool hbar = (fHScrollBar && fHVisible);
|
||||
bool vbar = (fVScrollBar && fVVisible);
|
||||
bool corner = (fScrollCorner && fCornerVisible);
|
||||
BRect childRect(_ChildRect());
|
||||
float innerWidth = childRect.Width();
|
||||
float innerHeight = childRect.Height();
|
||||
BPoint scrollLT(_InnerRect().LeftTop());
|
||||
BPoint scrollRB(childRect.RightBottom() + BPoint(1.0f, 1.0f));
|
||||
if (fScrollingFlags & SCROLL_NO_FRAME) {
|
||||
// cut off the top line and left line of the
|
||||
// scroll bars, otherwise they are used for the
|
||||
// frame appearance
|
||||
scrollLT.x--;
|
||||
scrollLT.y--;
|
||||
}
|
||||
// layout scroll bars and scroll corner
|
||||
if (corner) {
|
||||
// In this case the scrollbars overlap one pixel.
|
||||
fHScrollBar->MoveTo(scrollLT.x, scrollRB.y);
|
||||
fHScrollBar->ResizeTo(innerWidth + 2.0, B_H_SCROLL_BAR_HEIGHT);
|
||||
fVScrollBar->MoveTo(scrollRB.x, scrollLT.y);
|
||||
fVScrollBar->ResizeTo(B_V_SCROLL_BAR_WIDTH, innerHeight + 2.0);
|
||||
fScrollCorner->MoveTo(childRect.right + 2.0, childRect.bottom + 2.0);
|
||||
} else if (hbar) {
|
||||
fHScrollBar->MoveTo(scrollLT.x, scrollRB.y);
|
||||
fHScrollBar->ResizeTo(innerWidth + 2.0, B_H_SCROLL_BAR_HEIGHT);
|
||||
} else if (vbar) {
|
||||
fVScrollBar->MoveTo(scrollRB.x, scrollLT.y);
|
||||
fVScrollBar->ResizeTo(B_V_SCROLL_BAR_WIDTH, innerHeight + 2.0);
|
||||
}
|
||||
// layout child
|
||||
if (fChild) {
|
||||
fChild->MoveTo(childRect.LeftTop());
|
||||
fChild->ResizeTo(innerWidth, innerHeight);
|
||||
if (VisibleRectIsChildBounds())
|
||||
SetVisibleSize(innerWidth, innerHeight);
|
||||
// Due to a BeOS bug sometimes the area under a recently hidden
|
||||
// scroll bar isn't updated correctly.
|
||||
// We force this manually: The position of hidden scroll bar isn't
|
||||
// updated any longer, so we can't just invalidate it.
|
||||
if (fChild->Window()) {
|
||||
if (flags & SCROLL_HORIZONTAL && !fHVisible)
|
||||
fChild->Invalidate(fHScrollBar->Frame());
|
||||
if (flags & SCROLL_VERTICAL && !fVVisible)
|
||||
fChild->Invalidate(fVScrollBar->Frame());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _UpdateScrollBars
|
||||
//
|
||||
// Probably somewhat misnamed. This function updates the scroll bars'
|
||||
// proportion, range attributes and step widths according to the scroll
|
||||
// target's DataRect() and VisibleBounds(). May also be called, if there's
|
||||
// no scroll target -- then the scroll bars are disabled.
|
||||
void
|
||||
ScrollView::_UpdateScrollBars()
|
||||
{
|
||||
BRect dataRect = DataRect();
|
||||
BRect visibleBounds = VisibleBounds();
|
||||
if (!fScrollTarget) {
|
||||
dataRect.Set(0.0, 0.0, 0.0, 0.0);
|
||||
visibleBounds.Set(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
float hProportion = min(1.0f, (visibleBounds.Width() + 1.0f) /
|
||||
(dataRect.Width() + 1.0f));
|
||||
float hMaxValue = max(dataRect.left,
|
||||
dataRect.Width() - visibleBounds.Width());
|
||||
float vProportion = min(1.0f, (visibleBounds.Height() + 1.0f) /
|
||||
(dataRect.Height() + 1.0f));
|
||||
float vMaxValue = max(dataRect.top,
|
||||
dataRect.Height() - visibleBounds.Height());
|
||||
// update horizontal scroll bar
|
||||
if (fHScrollBar) {
|
||||
fHScrollBar->SetProportion(hProportion);
|
||||
fHScrollBar->SetRange(dataRect.left, hMaxValue);
|
||||
// This obviously ineffective line works around a BScrollBar bug:
|
||||
// As documented the scrollbar's value is adjusted, if the range
|
||||
// has been changed and it therefore falls out of the range. But if,
|
||||
// after resetting the range to what it has been before, the user
|
||||
// moves the scrollbar to the original value via one click
|
||||
// it is failed to invoke BScrollBar::ValueChanged().
|
||||
fHScrollBar->SetValue(fHScrollBar->Value());
|
||||
fHScrollBar->SetSteps(fHSmallStep, visibleBounds.Width());
|
||||
}
|
||||
// update vertical scroll bar
|
||||
if (fVScrollBar) {
|
||||
fVScrollBar->SetProportion(vProportion);
|
||||
fVScrollBar->SetRange(dataRect.top, vMaxValue);
|
||||
// This obviously ineffective line works around a BScrollBar bug.
|
||||
fVScrollBar->SetValue(fVScrollBar->Value());
|
||||
fVScrollBar->SetSteps(fVSmallStep, visibleBounds.Height());
|
||||
}
|
||||
// update scroll corner
|
||||
if (fScrollCorner) {
|
||||
fScrollCorner->SetActive(hProportion < 1.0f || vProportion < 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// set_visible_state
|
||||
//
|
||||
// Convenience function: Sets a view's visibility state to /visible/.
|
||||
// Returns true, if the state was actually changed, false otherwise.
|
||||
// This function never calls Hide() on a hidden or Show() on a visible
|
||||
// view. /view/ must be valid.
|
||||
static inline
|
||||
bool
|
||||
set_visible_state(BView* view, bool visible, bool* currentlyVisible)
|
||||
{
|
||||
bool changed = false;
|
||||
if (*currentlyVisible != visible) {
|
||||
if (visible)
|
||||
view->Show();
|
||||
else
|
||||
view->Hide();
|
||||
*currentlyVisible = visible;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// _UpdateScrollBarVisibility
|
||||
//
|
||||
// Checks which of scroll bars need to be visible according to
|
||||
// SCROLL_*_MAGIG and shows/hides them, if necessary.
|
||||
// Returns a bitwise combination of SCROLL_HORIZONTAL and SCROLL_VERTICAL
|
||||
// according to which scroll bar's visibility state has changed, 0 if none.
|
||||
// A return value != 0 usually means that the layout isn't valid any longer.
|
||||
uint32
|
||||
ScrollView::_UpdateScrollBarVisibility()
|
||||
{
|
||||
uint32 changed = 0;
|
||||
BRect childRect(_MaxVisibleRect());
|
||||
float width = childRect.Width();
|
||||
float height = childRect.Height();
|
||||
BRect dataRect = DataRect(); // Invalid if !ScrollTarget(),
|
||||
float dataWidth = dataRect.Width(); // but that doesn't harm.
|
||||
float dataHeight = dataRect.Height(); //
|
||||
bool hbar = (fScrollingFlags & SCROLL_HORIZONTAL_MAGIC);
|
||||
bool vbar = (fScrollingFlags & SCROLL_VERTICAL_MAGIC);
|
||||
if (!ScrollTarget()) {
|
||||
if (hbar) {
|
||||
if (set_visible_state(fHScrollBar, false, &fHVisible))
|
||||
changed |= SCROLL_HORIZONTAL;
|
||||
}
|
||||
if (vbar) {
|
||||
if (set_visible_state(fVScrollBar, false, &fVVisible))
|
||||
changed |= SCROLL_VERTICAL;
|
||||
}
|
||||
} else if (hbar && width >= dataWidth && vbar && height >= dataHeight) {
|
||||
// none
|
||||
if (set_visible_state(fHScrollBar, false, &fHVisible))
|
||||
changed |= SCROLL_HORIZONTAL;
|
||||
if (set_visible_state(fVScrollBar, false, &fVVisible))
|
||||
changed |= SCROLL_VERTICAL;
|
||||
} else {
|
||||
// The case, that both scroll bars are magic and invisible is catched,
|
||||
// so that while checking one bar we can suppose, that the other one
|
||||
// is visible (if it does exist at all).
|
||||
BRect innerRect(_GuessVisibleRect(fHScrollBar, fVScrollBar));
|
||||
float innerWidth = innerRect.Width();
|
||||
float innerHeight = innerRect.Height();
|
||||
// the horizontal one?
|
||||
if (hbar) {
|
||||
if (innerWidth >= dataWidth) {
|
||||
if (set_visible_state(fHScrollBar, false, &fHVisible))
|
||||
changed |= SCROLL_HORIZONTAL;
|
||||
} else {
|
||||
if (set_visible_state(fHScrollBar, true, &fHVisible))
|
||||
changed |= SCROLL_HORIZONTAL;
|
||||
}
|
||||
}
|
||||
// the vertical one?
|
||||
if (vbar) {
|
||||
if (innerHeight >= dataHeight) {
|
||||
if (set_visible_state(fVScrollBar, false, &fVVisible))
|
||||
changed |= SCROLL_VERTICAL;
|
||||
} else {
|
||||
if (set_visible_state(fVScrollBar, true, &fVVisible))
|
||||
changed |= SCROLL_VERTICAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If anything has changed, update the scroll corner as well.
|
||||
if (changed && fScrollCorner)
|
||||
set_visible_state(fScrollCorner, fHVisible && fVVisible, &fCornerVisible);
|
||||
return changed;
|
||||
}
|
||||
|
||||
// _InnerRect
|
||||
//
|
||||
// Returns the rectangle that actually can be used for the child and the
|
||||
// scroll bars, i.e. the view's Bounds() subtracted the space for the
|
||||
// decorative frame.
|
||||
BRect
|
||||
ScrollView::_InnerRect() const
|
||||
{
|
||||
if (fScrollingFlags & SCROLL_NO_FRAME)
|
||||
return Bounds();
|
||||
return Bounds().InsetBySelf(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// _ChildRect
|
||||
//
|
||||
// Returns the rectangle, that should be the current child frame.
|
||||
// `should' because 1. we might not have a child at all or 2. a
|
||||
// relayout is pending.
|
||||
BRect
|
||||
ScrollView::_ChildRect() const
|
||||
{
|
||||
return _ChildRect(fHScrollBar && fHVisible, fVScrollBar && fVVisible);
|
||||
}
|
||||
|
||||
// _ChildRect
|
||||
//
|
||||
// The same as _ChildRect() with the exception that not the current
|
||||
// scroll bar visibility, but a fictitious one given by /hbar/ and /vbar/
|
||||
// is considered.
|
||||
BRect
|
||||
ScrollView::_ChildRect(bool hbar, bool vbar) const
|
||||
{
|
||||
BRect rect(_InnerRect());
|
||||
float frameWidth = (fScrollingFlags & SCROLL_NO_FRAME) ? 0.0 : 1.0;
|
||||
|
||||
if (hbar)
|
||||
rect.bottom -= B_H_SCROLL_BAR_HEIGHT + frameWidth;
|
||||
else
|
||||
rect.bottom -= frameWidth;
|
||||
if (vbar)
|
||||
rect.right -= B_V_SCROLL_BAR_WIDTH + frameWidth;
|
||||
else
|
||||
rect.right -= frameWidth;
|
||||
rect.top += frameWidth;
|
||||
rect.left += frameWidth;
|
||||
return rect;
|
||||
}
|
||||
|
||||
// _GuessVisibleRect
|
||||
//
|
||||
// Returns an approximation of the visible rect for the
|
||||
// fictitious scroll bar visibility given by /hbar/ and /vbar/.
|
||||
// In the case !VisibleRectIsChildBounds() it is simply the current
|
||||
// visible rect.
|
||||
BRect
|
||||
ScrollView::_GuessVisibleRect(bool hbar, bool vbar) const
|
||||
{
|
||||
if (VisibleRectIsChildBounds())
|
||||
return _ChildRect(hbar, vbar).OffsetToCopy(ScrollOffset());
|
||||
return VisibleRect();
|
||||
}
|
||||
|
||||
// _MaxVisibleRect
|
||||
//
|
||||
// Returns the maximal possible visible rect in the current situation, that
|
||||
// is depending on if the visible rect is the child's bounds either the
|
||||
// rectangle the child covers when both scroll bars are hidden (offset to
|
||||
// the scroll offset) or the current visible rect.
|
||||
BRect
|
||||
ScrollView::_MaxVisibleRect() const
|
||||
{
|
||||
return _GuessVisibleRect(true, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SCROLL_VIEW_H
|
||||
#define SCROLL_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include "Scroller.h"
|
||||
|
||||
class Scrollable;
|
||||
class InternalScrollBar;
|
||||
class ScrollCorner;
|
||||
|
||||
enum {
|
||||
SCROLL_HORIZONTAL = 0x01,
|
||||
SCROLL_VERTICAL = 0x02,
|
||||
SCROLL_HORIZONTAL_MAGIC = 0x04,
|
||||
SCROLL_VERTICAL_MAGIC = 0x08,
|
||||
SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS = 0x10,
|
||||
SCROLL_NO_FRAME = 0x20,
|
||||
};
|
||||
|
||||
class ScrollView : public BView, public Scroller {
|
||||
public:
|
||||
ScrollView(BView* child,
|
||||
uint32 scrollingFlags,
|
||||
BRect frame,
|
||||
const char *name,
|
||||
uint32 resizingMode, uint32 flags);
|
||||
virtual ~ScrollView();
|
||||
|
||||
virtual void AllAttached();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void WindowActivated(bool activated);
|
||||
|
||||
uint32 ScrollingFlags() const;
|
||||
void SetVisibleRectIsChildBounds(bool flag);
|
||||
bool VisibleRectIsChildBounds() const;
|
||||
|
||||
BView* Child() const;
|
||||
void ChildFocusChanged(bool focused);
|
||||
|
||||
BScrollBar* HScrollBar() const;
|
||||
BScrollBar* VScrollBar() const;
|
||||
BView* HVScrollCorner() const;
|
||||
|
||||
void SetHSmallStep(float hStep);
|
||||
void SetVSmallStep(float vStep);
|
||||
void SetSmallSteps(float hStep, float vStep);
|
||||
void GetSmallSteps(float* hStep,
|
||||
float* vStep) const;
|
||||
float HSmallStep() const;
|
||||
float VSmallStep() const;
|
||||
|
||||
protected:
|
||||
virtual void DataRectChanged(BRect oldDataRect,
|
||||
BRect newDataRect);
|
||||
virtual void ScrollOffsetChanged(BPoint oldOffset,
|
||||
BPoint newOffset);
|
||||
virtual void VisibleSizeChanged(float oldWidth,
|
||||
float oldHeight,
|
||||
float newWidth,
|
||||
float newHeight);
|
||||
virtual void ScrollTargetChanged(Scrollable* oldTarget,
|
||||
Scrollable* newTarget);
|
||||
|
||||
private:
|
||||
BView* fChild; // child view
|
||||
uint32 fScrollingFlags;
|
||||
InternalScrollBar* fHScrollBar; // horizontal scroll bar
|
||||
InternalScrollBar* fVScrollBar; // vertical scroll bar
|
||||
ScrollCorner* fScrollCorner; // scroll corner
|
||||
bool fHVisible; // horizontal/vertical scroll
|
||||
bool fVVisible; // bar visible flag
|
||||
bool fCornerVisible; // scroll corner visible flag
|
||||
bool fWindowActive;
|
||||
bool fChildFocused;
|
||||
float fHSmallStep;
|
||||
float fVSmallStep;
|
||||
|
||||
void _ScrollValueChanged(
|
||||
InternalScrollBar* scrollBar,
|
||||
float value);
|
||||
void _ScrollCornerValueChanged(BPoint offset);
|
||||
|
||||
protected:
|
||||
virtual void _Layout(uint32 flags);
|
||||
|
||||
private:
|
||||
void _UpdateScrollBars();
|
||||
uint32 _UpdateScrollBarVisibility();
|
||||
|
||||
BRect _InnerRect() const;
|
||||
BRect _ChildRect() const;
|
||||
BRect _ChildRect(bool hbar, bool vbar) const;
|
||||
BRect _GuessVisibleRect(bool hbar, bool vbar) const;
|
||||
BRect _MaxVisibleRect() const;
|
||||
|
||||
friend class InternalScrollBar;
|
||||
friend class ScrollCorner;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // SCROLL_VIEW_H
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Scrollable.h"
|
||||
|
||||
#include <algobase.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Scroller.h"
|
||||
|
||||
// constructor
|
||||
Scrollable::Scrollable()
|
||||
: fDataRect(0.0, 0.0, 0.0, 0.0),
|
||||
fScrollOffset(0.0, 0.0),
|
||||
fVisibleWidth(0),
|
||||
fVisibleHeight(0),
|
||||
fScrollSource(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Scrollable::~Scrollable()
|
||||
{
|
||||
if (fScrollSource)
|
||||
fScrollSource->SetScrollTarget(NULL);
|
||||
}
|
||||
|
||||
// SetScrollSource
|
||||
//
|
||||
// Sets a new scroll source. Notifies the old and the new source
|
||||
// of the change if necessary .
|
||||
void
|
||||
Scrollable::SetScrollSource(Scroller* source)
|
||||
{
|
||||
Scroller* oldSource = fScrollSource;
|
||||
if (oldSource != source) {
|
||||
fScrollSource = NULL;
|
||||
// Notify the old source, if it doesn't know about the change.
|
||||
if (oldSource && oldSource->ScrollTarget() == this)
|
||||
fScrollSource->SetScrollTarget(NULL);
|
||||
fScrollSource = source;
|
||||
// Notify the new source, if it doesn't know about the change.
|
||||
if (source && source->ScrollTarget() != this)
|
||||
source->SetScrollTarget(this);
|
||||
// Notify ourselves.
|
||||
ScrollSourceChanged(oldSource, fScrollSource);
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollSource
|
||||
//
|
||||
// Returns the current scroll source. May be NULL, if we don't have any.
|
||||
Scroller*
|
||||
Scrollable::ScrollSource() const
|
||||
{
|
||||
return fScrollSource;
|
||||
}
|
||||
|
||||
// SetDataRect
|
||||
//
|
||||
// Sets the data rect.
|
||||
void
|
||||
Scrollable::SetDataRect(BRect dataRect)
|
||||
{
|
||||
if (fDataRect != dataRect && dataRect.IsValid()) {
|
||||
BRect oldDataRect = fDataRect;
|
||||
fDataRect = dataRect;
|
||||
// notify ourselves
|
||||
DataRectChanged(oldDataRect, fDataRect);
|
||||
// notify scroller
|
||||
if (fScrollSource)
|
||||
fScrollSource->DataRectChanged(oldDataRect, fDataRect);
|
||||
// adjust the scroll offset, if necessary
|
||||
BPoint offset = _ValidScrollOffsetFor(fScrollOffset);
|
||||
if (offset != fScrollOffset)
|
||||
SetScrollOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// DataRect
|
||||
//
|
||||
// Returns the current data rect.
|
||||
BRect
|
||||
Scrollable::DataRect() const
|
||||
{
|
||||
return fDataRect;
|
||||
}
|
||||
|
||||
// SetScrollOffset
|
||||
//
|
||||
// Sets the scroll offset.
|
||||
void
|
||||
Scrollable::SetScrollOffset(BPoint offset)
|
||||
{
|
||||
// adjust the supplied offset to be valid
|
||||
offset = _ValidScrollOffsetFor(offset);
|
||||
if (fScrollOffset != offset) {
|
||||
BPoint oldOffset = fScrollOffset;
|
||||
fScrollOffset = offset;
|
||||
// notify ourselves
|
||||
ScrollOffsetChanged(oldOffset, fScrollOffset);
|
||||
// notify scroller
|
||||
if (fScrollSource)
|
||||
fScrollSource->ScrollOffsetChanged(oldOffset, fScrollOffset);
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollOffset
|
||||
//
|
||||
// Returns the current scroll offset.
|
||||
BPoint
|
||||
Scrollable::ScrollOffset() const
|
||||
{
|
||||
return fScrollOffset;
|
||||
}
|
||||
|
||||
// SetVisibleSize
|
||||
//
|
||||
// Sets the visible size.
|
||||
void
|
||||
Scrollable::SetVisibleSize(float width, float height)
|
||||
{
|
||||
if ((fVisibleWidth != width || fVisibleHeight != height) &&
|
||||
width >= 0 && height >= 0) {
|
||||
float oldWidth = fVisibleWidth;
|
||||
float oldHeight = fVisibleHeight;
|
||||
fVisibleWidth = width;
|
||||
fVisibleHeight = height;
|
||||
// notify ourselves
|
||||
VisibleSizeChanged(oldWidth, oldHeight, fVisibleWidth, fVisibleHeight);
|
||||
// notify scroller
|
||||
if (fScrollSource) {
|
||||
fScrollSource->VisibleSizeChanged(oldWidth, oldHeight,
|
||||
fVisibleWidth, fVisibleHeight);
|
||||
}
|
||||
// adjust the scroll offset, if necessary
|
||||
BPoint offset = _ValidScrollOffsetFor(fScrollOffset);
|
||||
if (offset != fScrollOffset)
|
||||
SetScrollOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
// VisibleBounds
|
||||
//
|
||||
// Returns the visible bounds, i.e. a rectangle of the visible size
|
||||
// located at (0.0, 0.0).
|
||||
BRect
|
||||
Scrollable::VisibleBounds() const
|
||||
{
|
||||
return BRect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
|
||||
}
|
||||
|
||||
// VisibleRect
|
||||
//
|
||||
// Returns the visible rect, i.e. a rectangle of the visible size located
|
||||
// at the scroll offset.
|
||||
BRect
|
||||
Scrollable::VisibleRect() const
|
||||
{
|
||||
BRect rect(0.0, 0.0, fVisibleWidth, fVisibleHeight);
|
||||
rect.OffsetBy(fScrollOffset);
|
||||
return rect;
|
||||
}
|
||||
|
||||
// DataRectChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the data rect has changed.
|
||||
void
|
||||
Scrollable::DataRectChanged(BRect /*oldDataRect*/, BRect /*newDataRect*/)
|
||||
{
|
||||
}
|
||||
|
||||
// ScrollOffsetChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the scroll offset has changed.
|
||||
void
|
||||
Scrollable::ScrollOffsetChanged(BPoint /*oldOffset*/, BPoint /*newOffset*/)
|
||||
{
|
||||
}
|
||||
|
||||
// VisibleSizeChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the visible size has changed.
|
||||
void
|
||||
Scrollable::VisibleSizeChanged(float /*oldWidth*/, float /*oldHeight*/,
|
||||
float /*newWidth*/, float /*newHeight*/)
|
||||
{
|
||||
}
|
||||
|
||||
// ScrollSourceChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the scroll source has changed.
|
||||
void
|
||||
Scrollable::ScrollSourceChanged(Scroller* /*oldSource*/,
|
||||
Scroller* /*newSource*/)
|
||||
{
|
||||
}
|
||||
|
||||
// _ValidScrollOffsetFor
|
||||
//
|
||||
// Returns the valid scroll offset next to the supplied offset.
|
||||
BPoint
|
||||
Scrollable::_ValidScrollOffsetFor(BPoint offset) const
|
||||
{
|
||||
float maxX = max(fDataRect.left, fDataRect.Width() - fVisibleWidth);
|
||||
float maxY = max(fDataRect.top, fDataRect.Height() - fVisibleHeight);
|
||||
// adjust the offset to be valid
|
||||
if (offset.x < fDataRect.left)
|
||||
offset.x = fDataRect.left;
|
||||
else if (offset.x > maxX)
|
||||
offset.x = maxX;
|
||||
if (offset.y < fDataRect.top)
|
||||
offset.y = fDataRect.top;
|
||||
else if (offset.y > maxY)
|
||||
offset.y = maxY;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SCROLLABLE_H
|
||||
#define SCROLLABLE_H
|
||||
|
||||
#include <Point.h>
|
||||
#include <Rect.h>
|
||||
|
||||
class Scroller;
|
||||
|
||||
class Scrollable {
|
||||
public:
|
||||
Scrollable();
|
||||
virtual ~Scrollable();
|
||||
|
||||
void SetScrollSource(Scroller* source);
|
||||
Scroller* ScrollSource() const;
|
||||
|
||||
void SetDataRect(BRect dataRect);
|
||||
BRect DataRect() const;
|
||||
|
||||
void SetScrollOffset(BPoint offset);
|
||||
BPoint ScrollOffset() const;
|
||||
|
||||
void SetVisibleSize(float width, float height);
|
||||
BRect VisibleBounds() const;
|
||||
BRect VisibleRect() const;
|
||||
|
||||
protected:
|
||||
virtual void DataRectChanged(BRect oldDataRect,
|
||||
BRect newDataRect);
|
||||
virtual void ScrollOffsetChanged(BPoint oldOffset,
|
||||
BPoint newOffset);
|
||||
virtual void VisibleSizeChanged(float oldWidth,
|
||||
float oldHeight,
|
||||
float newWidth,
|
||||
float newHeight);
|
||||
virtual void ScrollSourceChanged(Scroller* oldSource,
|
||||
Scroller* newSource);
|
||||
|
||||
private:
|
||||
BRect fDataRect;
|
||||
BPoint fScrollOffset;
|
||||
float fVisibleWidth;
|
||||
float fVisibleHeight;
|
||||
Scroller* fScrollSource;
|
||||
|
||||
BPoint _ValidScrollOffsetFor(BPoint offset) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // SCROLLABLE_H
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ScrollableView.h"
|
||||
|
||||
#include <View.h>
|
||||
|
||||
// constructor
|
||||
ScrollableView::ScrollableView()
|
||||
: Scrollable()
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ScrollableView::~ScrollableView()
|
||||
{
|
||||
}
|
||||
|
||||
// ScrollOffsetChanged
|
||||
void
|
||||
ScrollableView::ScrollOffsetChanged(BPoint oldOffset, BPoint newOffset)
|
||||
{
|
||||
if (BView* view = dynamic_cast<BView*>(this)) {
|
||||
// We keep it simple: The part of the data rect we shall show now
|
||||
// has existed before as well (even if partially or completely
|
||||
// obscured), so we let CopyBits() do the messy details.
|
||||
BRect bounds(view->Bounds());
|
||||
view->CopyBits(bounds.OffsetByCopy(newOffset - oldOffset), bounds);
|
||||
// move our children
|
||||
for (int32 i = 0; BView* child = view->ChildAt(i); i++)
|
||||
child->MoveTo(child->Frame().LeftTop() + oldOffset - newOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
/** Simple extension to the Scrollable class to simplify the creation
|
||||
of derived view classes. */
|
||||
|
||||
#ifndef SCROLLABLE_VIEW_H
|
||||
#define SCROLLABLE_VIEW_H
|
||||
|
||||
#include "Scrollable.h"
|
||||
|
||||
class ScrollableView : public Scrollable {
|
||||
public:
|
||||
ScrollableView();
|
||||
virtual ~ScrollableView();
|
||||
|
||||
protected:
|
||||
virtual void ScrollOffsetChanged(BPoint oldOffset,
|
||||
BPoint newOffset);
|
||||
};
|
||||
|
||||
|
||||
#endif // SCROLLABLE_VIEW_H
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Scroller.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Point.h>
|
||||
#include <Rect.h>
|
||||
|
||||
#include "Scrollable.h"
|
||||
|
||||
// constructor
|
||||
Scroller::Scroller()
|
||||
: fScrollTarget(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Scroller::~Scroller()
|
||||
{
|
||||
}
|
||||
|
||||
// SetScrollTarget
|
||||
//
|
||||
// Sets a new scroll target. Notifies the old and the new target
|
||||
// of the change if necessary .
|
||||
void
|
||||
Scroller::SetScrollTarget(Scrollable* target)
|
||||
{
|
||||
Scrollable* oldTarget = fScrollTarget;
|
||||
if (oldTarget != target) {
|
||||
fScrollTarget = NULL;
|
||||
// Notify the old target, if it doesn't know about the change.
|
||||
if (oldTarget && oldTarget->ScrollSource() == this)
|
||||
oldTarget->SetScrollSource(NULL);
|
||||
fScrollTarget = target;
|
||||
// Notify the new target, if it doesn't know about the change.
|
||||
if (target && target->ScrollSource() != this)
|
||||
target->SetScrollSource(this);
|
||||
// Notify ourselves.
|
||||
ScrollTargetChanged(oldTarget, target);
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollTarget
|
||||
//
|
||||
// Returns the current scroll target. May be NULL, if we don't have any.
|
||||
Scrollable*
|
||||
Scroller::ScrollTarget() const
|
||||
{
|
||||
return fScrollTarget;
|
||||
}
|
||||
|
||||
// SetDataRect
|
||||
//
|
||||
// Sets the data rect of the scroll target, if we have one.
|
||||
void
|
||||
Scroller::SetDataRect(BRect dataRect)
|
||||
{
|
||||
if (fScrollTarget)
|
||||
fScrollTarget->SetDataRect(dataRect);
|
||||
}
|
||||
|
||||
// DataRect
|
||||
//
|
||||
// Returns the data rect of the scroll target or a undefined value, if
|
||||
// we have none.
|
||||
BRect
|
||||
Scroller::DataRect() const
|
||||
{
|
||||
if (fScrollTarget)
|
||||
return fScrollTarget->DataRect();
|
||||
return BRect();
|
||||
}
|
||||
|
||||
// SetScrollOffset
|
||||
//
|
||||
// Sets the scroll offset of the scroll target, if we have one.
|
||||
void
|
||||
Scroller::SetScrollOffset(BPoint offset)
|
||||
{
|
||||
if (fScrollTarget)
|
||||
fScrollTarget->SetScrollOffset(offset);
|
||||
}
|
||||
|
||||
// ScrollOffset
|
||||
//
|
||||
// Returns the scroll offset of the scroll target or a undefined value, if
|
||||
// we have none.
|
||||
BPoint
|
||||
Scroller::ScrollOffset() const
|
||||
{
|
||||
if (fScrollTarget)
|
||||
return fScrollTarget->ScrollOffset();
|
||||
return BPoint(0.0, 0.0);
|
||||
}
|
||||
|
||||
// SetVisibleSize
|
||||
//
|
||||
// Sets the visible size of the scroll target, if we have one.
|
||||
void
|
||||
Scroller::SetVisibleSize(float width, float height)
|
||||
{
|
||||
if (fScrollTarget)
|
||||
fScrollTarget->SetVisibleSize(width, height);
|
||||
}
|
||||
|
||||
// VisibleBounds
|
||||
//
|
||||
// Returns the visible bounds of the scroll target or a undefined value, if
|
||||
// we have none.
|
||||
BRect
|
||||
Scroller::VisibleBounds() const
|
||||
{
|
||||
if (fScrollTarget)
|
||||
return fScrollTarget->VisibleBounds();
|
||||
return BRect();
|
||||
}
|
||||
|
||||
// VisibleRect
|
||||
//
|
||||
// Returns the visible rect of the scroll target or a undefined value, if
|
||||
// we have none.
|
||||
BRect
|
||||
Scroller::VisibleRect() const
|
||||
{
|
||||
if (fScrollTarget)
|
||||
return fScrollTarget->VisibleRect();
|
||||
return BRect();
|
||||
}
|
||||
|
||||
|
||||
// hooks
|
||||
|
||||
// DataRectChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the data rect of the sroll target has changed.
|
||||
void
|
||||
Scroller::DataRectChanged(BRect /*oldDataRect*/, BRect /*newDataRect*/)
|
||||
{
|
||||
}
|
||||
|
||||
// ScrollOffsetChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the scroll offset of the sroll target has changed.
|
||||
void
|
||||
Scroller::ScrollOffsetChanged(BPoint /*oldOffset*/, BPoint /*newOffset*/)
|
||||
{
|
||||
}
|
||||
|
||||
// VisiblSizeChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the visible size of the sroll target has changed.
|
||||
void
|
||||
Scroller::VisibleSizeChanged(float /*oldWidth*/, float /*oldHeight*/,
|
||||
float /*newWidth*/, float /*newHeight*/)
|
||||
{
|
||||
}
|
||||
|
||||
// ScrollTargetChanged
|
||||
//
|
||||
// Hook function. Implemented by derived classes to get notified when
|
||||
// the sroll target has changed. /target/ may be NULL.
|
||||
void
|
||||
Scroller::ScrollTargetChanged(Scrollable* /*oldTarget*/,
|
||||
Scrollable* /*newTarget*/)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SCROLLER_H
|
||||
#define SCROLLER_H
|
||||
|
||||
class Scrollable;
|
||||
|
||||
class Scroller {
|
||||
public:
|
||||
Scroller();
|
||||
virtual ~Scroller();
|
||||
|
||||
void SetScrollTarget(Scrollable* target);
|
||||
Scrollable* ScrollTarget() const;
|
||||
|
||||
void SetDataRect(BRect dataRect);
|
||||
BRect DataRect() const;
|
||||
|
||||
void SetScrollOffset(BPoint offset);
|
||||
BPoint ScrollOffset() const;
|
||||
|
||||
void SetVisibleSize(float width, float height);
|
||||
BRect VisibleBounds() const;
|
||||
BRect VisibleRect() const;
|
||||
|
||||
protected:
|
||||
virtual void DataRectChanged(BRect oldDataRect,
|
||||
BRect newDataRect);
|
||||
virtual void ScrollOffsetChanged(BPoint oldOffset,
|
||||
BPoint newOffset);
|
||||
virtual void VisibleSizeChanged(float oldWidth,
|
||||
float oldHeight,
|
||||
float newWidth,
|
||||
float newHeight);
|
||||
virtual void ScrollTargetChanged(Scrollable* oldTarget,
|
||||
Scrollable* newTarget);
|
||||
|
||||
protected:
|
||||
Scrollable* fScrollTarget;
|
||||
|
||||
friend class Scrollable;
|
||||
};
|
||||
|
||||
|
||||
#endif // SCROLLER_H
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Manipulator.h"
|
||||
|
||||
#include "Observable.h"
|
||||
|
||||
// constructor
|
||||
Manipulator::Manipulator(Observable* object)
|
||||
: Observer(),
|
||||
fManipulatedObject(object)
|
||||
{
|
||||
if (fManipulatedObject)
|
||||
fManipulatedObject->AddObserver(this);
|
||||
}
|
||||
|
||||
// destructor
|
||||
Manipulator::~Manipulator()
|
||||
{
|
||||
if (fManipulatedObject)
|
||||
fManipulatedObject->RemoveObserver(this);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Draw
|
||||
void
|
||||
Manipulator::Draw(BView* into, BRect updateRect)
|
||||
{
|
||||
}
|
||||
|
||||
// MouseDown
|
||||
bool
|
||||
Manipulator::MouseDown(BPoint where)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
Manipulator::MouseMoved(BPoint where)
|
||||
{
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
Command*
|
||||
Manipulator::MouseUp()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// MouseOver
|
||||
bool
|
||||
Manipulator::MouseOver(BPoint where)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// DoubleClicked
|
||||
bool
|
||||
Manipulator::DoubleClicked(BPoint where)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
bool
|
||||
Manipulator::MessageReceived(BMessage* message, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ModifiersChanged
|
||||
void
|
||||
Manipulator::ModifiersChanged(uint32 modifiers)
|
||||
{
|
||||
}
|
||||
|
||||
// HandleKeyDown
|
||||
bool
|
||||
Manipulator::HandleKeyDown(uint32 key, uint32 modifiers, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// HandleKeyUp
|
||||
bool
|
||||
Manipulator::HandleKeyUp(uint32 key, uint32 modifiers, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// UpdateCursor
|
||||
void
|
||||
Manipulator::UpdateCursor()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// TrackingBounds
|
||||
BRect
|
||||
Manipulator::TrackingBounds(BView* withinView)
|
||||
{
|
||||
return Bounds();
|
||||
}
|
||||
|
||||
// AttachedToView
|
||||
void
|
||||
Manipulator::AttachedToView(BView* view)
|
||||
{
|
||||
}
|
||||
|
||||
// DetachedFromView
|
||||
void
|
||||
Manipulator::DetachedFromView(BView* view)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef MANIPULATOR_H
|
||||
#define MANIPULATOR_H
|
||||
|
||||
#include <Rect.h>
|
||||
|
||||
#include "Observer.h"
|
||||
|
||||
class BView;
|
||||
class Command;
|
||||
|
||||
// TODO: merge ViewState and Manipulator
|
||||
|
||||
class Manipulator : public Observer {
|
||||
public:
|
||||
Manipulator(Observable* object);
|
||||
virtual ~Manipulator();
|
||||
|
||||
// Manipulator interface
|
||||
virtual void Draw(BView* into, BRect updateRect);
|
||||
|
||||
virtual bool MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where);
|
||||
virtual Command* MouseUp();
|
||||
virtual bool MouseOver(BPoint where);
|
||||
virtual bool DoubleClicked(BPoint where);
|
||||
|
||||
virtual bool MessageReceived(BMessage* message,
|
||||
Command** _command);
|
||||
|
||||
virtual void ModifiersChanged(uint32 modifiers);
|
||||
virtual bool HandleKeyDown(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
virtual bool HandleKeyUp(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
|
||||
virtual void UpdateCursor();
|
||||
|
||||
virtual BRect Bounds() = 0;
|
||||
// the area that the manipulator is
|
||||
// occupying in the "parent" view
|
||||
virtual BRect TrackingBounds(BView* withinView);
|
||||
// the area within "view" in which the
|
||||
// Manipulator wants to receive MouseOver()
|
||||
// events
|
||||
|
||||
virtual void AttachedToView(BView* view);
|
||||
virtual void DetachedFromView(BView* view);
|
||||
|
||||
protected:
|
||||
Observable* fManipulatedObject;
|
||||
};
|
||||
|
||||
#endif // MANIPULATOR_H
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "MultipleManipulatorState.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Manipulator.h"
|
||||
#include "StateView.h"
|
||||
|
||||
// constructor
|
||||
MultipleManipulatorState::MultipleManipulatorState(StateView* view)
|
||||
: ViewState(view),
|
||||
fManipulators(24),
|
||||
fCurrentManipulator(NULL),
|
||||
fPreviousManipulator(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
MultipleManipulatorState::~MultipleManipulatorState()
|
||||
{
|
||||
DeleteManipulators();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Init
|
||||
void
|
||||
MultipleManipulatorState::Init()
|
||||
{
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
void
|
||||
MultipleManipulatorState::Cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Draw
|
||||
void
|
||||
MultipleManipulatorState::Draw(BView* into, BRect updateRect)
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->Bounds().Intersects(updateRect))
|
||||
manipulator->Draw(into, updateRect);
|
||||
}
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
bool
|
||||
MultipleManipulatorState::MessageReceived(BMessage* message,
|
||||
Command** _command)
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->MessageReceived(message, _command))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
MultipleManipulatorState::MouseDown(BPoint where, uint32 buttons, uint32 clicks)
|
||||
{
|
||||
// NOTE: buttons currently ignored
|
||||
|
||||
if (clicks == 2
|
||||
&& fPreviousManipulator
|
||||
&& fManipulators.HasItem(fPreviousManipulator)) {
|
||||
// valid double click (onto the same, still existing manipulator)
|
||||
if (fPreviousManipulator->TrackingBounds(fView).Contains(where)
|
||||
&& fPreviousManipulator->DoubleClicked(where)) {
|
||||
// TODO: eat the click here or wait for MouseUp?
|
||||
fPreviousManipulator = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = count - 1; i >= 0; i--) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->MouseDown(where)) {
|
||||
fCurrentManipulator = manipulator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fView->SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
MultipleManipulatorState::MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage)
|
||||
{
|
||||
if (fCurrentManipulator) {
|
||||
// the mouse is currently pressed
|
||||
fCurrentManipulator->MouseMoved(where);
|
||||
|
||||
} else {
|
||||
// the mouse is currently NOT pressed
|
||||
|
||||
// call MouseOver on all manipulators
|
||||
// until one feels responsible
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->TrackingBounds(fView).Contains(where)
|
||||
&& manipulator->MouseOver(where)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
Command*
|
||||
MultipleManipulatorState::MouseUp()
|
||||
{
|
||||
Command* command = NULL;
|
||||
if (fCurrentManipulator) {
|
||||
command = fCurrentManipulator->MouseUp();
|
||||
fPreviousManipulator = fCurrentManipulator;
|
||||
fCurrentManipulator = NULL;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ModifiersChanged
|
||||
void
|
||||
MultipleManipulatorState::ModifiersChanged(uint32 modifiers)
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
manipulator->ModifiersChanged(modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
// HandleKeyDown
|
||||
bool
|
||||
MultipleManipulatorState::HandleKeyDown(uint32 key, uint32 modifiers,
|
||||
Command** _command)
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->HandleKeyDown(key, modifiers, _command))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// HandleKeyUp
|
||||
bool
|
||||
MultipleManipulatorState::HandleKeyUp(uint32 key, uint32 modifiers,
|
||||
Command** _command)
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* manipulator =
|
||||
(Manipulator*)fManipulators.ItemAtFast(i);
|
||||
if (manipulator->HandleKeyUp(key, modifiers, _command))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AddManipulator
|
||||
bool
|
||||
MultipleManipulatorState::AddManipulator(Manipulator* manipulator)
|
||||
{
|
||||
if (!manipulator)
|
||||
return false;
|
||||
|
||||
if (fManipulators.AddItem((void*)manipulator)) {
|
||||
manipulator->AttachedToView(fView);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveManipulator
|
||||
Manipulator*
|
||||
MultipleManipulatorState::RemoveManipulator(int32 index)
|
||||
{
|
||||
Manipulator* manipulator = (Manipulator*)fManipulators.RemoveItem(index);
|
||||
|
||||
if (manipulator == fCurrentManipulator)
|
||||
fCurrentManipulator = NULL;
|
||||
|
||||
return manipulator;
|
||||
}
|
||||
|
||||
// DeleteManipulators
|
||||
void
|
||||
MultipleManipulatorState::DeleteManipulators()
|
||||
{
|
||||
int32 count = fManipulators.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Manipulator* m = (Manipulator*)fManipulators.ItemAtFast(i);
|
||||
m->DetachedFromView(fView);
|
||||
delete m;
|
||||
}
|
||||
fManipulators.MakeEmpty();
|
||||
fCurrentManipulator = NULL;
|
||||
fPreviousManipulator = NULL;
|
||||
}
|
||||
|
||||
// CountManipulators
|
||||
int32
|
||||
MultipleManipulatorState::CountManipulators() const
|
||||
{
|
||||
return fManipulators.CountItems();
|
||||
}
|
||||
|
||||
// ManipulatorAt
|
||||
Manipulator*
|
||||
MultipleManipulatorState::ManipulatorAt(int32 index) const
|
||||
{
|
||||
return (Manipulator*)fManipulators.ItemAt(index);
|
||||
}
|
||||
|
||||
// ManipulatorAtFast
|
||||
Manipulator*
|
||||
MultipleManipulatorState::ManipulatorAtFast(int32 index) const
|
||||
{
|
||||
return (Manipulator*)fManipulators.ItemAtFast(index);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef MULTIPLE_MANIPULATOR_STATE_H
|
||||
#define MULTIPLE_MANIPULATOR_STATE_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
#include "ViewState.h"
|
||||
|
||||
class Manipulator;
|
||||
|
||||
class MultipleManipulatorState : public ViewState {
|
||||
public:
|
||||
MultipleManipulatorState(StateView* view);
|
||||
virtual ~MultipleManipulatorState();
|
||||
|
||||
// ViewState interface
|
||||
virtual void Init();
|
||||
virtual void Cleanup();
|
||||
|
||||
virtual void Draw(BView* into, BRect updateRect);
|
||||
virtual bool MessageReceived(BMessage* message,
|
||||
Command** _command);
|
||||
|
||||
virtual void MouseDown(BPoint where,
|
||||
uint32 buttons,
|
||||
uint32 clicks);
|
||||
|
||||
virtual void MouseMoved(BPoint where,
|
||||
uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
virtual Command* MouseUp();
|
||||
|
||||
virtual void ModifiersChanged(uint32 modifiers);
|
||||
|
||||
virtual bool HandleKeyDown(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
virtual bool HandleKeyUp(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
|
||||
// MultipleManipulatorState
|
||||
bool AddManipulator(Manipulator* manipulator);
|
||||
Manipulator* RemoveManipulator(int32 index);
|
||||
void DeleteManipulators();
|
||||
|
||||
int32 CountManipulators() const;
|
||||
Manipulator* ManipulatorAt(int32 index) const;
|
||||
Manipulator* ManipulatorAtFast(int32 index) const;
|
||||
|
||||
private:
|
||||
BList fManipulators;
|
||||
Manipulator* fCurrentManipulator;
|
||||
Manipulator* fPreviousManipulator;
|
||||
};
|
||||
|
||||
#endif // MULTIPLE_MANIPULATOR_STATE_H
|
||||
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "StateView.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "Command.h"
|
||||
#include "CommandStack.h"
|
||||
#include "RWLocker.h"
|
||||
|
||||
|
||||
class EventFilter : public BMessageFilter {
|
||||
public:
|
||||
EventFilter(StateView* target)
|
||||
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
|
||||
fTarget(target)
|
||||
{
|
||||
}
|
||||
virtual ~EventFilter()
|
||||
{
|
||||
}
|
||||
virtual filter_result Filter(BMessage* message, BHandler** target)
|
||||
{
|
||||
filter_result result = B_DISPATCH_MESSAGE;
|
||||
switch (message->what) {
|
||||
case B_KEY_DOWN: {
|
||||
uint32 key;
|
||||
uint32 modifiers;
|
||||
if (message->FindInt32("raw_char", (int32*)&key) >= B_OK
|
||||
&& message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK)
|
||||
if (fTarget->HandleKeyDown(key, modifiers))
|
||||
result = B_SKIP_MESSAGE;
|
||||
break;
|
||||
}
|
||||
case B_KEY_UP: {
|
||||
uint32 key;
|
||||
uint32 modifiers;
|
||||
if (message->FindInt32("raw_char", (int32*)&key) >= B_OK
|
||||
&& message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK)
|
||||
if (fTarget->HandleKeyUp(key, modifiers))
|
||||
result = B_SKIP_MESSAGE;
|
||||
break;
|
||||
|
||||
}
|
||||
case B_MODIFIERS_CHANGED:
|
||||
*target = fTarget;
|
||||
break;
|
||||
|
||||
case B_MOUSE_WHEEL_CHANGED: {
|
||||
float x;
|
||||
float y;
|
||||
if (message->FindFloat("be:wheel_delta_x", &x) >= B_OK
|
||||
&& message->FindFloat("be:wheel_delta_y", &y) >= B_OK) {
|
||||
if (fTarget->MouseWheelChanged(x, y))
|
||||
result = B_SKIP_MESSAGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
StateView* fTarget;
|
||||
};
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// constructor
|
||||
StateView::StateView(BRect frame, const char* name,
|
||||
uint32 resizingMode, uint32 flags)
|
||||
: BView(frame, name, resizingMode, flags),
|
||||
fCurrentState(NULL),
|
||||
fDropAnticipatingState(NULL),
|
||||
|
||||
fMouseInfo(),
|
||||
|
||||
fCommandStack(NULL),
|
||||
fLocker(NULL),
|
||||
|
||||
fEventFilter(NULL),
|
||||
fCatchAllEvents(false),
|
||||
|
||||
fUpdateTarget(NULL),
|
||||
fUpdateCommand(0)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
StateView::~StateView()
|
||||
{
|
||||
delete fEventFilter;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
StateView::AttachedToWindow()
|
||||
{
|
||||
_InstallEventFilter();
|
||||
|
||||
BView::AttachedToWindow();
|
||||
}
|
||||
|
||||
// DetachedFromWindow
|
||||
void
|
||||
StateView::DetachedFromWindow()
|
||||
{
|
||||
_RemoveEventFilter();
|
||||
|
||||
StateView::AttachedToWindow();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
StateView::Draw(BRect updateRect)
|
||||
{
|
||||
Draw(this, updateRect);
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
StateView::MessageReceived(BMessage* message)
|
||||
{
|
||||
// let the state handle the message if it wants
|
||||
if (fCurrentState) {
|
||||
AutoWriteLocker locker(fLocker);
|
||||
if (fLocker && !locker.IsLocked())
|
||||
return;
|
||||
|
||||
Command* command = NULL;
|
||||
if (fCurrentState->MessageReceived(message, &command)) {
|
||||
Perform(command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (message->what) {
|
||||
case B_MODIFIERS_CHANGED:
|
||||
// NOTE: received only if the view has focus!!
|
||||
if (fCurrentState) {
|
||||
uint32 mods;
|
||||
if (message->FindInt32("modifiers", (int32*)&mods) != B_OK)
|
||||
mods = modifiers();
|
||||
fCurrentState->ModifiersChanged(mods);
|
||||
fMouseInfo.modifiers = mods;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
StateView::MouseDown(BPoint where)
|
||||
{
|
||||
if (fLocker && !fLocker->WriteLock())
|
||||
return;
|
||||
|
||||
// query more info from the windows current message if available
|
||||
uint32 buttons;
|
||||
uint32 clicks;
|
||||
BMessage* message = Window() ? Window()->CurrentMessage() : NULL;
|
||||
if (!message || message->FindInt32("buttons", (int32*)&buttons) != B_OK)
|
||||
buttons = B_PRIMARY_MOUSE_BUTTON;
|
||||
if (!message || message->FindInt32("clicks", (int32*)&clicks) != B_OK)
|
||||
clicks = 1;
|
||||
|
||||
if (fCurrentState)
|
||||
fCurrentState->MouseDown(where, buttons, clicks);
|
||||
|
||||
// update mouse info *after* having called the ViewState hook
|
||||
fMouseInfo.buttons = buttons;
|
||||
fMouseInfo.position = where;
|
||||
|
||||
if (fLocker)
|
||||
fLocker->WriteUnlock();
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
StateView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
|
||||
{
|
||||
if (fLocker && !fLocker->WriteLock())
|
||||
return;
|
||||
|
||||
if (dragMessage && !fDropAnticipatingState) {
|
||||
// switch to a drop anticipating state if there is one available
|
||||
fDropAnticipatingState = StateForDragMessage(dragMessage);
|
||||
if (fDropAnticipatingState)
|
||||
fDropAnticipatingState->Init();
|
||||
}
|
||||
|
||||
// TODO: I don't like this too much
|
||||
if (!dragMessage && fDropAnticipatingState) {
|
||||
fDropAnticipatingState->Cleanup();
|
||||
fDropAnticipatingState = NULL;
|
||||
}
|
||||
|
||||
if (fDropAnticipatingState)
|
||||
fDropAnticipatingState->MouseMoved(where, transit, dragMessage);
|
||||
else {
|
||||
if (fCurrentState) {
|
||||
fCurrentState->MouseMoved(where, transit, dragMessage);
|
||||
if (fMouseInfo.buttons != 0)
|
||||
_TriggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// update mouse info *after* having called the ViewState hook
|
||||
fMouseInfo.position = where;
|
||||
fMouseInfo.transit = transit;
|
||||
|
||||
if (fLocker)
|
||||
fLocker->WriteUnlock();
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
StateView::MouseUp(BPoint where)
|
||||
{
|
||||
if (fLocker && !fLocker->WriteLock())
|
||||
return;
|
||||
|
||||
if (fDropAnticipatingState) {
|
||||
Perform(fDropAnticipatingState->MouseUp());
|
||||
fDropAnticipatingState->Cleanup();
|
||||
fDropAnticipatingState = NULL;
|
||||
|
||||
if (fCurrentState) {
|
||||
fCurrentState->MouseMoved(fMouseInfo.position, fMouseInfo.transit,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
if (fCurrentState) {
|
||||
Perform(fCurrentState->MouseUp());
|
||||
_TriggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// update mouse info *after* having called the ViewState hook
|
||||
fMouseInfo.buttons = 0;
|
||||
|
||||
if (fLocker)
|
||||
fLocker->WriteUnlock();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// KeyDown
|
||||
void
|
||||
StateView::KeyDown(const char* bytes, int32 numBytes)
|
||||
{
|
||||
uint32 key;
|
||||
uint32 modifiers;
|
||||
BMessage* message = Window() ? Window()->CurrentMessage() : NULL;
|
||||
if (message
|
||||
&& message->FindInt32("raw_char", (int32*)&key) >= B_OK
|
||||
&& message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) {
|
||||
if (HandleKeyDown(key, modifiers))
|
||||
return;
|
||||
}
|
||||
BView::KeyDown(bytes, numBytes);
|
||||
}
|
||||
|
||||
// KeyUp
|
||||
void
|
||||
StateView::KeyUp(const char* bytes, int32 numBytes)
|
||||
{
|
||||
uint32 key;
|
||||
uint32 modifiers;
|
||||
BMessage* message = Window() ? Window()->CurrentMessage() : NULL;
|
||||
if (message
|
||||
&& message->FindInt32("raw_char", (int32*)&key) >= B_OK
|
||||
&& message->FindInt32("modifiers", (int32*)&modifiers) >= B_OK) {
|
||||
if (HandleKeyUp(key, modifiers))
|
||||
return;
|
||||
}
|
||||
BView::KeyUp(bytes, numBytes);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetState
|
||||
void
|
||||
StateView::SetState(ViewState* state)
|
||||
{
|
||||
if (fCurrentState == state)
|
||||
return;
|
||||
|
||||
// switch states as appropriate
|
||||
if (fCurrentState)
|
||||
fCurrentState->Cleanup();
|
||||
|
||||
fCurrentState = state;
|
||||
|
||||
if (fCurrentState)
|
||||
fCurrentState->Init();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
StateView::Draw(BView* into, BRect updateRect)
|
||||
{
|
||||
if (fLocker && !fLocker->ReadLock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fCurrentState)
|
||||
fCurrentState->Draw(into, updateRect);
|
||||
|
||||
if (fDropAnticipatingState)
|
||||
fDropAnticipatingState->Draw(into, updateRect);
|
||||
|
||||
if (fLocker)
|
||||
fLocker->ReadUnlock();
|
||||
}
|
||||
|
||||
// MouseWheelChanged
|
||||
bool
|
||||
StateView::MouseWheelChanged(float x, float y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// HandleKeyDown
|
||||
bool
|
||||
StateView::HandleKeyDown(uint32 key, uint32 modifiers)
|
||||
{
|
||||
AutoWriteLocker locker(fLocker);
|
||||
if (fLocker && !locker.IsLocked())
|
||||
return false;
|
||||
|
||||
if (_HandleKeyDown(key, modifiers))
|
||||
return true;
|
||||
|
||||
if (fCurrentState) {
|
||||
Command* command = NULL;
|
||||
if (fCurrentState->HandleKeyDown(key, modifiers, &command)) {
|
||||
Perform(command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// HandleKeyUp
|
||||
bool
|
||||
StateView::HandleKeyUp(uint32 key, uint32 modifiers)
|
||||
{
|
||||
AutoWriteLocker locker(fLocker);
|
||||
if (fLocker && !locker.IsLocked())
|
||||
return false;
|
||||
|
||||
if (_HandleKeyUp(key, modifiers))
|
||||
return true;
|
||||
|
||||
if (fCurrentState) {
|
||||
Command* command = NULL;
|
||||
if (fCurrentState->HandleKeyUp(key, modifiers, &command)) {
|
||||
Perform(command);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// StateForDragMessage
|
||||
ViewState*
|
||||
StateView::StateForDragMessage(const BMessage* message)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// SetCommandStack
|
||||
void
|
||||
StateView::SetCommandStack(::CommandStack* stack)
|
||||
{
|
||||
fCommandStack = stack;
|
||||
}
|
||||
|
||||
// SetLocker
|
||||
void
|
||||
StateView::SetLocker(RWLocker* locker)
|
||||
{
|
||||
fLocker = locker;
|
||||
}
|
||||
|
||||
// SetUpdateTarget
|
||||
void
|
||||
StateView::SetUpdateTarget(BHandler* target, uint32 command)
|
||||
{
|
||||
fUpdateTarget = target;
|
||||
fUpdateCommand = command;
|
||||
}
|
||||
|
||||
// SetCatchAllEvents
|
||||
void
|
||||
StateView::SetCatchAllEvents(bool catchAll)
|
||||
{
|
||||
if (fCatchAllEvents == catchAll)
|
||||
return;
|
||||
|
||||
fCatchAllEvents = catchAll;
|
||||
|
||||
if (fCatchAllEvents)
|
||||
_InstallEventFilter();
|
||||
else
|
||||
_RemoveEventFilter();
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
StateView::Perform(Command* command)
|
||||
{
|
||||
if (fCommandStack)
|
||||
return fCommandStack->Perform(command);
|
||||
|
||||
// if there is no command stack, then nobody
|
||||
// else feels responsible...
|
||||
delete command;
|
||||
|
||||
return B_NO_INIT;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _HandleKeyDown
|
||||
bool
|
||||
StateView::_HandleKeyDown(uint32 key, uint32 modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// _HandleKeyUp
|
||||
bool
|
||||
StateView::_HandleKeyUp(uint32 key, uint32 modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// _InstallEventFilter
|
||||
void
|
||||
StateView::_InstallEventFilter()
|
||||
{
|
||||
if (!fCatchAllEvents)
|
||||
return;
|
||||
|
||||
if (!fEventFilter)
|
||||
fEventFilter = new (nothrow) EventFilter(this);
|
||||
|
||||
if (!fEventFilter || !Window())
|
||||
return;
|
||||
|
||||
Window()->AddCommonFilter(fEventFilter);
|
||||
}
|
||||
|
||||
void
|
||||
StateView::_RemoveEventFilter()
|
||||
{
|
||||
if (!fEventFilter || !Window())
|
||||
return;
|
||||
|
||||
Window()->RemoveCommonFilter(fEventFilter);
|
||||
}
|
||||
|
||||
// _TriggerUpdate
|
||||
void
|
||||
StateView::_TriggerUpdate()
|
||||
{
|
||||
if (fUpdateTarget && fUpdateTarget->Looper()) {
|
||||
fUpdateTarget->Looper()->PostMessage(fUpdateCommand);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef STATE_VIEW_H
|
||||
#define STATE_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include "ViewState.h"
|
||||
|
||||
class BMessageFilter;
|
||||
class Command;
|
||||
class CommandStack;
|
||||
class RWLocker;
|
||||
|
||||
class StateView : public BView {
|
||||
public:
|
||||
StateView(BRect frame, const char* name,
|
||||
uint32 resizingMode, uint32 flags);
|
||||
virtual ~StateView();
|
||||
|
||||
// BView interface
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
virtual void MouseUp(BPoint where);
|
||||
|
||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||
virtual void KeyUp(const char* bytes, int32 numBytes);
|
||||
|
||||
// StateView interface
|
||||
void SetState(ViewState* state);
|
||||
|
||||
void Draw(BView* into, BRect updateRect);
|
||||
|
||||
virtual bool MouseWheelChanged(float x, float y);
|
||||
|
||||
bool HandleKeyDown(uint32 key, uint32 modifiers);
|
||||
bool HandleKeyUp(uint32 key, uint32 modifiers);
|
||||
|
||||
const mouse_info* MouseInfo() const
|
||||
{ return &fMouseInfo; }
|
||||
|
||||
virtual ViewState* StateForDragMessage(const BMessage* message);
|
||||
|
||||
void SetLocker(RWLocker* locker);
|
||||
RWLocker* Locker() const
|
||||
{ return fLocker; }
|
||||
|
||||
void SetCommandStack(::CommandStack* stack);
|
||||
::CommandStack* CommandStack() const
|
||||
{ return fCommandStack; }
|
||||
|
||||
void SetUpdateTarget(BHandler* target,
|
||||
uint32 command);
|
||||
|
||||
void SetCatchAllEvents(bool catchAll);
|
||||
|
||||
status_t Perform(Command* command);
|
||||
|
||||
protected:
|
||||
virtual bool _HandleKeyDown(uint32 key, uint32 modifiers);
|
||||
virtual bool _HandleKeyUp(uint32 key, uint32 modifiers);
|
||||
|
||||
void _InstallEventFilter();
|
||||
void _RemoveEventFilter();
|
||||
|
||||
void _TriggerUpdate();
|
||||
|
||||
ViewState* fCurrentState;
|
||||
ViewState* fDropAnticipatingState;
|
||||
// the drop anticipation state is some
|
||||
// kind of "temporary" state that is
|
||||
// used on top of the current state (it
|
||||
// doesn't replace it)
|
||||
mouse_info fMouseInfo;
|
||||
|
||||
::CommandStack* fCommandStack;
|
||||
RWLocker* fLocker;
|
||||
|
||||
BMessageFilter* fEventFilter;
|
||||
bool fCatchAllEvents;
|
||||
|
||||
BHandler* fUpdateTarget;
|
||||
uint32 fUpdateCommand;
|
||||
};
|
||||
|
||||
#endif // STATE_VIEW_H
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "ViewState.h"
|
||||
|
||||
#include "StateView.h"
|
||||
|
||||
mouse_info::mouse_info()
|
||||
: buttons(0),
|
||||
position(B_ORIGIN),
|
||||
transit(B_OUTSIDE_VIEW),
|
||||
modifiers(::modifiers())
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
ViewState::ViewState(StateView* view)
|
||||
: fView(view),
|
||||
fMouseInfo(view->MouseInfo())
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
ViewState::ViewState(const ViewState& other)
|
||||
: fView(other.fView),
|
||||
fMouseInfo(other.fMouseInfo)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
ViewState::~ViewState()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Init
|
||||
void
|
||||
ViewState::Init()
|
||||
{
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
void
|
||||
ViewState::Cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// Draw
|
||||
void
|
||||
ViewState::Draw(BView* into, BRect updateRect)
|
||||
{
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
bool
|
||||
ViewState::MessageReceived(BMessage* message, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// MouseDown
|
||||
void
|
||||
ViewState::MouseDown(BPoint where, uint32 buttons, uint32 clicks)
|
||||
{
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
ViewState::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
|
||||
{
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
Command*
|
||||
ViewState::MouseUp()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// ModifiersChanged
|
||||
void
|
||||
ViewState::ModifiersChanged(uint32 modifiers)
|
||||
{
|
||||
}
|
||||
|
||||
// HandleKeyDown
|
||||
bool
|
||||
ViewState::HandleKeyDown(uint32 key, uint32 modifiers, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// HandleKeyUp
|
||||
bool
|
||||
ViewState::HandleKeyUp(uint32 key, uint32 modifiers, Command** _command)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef VIEW_STATE_H
|
||||
#define VIEW_STATE_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class BMessage;
|
||||
class Command;
|
||||
class StateView;
|
||||
|
||||
struct mouse_info {
|
||||
mouse_info();
|
||||
|
||||
uint32 buttons;
|
||||
BPoint position;
|
||||
uint32 transit;
|
||||
uint32 modifiers;
|
||||
};
|
||||
|
||||
class ViewState {
|
||||
public:
|
||||
ViewState(StateView* view);
|
||||
ViewState(const ViewState& other);
|
||||
virtual ~ViewState();
|
||||
|
||||
// ViewState interface
|
||||
virtual void Init();
|
||||
virtual void Cleanup();
|
||||
|
||||
virtual void Draw(BView* into, BRect updateRect);
|
||||
virtual bool MessageReceived(BMessage* message,
|
||||
Command** _command);
|
||||
|
||||
// mouse tracking
|
||||
virtual void MouseDown(BPoint where,
|
||||
uint32 buttons,
|
||||
uint32 clicks);
|
||||
|
||||
virtual void MouseMoved(BPoint where,
|
||||
uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
virtual Command* MouseUp();
|
||||
|
||||
// modifiers
|
||||
virtual void ModifiersChanged(uint32 modifiers);
|
||||
|
||||
|
||||
// TODO: mouse wheel
|
||||
virtual bool HandleKeyDown(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
virtual bool HandleKeyUp(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
|
||||
|
||||
inline uint32 PressedMouseButtons() const
|
||||
{ return fMouseInfo->buttons; }
|
||||
|
||||
inline bool IsFirstButtonDown() const
|
||||
{ return fMouseInfo->buttons & B_PRIMARY_MOUSE_BUTTON; }
|
||||
inline bool IsSecondButtonDown() const
|
||||
{ return fMouseInfo->buttons & B_SECONDARY_MOUSE_BUTTON; }
|
||||
inline bool IsThirdButtonDown() const
|
||||
{ return fMouseInfo->buttons & B_TERTIARY_MOUSE_BUTTON; }
|
||||
|
||||
inline BPoint MousePos() const
|
||||
{ return fMouseInfo->position; }
|
||||
|
||||
inline uint32 Modifiers() const
|
||||
{ return fMouseInfo->modifiers; }
|
||||
|
||||
protected:
|
||||
StateView* fView;
|
||||
|
||||
// NOTE: the intention of using a pointer
|
||||
// to a mouse_info struct is that all
|
||||
// ViewStates belonging to the same StateView
|
||||
// should have the same pointer, so that
|
||||
// they will all be up to date with the same info
|
||||
const mouse_info* fMouseInfo;
|
||||
};
|
||||
|
||||
#endif // VIEW_STATE_H
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef UI_DEFINES_H
|
||||
#define UI_DEFINES_H
|
||||
|
||||
const rgb_color kBlack = { 0, 0, 0, 255 };
|
||||
const rgb_color kWhite = { 255, 255, 255, 255 };
|
||||
const rgb_color kOrange = { 255, 217, 121, 255 };
|
||||
const rgb_color kLightOrange = { 255, 217, 138, 255 };
|
||||
const rgb_color kDarkOrange = { 255, 145, 71, 255 };
|
||||
|
||||
#endif // UI_DEFINES_H
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "AbstractLOAdapter.h"
|
||||
|
||||
#include <Handler.h>
|
||||
#include <Looper.h>
|
||||
#include <Messenger.h>
|
||||
|
||||
// constructor
|
||||
AbstractLOAdapter::AbstractLOAdapter(BHandler* handler)
|
||||
: fHandler(handler),
|
||||
fMessenger(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
AbstractLOAdapter::AbstractLOAdapter(const BMessenger& messenger)
|
||||
: fHandler(NULL),
|
||||
fMessenger(new BMessenger(messenger))
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
AbstractLOAdapter::~AbstractLOAdapter()
|
||||
{
|
||||
delete fMessenger;
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(BMessage* message)
|
||||
{
|
||||
if (fHandler) {
|
||||
if (BLooper* looper = fHandler->Looper())
|
||||
looper->PostMessage(message, fHandler);
|
||||
} else if (fMessenger)
|
||||
fMessenger->SendMessage(message);
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(BMessage& message)
|
||||
{
|
||||
DeliverMessage(&message);
|
||||
}
|
||||
|
||||
// DeliverMessage
|
||||
void
|
||||
AbstractLOAdapter::DeliverMessage(uint32 command)
|
||||
{
|
||||
BMessage message(command);
|
||||
DeliverMessage(&message);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Ingo Weinhold <[email protected]>
|
||||
*/
|
||||
|
||||
// This class provides some basic functionality for derivation of a
|
||||
// listener -> observer adapter.
|
||||
// The derived class should implement constructors similar to the
|
||||
// ones of this class and pass the respective parameter.
|
||||
// Each of the listener hook functions should construct a message
|
||||
// and let it be delivered by DeliverMessage().
|
||||
|
||||
#ifndef ABSTRACT_LO_ADAPTER_H
|
||||
#define ABSTRACT_LO_ADAPTER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BHandler;
|
||||
class BLooper;
|
||||
class BMessage;
|
||||
class BMessenger;
|
||||
|
||||
class AbstractLOAdapter {
|
||||
public:
|
||||
AbstractLOAdapter(BHandler* handler);
|
||||
AbstractLOAdapter(const BMessenger& messenger);
|
||||
virtual ~AbstractLOAdapter();
|
||||
|
||||
void DeliverMessage(BMessage* message);
|
||||
void DeliverMessage(BMessage& message);
|
||||
void DeliverMessage(uint32 command);
|
||||
|
||||
private:
|
||||
BHandler* fHandler;
|
||||
BMessenger* fMessenger;
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_LO_ADAPTER_H
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Observable.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include "Observer.h"
|
||||
|
||||
// constructor
|
||||
Observable::Observable()
|
||||
: fObservers(2),
|
||||
fSuspended(0),
|
||||
fPendingNotifications(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Observable::~Observable()
|
||||
{
|
||||
if (fObservers.CountItems() > 0) {
|
||||
char message[256];
|
||||
sprintf(message, "Observable::~Observable() - %ld "
|
||||
"observers still watching!\n", fObservers.CountItems());
|
||||
debugger(message);
|
||||
}
|
||||
}
|
||||
|
||||
// AddObserver
|
||||
bool
|
||||
Observable::AddObserver(Observer* observer)
|
||||
{
|
||||
if (observer && !fObservers.HasItem((void*)observer)) {
|
||||
return fObservers.AddItem((void*)observer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemoveObserver
|
||||
bool
|
||||
Observable::RemoveObserver(Observer* observer)
|
||||
{
|
||||
return fObservers.RemoveItem((void*)observer);
|
||||
}
|
||||
|
||||
// Notify
|
||||
void
|
||||
Observable::Notify() const
|
||||
{
|
||||
if (!fSuspended) {
|
||||
BList observers(fObservers);
|
||||
int32 count = observers.CountItems();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
((Observer*)observers.ItemAtFast(i))->ObjectChanged(this);
|
||||
fPendingNotifications = false;
|
||||
} else {
|
||||
fPendingNotifications = true;
|
||||
}
|
||||
}
|
||||
|
||||
// SuspendNotifications
|
||||
void
|
||||
Observable::SuspendNotifications(bool suspend)
|
||||
{
|
||||
if (suspend)
|
||||
fSuspended++;
|
||||
else
|
||||
fSuspended--;
|
||||
|
||||
if (fSuspended < 0) {
|
||||
fprintf(stderr, "Observable::SuspendNotifications(false) - "
|
||||
"error: suspend level below zero!\n");
|
||||
fSuspended = 0;
|
||||
}
|
||||
|
||||
if (!fSuspended && fPendingNotifications)
|
||||
Notify();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef OBSERVABLE_H
|
||||
#define OBSERVABLE_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
class Observer;
|
||||
|
||||
class Observable {
|
||||
public:
|
||||
Observable();
|
||||
virtual ~Observable();
|
||||
|
||||
bool AddObserver(Observer* observer);
|
||||
bool RemoveObserver(Observer* observer);
|
||||
|
||||
void Notify() const;
|
||||
|
||||
void SuspendNotifications(bool suspend);
|
||||
|
||||
private:
|
||||
BList fObservers;
|
||||
|
||||
int32 fSuspended;
|
||||
mutable bool fPendingNotifications;
|
||||
};
|
||||
|
||||
class AutoNotificationSuspender {
|
||||
public:
|
||||
AutoNotificationSuspender(Observable* object)
|
||||
: fObject(object)
|
||||
{
|
||||
fObject->SuspendNotifications(true);
|
||||
}
|
||||
|
||||
virtual ~AutoNotificationSuspender()
|
||||
{
|
||||
fObject->SuspendNotifications(false);
|
||||
}
|
||||
private:
|
||||
Observable* fObject;
|
||||
};
|
||||
|
||||
#endif // OBSERVABLE_H
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Observer.h"
|
||||
|
||||
Observer::Observer()
|
||||
{
|
||||
}
|
||||
|
||||
Observer::~Observer()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef OBSERVER_H
|
||||
#define OBSERVER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Observable;
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
Observer();
|
||||
virtual ~Observer();
|
||||
|
||||
virtual void ObjectChanged(const Observable* object) = 0;
|
||||
};
|
||||
|
||||
#endif // OBSERVER_H
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Selectable.h"
|
||||
|
||||
// constructor
|
||||
Selectable::Selectable()
|
||||
: fSelected(false)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Selectable::~Selectable()
|
||||
{
|
||||
}
|
||||
|
||||
// SetSelected
|
||||
void
|
||||
Selectable::SetSelected(bool selected)
|
||||
{
|
||||
if (fSelected != selected) {
|
||||
fSelected = selected;
|
||||
SelectedChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SELECTABLE_H
|
||||
#define SELECTABLE_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Selectable {
|
||||
public:
|
||||
Selectable();
|
||||
virtual ~Selectable();
|
||||
|
||||
inline bool IsSelected() const
|
||||
{ return fSelected; }
|
||||
|
||||
virtual void SelectedChanged() = 0;
|
||||
|
||||
private:
|
||||
friend class Selection;
|
||||
void SetSelected(bool selected);
|
||||
|
||||
bool fSelected;
|
||||
};
|
||||
|
||||
#endif // SELECTABLE_H
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Selection.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <debugger.h>
|
||||
|
||||
#include "Selectable.h"
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
// constructor
|
||||
Selection::Selection()
|
||||
: fSelected(20)
|
||||
{
|
||||
}
|
||||
|
||||
// destructor
|
||||
Selection::~Selection()
|
||||
{
|
||||
}
|
||||
|
||||
// Select
|
||||
bool
|
||||
Selection::Select(Selectable* object, bool extend)
|
||||
{
|
||||
AutoNotificationSuspender _(this);
|
||||
|
||||
if (!extend)
|
||||
_DeselectAllExcept(object);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (!object->IsSelected()) {
|
||||
|
||||
#if DEBUG
|
||||
if (fSelected.HasItem((void*)object))
|
||||
debugger("Selection::Select() - "
|
||||
"unselected object in list!");
|
||||
#endif
|
||||
|
||||
if (fSelected.AddItem((void*)object)) {
|
||||
object->SetSelected(true);
|
||||
success = true;
|
||||
|
||||
Notify();
|
||||
} else {
|
||||
fprintf(stderr, "Selection::Select() - out of memory\n");
|
||||
}
|
||||
} else {
|
||||
|
||||
#if DEBUG
|
||||
if (!fSelected.HasItem((void*)object))
|
||||
debugger("Selection::Select() - "
|
||||
"already selected object not in list!");
|
||||
#endif
|
||||
|
||||
success = true;
|
||||
// object already in list
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Deselect
|
||||
void
|
||||
Selection::Deselect(Selectable* object)
|
||||
{
|
||||
if (object->IsSelected()) {
|
||||
if (!fSelected.RemoveItem((void*)object))
|
||||
debugger("Selection::Deselect() - "
|
||||
"selected object not within list!");
|
||||
object->SetSelected(false);
|
||||
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// DeselectAll
|
||||
void
|
||||
Selection::DeselectAll()
|
||||
{
|
||||
_DeselectAllExcept(NULL);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SelectableAt
|
||||
Selectable*
|
||||
Selection::SelectableAt(int32 index) const
|
||||
{
|
||||
return (Selectable*)fSelected.ItemAt(index);
|
||||
}
|
||||
|
||||
// SelectableAtFast
|
||||
Selectable*
|
||||
Selection::SelectableAtFast(int32 index) const
|
||||
{
|
||||
return (Selectable*)fSelected.ItemAtFast(index);
|
||||
}
|
||||
|
||||
// CountSelected
|
||||
int32
|
||||
Selection::CountSelected() const
|
||||
{
|
||||
return fSelected.CountItems();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _DeselectAllExcept
|
||||
void
|
||||
Selection::_DeselectAllExcept(Selectable* except)
|
||||
{
|
||||
bool notify = false;
|
||||
bool containedExcept = false;
|
||||
|
||||
int32 count = fSelected.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Selectable* object = (Selectable*)fSelected.ItemAtFast(i);
|
||||
if (object != except) {
|
||||
object->SetSelected(false);
|
||||
notify = true;
|
||||
} else {
|
||||
containedExcept = true;
|
||||
}
|
||||
}
|
||||
|
||||
fSelected.MakeEmpty();
|
||||
|
||||
// if the "except" object was previously
|
||||
// in the selection, add it again after
|
||||
// making the selection list empty
|
||||
if (containedExcept)
|
||||
fSelected.AddItem(except);
|
||||
|
||||
if (notify)
|
||||
Notify();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SELECTION_H
|
||||
#define SELECTION_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
#include "Observable.h"
|
||||
|
||||
class Selectable;
|
||||
|
||||
class Selection : public Observable {
|
||||
public:
|
||||
Selection();
|
||||
virtual ~Selection();
|
||||
|
||||
// modify selection
|
||||
bool Select(Selectable* object,
|
||||
bool extend = false);
|
||||
void Deselect(Selectable* object);
|
||||
void DeselectAll();
|
||||
|
||||
// query selection
|
||||
Selectable* SelectableAt(int32 index) const;
|
||||
Selectable* SelectableAtFast(int32 index) const;
|
||||
int32 CountSelected() const;
|
||||
|
||||
private:
|
||||
void _DeselectAllExcept(Selectable* object);
|
||||
|
||||
BList fSelected;
|
||||
};
|
||||
|
||||
#endif // SELECTION_H
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2001-2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
/** Scope-based automatic deletion of objects/arrays.
|
||||
* ObjectDeleter - deletes an object
|
||||
* ArrayDeleter - deletes an array
|
||||
* MemoryDeleter - free()s malloc()ed memory
|
||||
*/
|
||||
|
||||
#ifndef _AUTO_DELETER_H
|
||||
#define _AUTO_DELETER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
// AutoDeleter
|
||||
|
||||
template<typename C, typename DeleteFunc>
|
||||
class AutoDeleter {
|
||||
public:
|
||||
inline AutoDeleter()
|
||||
: fObject(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
inline AutoDeleter(C *object)
|
||||
: fObject(object)
|
||||
{
|
||||
}
|
||||
|
||||
inline ~AutoDeleter()
|
||||
{
|
||||
fDelete(fObject);
|
||||
}
|
||||
|
||||
inline void SetTo(C *object)
|
||||
{
|
||||
if (object != fObject) {
|
||||
fDelete(fObject);
|
||||
fObject = object;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Unset()
|
||||
{
|
||||
SetTo(NULL);
|
||||
}
|
||||
|
||||
inline void Delete()
|
||||
{
|
||||
SetTo(NULL);
|
||||
}
|
||||
|
||||
inline C *Detach()
|
||||
{
|
||||
C *object = fObject;
|
||||
fObject = NULL;
|
||||
return object;
|
||||
}
|
||||
|
||||
private:
|
||||
C *fObject;
|
||||
DeleteFunc fDelete;
|
||||
};
|
||||
|
||||
|
||||
// ObjectDeleter
|
||||
|
||||
template<typename C>
|
||||
struct ObjectDelete
|
||||
{
|
||||
inline void operator()(C *object)
|
||||
{
|
||||
delete object;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct ObjectDeleter : AutoDeleter<C, ObjectDelete<C> >
|
||||
{
|
||||
ObjectDeleter() : AutoDeleter<C, ObjectDelete<C> >() {}
|
||||
ObjectDeleter(C *object) : AutoDeleter<C, ObjectDelete<C> >(object) {}
|
||||
};
|
||||
|
||||
|
||||
// ArrayDeleter
|
||||
|
||||
template<typename C>
|
||||
struct ArrayDelete
|
||||
{
|
||||
inline void operator()(C *array)
|
||||
{
|
||||
delete[] array;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct ArrayDeleter : AutoDeleter<C, ArrayDelete<C> >
|
||||
{
|
||||
ArrayDeleter() : AutoDeleter<C, ArrayDelete<C> >() {}
|
||||
ArrayDeleter(C *array) : AutoDeleter<C, ArrayDelete<C> >(array) {}
|
||||
};
|
||||
|
||||
|
||||
// MemoryDeleter
|
||||
|
||||
struct MemoryDelete
|
||||
{
|
||||
inline void operator()(void *memory)
|
||||
{
|
||||
free(memory);
|
||||
}
|
||||
};
|
||||
|
||||
struct MemoryDeleter : AutoDeleter<void, MemoryDelete >
|
||||
{
|
||||
MemoryDeleter() : AutoDeleter<void, MemoryDelete >() {}
|
||||
MemoryDeleter(void *memory) : AutoDeleter<void, MemoryDelete >(memory) {}
|
||||
};
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
using BPrivate::ObjectDeleter;
|
||||
using BPrivate::ArrayDeleter;
|
||||
using BPrivate::MemoryDeleter;
|
||||
|
||||
#endif // _AUTO_DELETER_H
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2004-2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
/** Scope-based automatic deletion of objects/arrays.
|
||||
* ObjectDeleter - deletes an object
|
||||
* ArrayDeleter - deletes an array
|
||||
* MemoryDeleter - free()s malloc()ed memory
|
||||
*/
|
||||
|
||||
#ifndef AUTO_LOCKER_H
|
||||
#define AUTO_LOCKER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// locking
|
||||
|
||||
// AutoLockerStandardLocking
|
||||
template<typename Lockable>
|
||||
class AutoLockerStandardLocking {
|
||||
public:
|
||||
inline bool Lock(Lockable *lockable)
|
||||
{
|
||||
return lockable->Lock();
|
||||
}
|
||||
|
||||
inline void Unlock(Lockable *lockable)
|
||||
{
|
||||
lockable->Unlock();
|
||||
}
|
||||
};
|
||||
|
||||
// AutoLockerReadLocking
|
||||
template<typename Lockable>
|
||||
class AutoLockerReadLocking {
|
||||
public:
|
||||
inline bool Lock(Lockable *lockable)
|
||||
{
|
||||
return lockable->ReadLock();
|
||||
}
|
||||
|
||||
inline void Unlock(Lockable *lockable)
|
||||
{
|
||||
lockable->ReadUnlock();
|
||||
}
|
||||
};
|
||||
|
||||
// AutoLockerWriteLocking
|
||||
template<typename Lockable>
|
||||
class AutoLockerWriteLocking {
|
||||
public:
|
||||
inline bool Lock(Lockable *lockable)
|
||||
{
|
||||
return lockable->WriteLock();
|
||||
}
|
||||
|
||||
inline void Unlock(Lockable *lockable)
|
||||
{
|
||||
lockable->WriteUnlock();
|
||||
}
|
||||
};
|
||||
|
||||
// AutoLocker
|
||||
template<typename Lockable,
|
||||
typename Locking = AutoLockerStandardLocking<Lockable> >
|
||||
class AutoLocker {
|
||||
private:
|
||||
typedef AutoLocker<Lockable, Locking> ThisClass;
|
||||
public:
|
||||
inline AutoLocker(Lockable *lockable, bool alreadyLocked = false)
|
||||
: fLockable(lockable),
|
||||
fLocked(fLockable && alreadyLocked)
|
||||
{
|
||||
if (!fLocked)
|
||||
_Lock();
|
||||
}
|
||||
|
||||
inline AutoLocker(Lockable &lockable, bool alreadyLocked = false)
|
||||
: fLockable(&lockable),
|
||||
fLocked(fLockable && alreadyLocked)
|
||||
{
|
||||
if (!fLocked)
|
||||
_Lock();
|
||||
}
|
||||
|
||||
inline ~AutoLocker()
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
|
||||
inline void SetTo(Lockable *lockable, bool alreadyLocked)
|
||||
{
|
||||
Unlock();
|
||||
fLockable = lockable;
|
||||
fLocked = alreadyLocked;
|
||||
if (!fLocked)
|
||||
_Lock();
|
||||
}
|
||||
|
||||
inline void SetTo(Lockable &lockable, bool alreadyLocked)
|
||||
{
|
||||
SetTo(&lockable, alreadyLocked);
|
||||
}
|
||||
|
||||
inline void Unset()
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
|
||||
inline AutoLocker<Lockable, Locking> &operator=(Lockable *lockable)
|
||||
{
|
||||
SetTo(lockable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AutoLocker<Lockable, Locking> &operator=(Lockable &lockable)
|
||||
{
|
||||
SetTo(&lockable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool IsLocked() const { return fLocked; }
|
||||
|
||||
inline void Unlock()
|
||||
{
|
||||
if (fLockable && fLocked) {
|
||||
fLocking.Unlock(fLockable);
|
||||
fLocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline operator bool() const { return fLocked; }
|
||||
|
||||
private:
|
||||
inline void _Lock()
|
||||
{
|
||||
if (fLockable)
|
||||
fLocked = fLocking.Lock(fLockable);
|
||||
}
|
||||
|
||||
private:
|
||||
Lockable *fLockable;
|
||||
bool fLocked;
|
||||
Locking fLocking;
|
||||
};
|
||||
|
||||
#endif // AUTO_LOCKER_H
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2003-2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "Debug.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
/*!
|
||||
\file Debug.cpp
|
||||
\brief Defines debug output function with printf() signature printing
|
||||
into a file.
|
||||
|
||||
\note The initialization is not thread safe!
|
||||
*/
|
||||
|
||||
// locking support
|
||||
static int32 init_counter = 0;
|
||||
static sem_id dbg_printf_sem = -1;
|
||||
static thread_id dbg_printf_thread = -1;
|
||||
static int dbg_printf_nesting = 0;
|
||||
|
||||
#if DEBUG_PRINT
|
||||
static int out = -1;
|
||||
#endif
|
||||
|
||||
// init_debugging
|
||||
status_t
|
||||
init_debugging()
|
||||
{
|
||||
status_t error = B_OK;
|
||||
if (init_counter++ == 0) {
|
||||
// open the file
|
||||
#if DEBUG_PRINT
|
||||
out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
|
||||
if (out < 0) {
|
||||
error = errno;
|
||||
init_counter--;
|
||||
}
|
||||
#endif // DEBUG_PRINT
|
||||
// allocate the semaphore
|
||||
if (error == B_OK) {
|
||||
dbg_printf_sem = create_sem(1, "dbg_printf");
|
||||
if (dbg_printf_sem < 0)
|
||||
error = dbg_printf_sem;
|
||||
}
|
||||
if (error == B_OK) {
|
||||
#if DEBUG
|
||||
__out("##################################################\n");
|
||||
#endif
|
||||
} else
|
||||
exit_debugging();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// exit_debugging
|
||||
status_t
|
||||
exit_debugging()
|
||||
{
|
||||
status_t error = B_OK;
|
||||
if (--init_counter == 0) {
|
||||
#if DEBUG_PRINT
|
||||
close(out);
|
||||
out = -1;
|
||||
#endif // DEBUG_PRINT
|
||||
delete_sem(dbg_printf_sem);
|
||||
} else
|
||||
error = B_NO_INIT;
|
||||
return error;
|
||||
}
|
||||
|
||||
// dbg_printf_lock
|
||||
static inline
|
||||
bool
|
||||
dbg_printf_lock()
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread != dbg_printf_thread) {
|
||||
if (acquire_sem(dbg_printf_sem) != B_OK)
|
||||
return false;
|
||||
dbg_printf_thread = thread;
|
||||
}
|
||||
dbg_printf_nesting++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// dbg_printf_unlock
|
||||
static inline
|
||||
void
|
||||
dbg_printf_unlock()
|
||||
{
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread != dbg_printf_thread)
|
||||
return;
|
||||
dbg_printf_nesting--;
|
||||
if (dbg_printf_nesting == 0) {
|
||||
dbg_printf_thread = -1;
|
||||
release_sem(dbg_printf_sem);
|
||||
}
|
||||
}
|
||||
|
||||
// dbg_printf_begin
|
||||
void
|
||||
dbg_printf_begin()
|
||||
{
|
||||
dbg_printf_lock();
|
||||
}
|
||||
|
||||
// dbg_printf_end
|
||||
void
|
||||
dbg_printf_end()
|
||||
{
|
||||
dbg_printf_unlock();
|
||||
}
|
||||
|
||||
#if DEBUG_PRINT
|
||||
|
||||
// dbg_printf
|
||||
void
|
||||
dbg_printf(const char *format,...)
|
||||
{
|
||||
if (!dbg_printf_lock())
|
||||
return;
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
// no vsnprintf() on PPC and in kernel
|
||||
#if defined(__INTEL__) && USER
|
||||
vsnprintf(buffer, sizeof(buffer) - 1, format, args);
|
||||
#else
|
||||
vsprintf(buffer, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
buffer[sizeof(buffer) - 1] = '\0';
|
||||
write(out, buffer, strlen(buffer));
|
||||
dbg_printf_unlock();
|
||||
}
|
||||
|
||||
#endif // DEBUG_PRINT
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler <[email protected]>
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// USER defaults to 1
|
||||
#ifndef USER
|
||||
# define USER 1
|
||||
#endif
|
||||
|
||||
#if !USER
|
||||
# include <KernelExport.h>
|
||||
#endif
|
||||
#include <OS.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// define all macros we work with -- undefined macros are set to defaults
|
||||
#ifndef DEBUG
|
||||
# define DEBUG 0
|
||||
#endif
|
||||
#if !DEBUG
|
||||
# undef DEBUG_PRINT
|
||||
# define DEBUG_PRINT 0
|
||||
#endif
|
||||
#ifndef DEBUG_PRINT
|
||||
# define DEBUG_PRINT 0
|
||||
#endif
|
||||
#ifndef DEBUG_APP
|
||||
# define DEBUG_APP "debug"
|
||||
#endif
|
||||
#ifndef DEBUG_PRINT_FILE
|
||||
# define DEBUG_PRINT_FILE "/var/log/" DEBUG_APP ".log"
|
||||
#endif
|
||||
|
||||
// define the debug output function
|
||||
#if USER
|
||||
# include <stdio.h>
|
||||
# if DEBUG_PRINT
|
||||
# define __out dbg_printf
|
||||
# else
|
||||
# define __out printf
|
||||
# endif
|
||||
#else
|
||||
# include <KernelExport.h>
|
||||
# include <null.h>
|
||||
# if DEBUG_PRINT
|
||||
# define __out dbg_printf
|
||||
# else
|
||||
# define __out dprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// define the PANIC() macro
|
||||
#ifndef PANIC
|
||||
# if USER
|
||||
# define PANIC(str) debugger(str)
|
||||
# else
|
||||
# define PANIC(str) panic(str)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// functions exported by this module
|
||||
status_t init_debugging();
|
||||
status_t exit_debugging();
|
||||
void dbg_printf_begin();
|
||||
void dbg_printf_end();
|
||||
#if DEBUG_PRINT
|
||||
void dbg_printf(const char *format,...);
|
||||
#else
|
||||
static inline void dbg_printf(const char *,...) {}
|
||||
#endif
|
||||
|
||||
// Short overview over the debug output macros:
|
||||
// PRINT()
|
||||
// is for general messages that very unlikely should appear in a release build
|
||||
// FATAL()
|
||||
// this is for fatal messages, when something has really gone wrong
|
||||
// INFORM()
|
||||
// general information, as disk size, etc.
|
||||
// REPORT_ERROR(status_t)
|
||||
// prints out error information
|
||||
// RETURN_ERROR(status_t)
|
||||
// calls REPORT_ERROR() and return the value
|
||||
// D()
|
||||
// the statements in D() are only included if DEBUG is defined
|
||||
|
||||
#if __MWERKS__
|
||||
# define __FUNCTION__ ""
|
||||
#endif
|
||||
|
||||
#define DEBUG_THREAD find_thread(NULL)
|
||||
#define DEBUG_CONTEXT(x) { dbg_printf_begin(); __out(DEBUG_APP " [%Ld: %5ld] ", system_time(), DEBUG_THREAD); x; dbg_printf_end(); }
|
||||
#define DEBUG_CONTEXT_FUNCTION(prefix, x) { dbg_printf_begin(); __out(DEBUG_APP " [%Ld: %5ld] %s()" prefix, system_time(), DEBUG_THREAD, __FUNCTION__); x; dbg_printf_end(); }
|
||||
#define DEBUG_CONTEXT_LINE(x) { dbg_printf_begin(); __out(DEBUG_APP " [%Ld: %5ld] %s():%d: ", system_time(), DEBUG_THREAD, __FUNCTION__, __LINE__); x; dbg_printf_end(); }
|
||||
|
||||
#define TPRINT(x) DEBUG_CONTEXT( __out x )
|
||||
#define TREPORT_ERROR(status) DEBUG_CONTEXT_LINE( __out("%s\n", strerror(status)) )
|
||||
#define TRETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) TREPORT_ERROR(_status); return _status;}
|
||||
#define TSET_ERROR(var, err) { status_t _status = err; if (_status < B_OK) TREPORT_ERROR(_status); var = _status; }
|
||||
#define TFUNCTION(x) DEBUG_CONTEXT_FUNCTION( ": ", __out x )
|
||||
#define TFUNCTION_START() DEBUG_CONTEXT_FUNCTION( "\n", )
|
||||
#define TFUNCTION_END() DEBUG_CONTEXT_FUNCTION( " done\n", )
|
||||
|
||||
#if DEBUG
|
||||
#define PRINT(x) TPRINT(x)
|
||||
#define REPORT_ERROR(status) TREPORT_ERROR(status)
|
||||
#define RETURN_ERROR(err) TRETURN_ERROR(err)
|
||||
#define SET_ERROR(var, err) TSET_ERROR(var, err)
|
||||
#define FATAL(x) DEBUG_CONTEXT( __out x )
|
||||
#define ERROR(x) DEBUG_CONTEXT( __out x )
|
||||
#define WARN(x) DEBUG_CONTEXT( __out x )
|
||||
#define INFORM(x) DEBUG_CONTEXT( __out x )
|
||||
#define FUNCTION(x) TFUNCTION(x)
|
||||
#define FUNCTION_START() TFUNCTION_START()
|
||||
#define FUNCTION_END() TFUNCTION_END()
|
||||
#define D(x) {x;};
|
||||
#else
|
||||
#define PRINT(x) ;
|
||||
#define REPORT_ERROR(status) ;
|
||||
#define RETURN_ERROR(status) return status;
|
||||
#define SET_ERROR(var, err) var = err;
|
||||
#define FATAL(x) DEBUG_CONTEXT( __out x )
|
||||
#define ERROR(x) DEBUG_CONTEXT( __out x )
|
||||
#define WARN(x) DEBUG_CONTEXT( __out x )
|
||||
#define INFORM(x) DEBUG_CONTEXT( __out x )
|
||||
#define FUNCTION(x) ;
|
||||
#define FUNCTION_START() ;
|
||||
#define FUNCTION_END() ;
|
||||
#define D(x) ;
|
||||
#endif
|
||||
|
||||
#ifndef TOUCH
|
||||
#define TOUCH(var) (void)var
|
||||
#endif
|
||||
|
||||
|
||||
static inline void nodebug(...)
|
||||
{
|
||||
}
|
||||
|
||||
#define debug dbg_printf
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#include <List.h>
|
||||
|
||||
template<class T, bool delete_on_destruction = true>
|
||||
class List : protected BList {
|
||||
public:
|
||||
List(int32 count = 10)
|
||||
: BList(count) {}
|
||||
|
||||
~List()
|
||||
{ MakeEmpty(); }
|
||||
|
||||
// adding items
|
||||
inline void AddItem(T value)
|
||||
{ BList::AddItem((void*)value); }
|
||||
|
||||
inline void AddItem(T value, int32 index)
|
||||
{ BList::AddItem((void*)value, index); }
|
||||
|
||||
// information
|
||||
inline bool HasItem(T value) const
|
||||
{ return BList::HasItem((void*)value); }
|
||||
|
||||
inline int32 IndexOf(T value) const
|
||||
{ return BList::IndexOf((void*)value); }
|
||||
|
||||
inline bool IsEmpty() const
|
||||
{ return BList::IsEmpty(); }
|
||||
|
||||
inline int32 CountItems() const
|
||||
{ return BList::CountItems(); }
|
||||
|
||||
// retrieving items
|
||||
inline T ItemAt(int32 index) const
|
||||
{ return (T)BList::ItemAt(index); }
|
||||
|
||||
inline T ItemAtFast(int32 index) const
|
||||
{ return (T)BList::ItemAtFast(index); }
|
||||
|
||||
inline T FirstItem() const
|
||||
{ return (T)BList::FirstItem(); }
|
||||
|
||||
inline T LastItem() const
|
||||
{ return (T)BList::LastItem(); }
|
||||
|
||||
// removing items
|
||||
inline bool RemoveItem(T value)
|
||||
{ return BList::RemoveItem((void*)value); }
|
||||
|
||||
inline T RemoveItem(int32 index)
|
||||
{ return (T)BList::RemoveItem(index); }
|
||||
|
||||
inline bool RemoveItems(int32 index, int32 count)
|
||||
{ return BList::RemoveItems(index, count); }
|
||||
|
||||
inline void MakeEmpty() {
|
||||
if (delete_on_destruction) {
|
||||
// delete all values
|
||||
int32 count = CountItems();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
delete (T)BList::ItemAtFast(i);
|
||||
}
|
||||
BList::MakeEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LIST_H
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
#include "RWLocker.h"
|
||||
|
||||
#include <String.h>
|
||||
|
||||
// info about a read lock owner
|
||||
struct RWLocker::ReadLockInfo {
|
||||
thread_id reader;
|
||||
int32 count;
|
||||
};
|
||||
|
||||
|
||||
// constructor
|
||||
RWLocker::RWLocker()
|
||||
: fLock(),
|
||||
fMutex(),
|
||||
fQueue(),
|
||||
fReaderCount(0),
|
||||
fWriterCount(0),
|
||||
fReadLockInfos(8),
|
||||
fWriter(B_ERROR),
|
||||
fWriterWriterCount(0),
|
||||
fWriterReaderCount(0)
|
||||
{
|
||||
_Init(NULL);
|
||||
}
|
||||
|
||||
// constructor
|
||||
RWLocker::RWLocker(const char* name)
|
||||
: fLock(name),
|
||||
fMutex(),
|
||||
fQueue(),
|
||||
fReaderCount(0),
|
||||
fWriterCount(0),
|
||||
fReadLockInfos(8),
|
||||
fWriter(B_ERROR),
|
||||
fWriterWriterCount(0),
|
||||
fWriterReaderCount(0)
|
||||
{
|
||||
_Init(name);
|
||||
}
|
||||
|
||||
// destructor
|
||||
RWLocker::~RWLocker()
|
||||
{
|
||||
fLock.Lock();
|
||||
delete_sem(fMutex.semaphore);
|
||||
delete_sem(fQueue.semaphore);
|
||||
for (int32 i = 0; ReadLockInfo* info = _ReadLockInfoAt(i); i++)
|
||||
delete info;
|
||||
}
|
||||
|
||||
// ReadLock
|
||||
bool
|
||||
RWLocker::ReadLock()
|
||||
{
|
||||
status_t error = _ReadLock(B_INFINITE_TIMEOUT);
|
||||
return (error == B_OK);
|
||||
}
|
||||
|
||||
// ReadLockWithTimeout
|
||||
status_t
|
||||
RWLocker::ReadLockWithTimeout(bigtime_t timeout)
|
||||
{
|
||||
bigtime_t absoluteTimeout = system_time() + timeout;
|
||||
// take care of overflow
|
||||
if (timeout > 0 && absoluteTimeout < 0)
|
||||
absoluteTimeout = B_INFINITE_TIMEOUT;
|
||||
return _ReadLock(absoluteTimeout);
|
||||
}
|
||||
|
||||
// ReadUnlock
|
||||
void
|
||||
RWLocker::ReadUnlock()
|
||||
{
|
||||
if (fLock.Lock()) {
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread == fWriter) {
|
||||
// We (also) have a write lock.
|
||||
if (fWriterReaderCount > 0)
|
||||
fWriterReaderCount--;
|
||||
// else: error: unmatched ReadUnlock()
|
||||
} else {
|
||||
int32 index = _IndexOf(thread);
|
||||
if (ReadLockInfo* info = _ReadLockInfoAt(index)) {
|
||||
fReaderCount--;
|
||||
if (--info->count == 0) {
|
||||
// The outer read lock bracket for the thread has been
|
||||
// reached. Dispose the info.
|
||||
_DeleteReadLockInfo(index);
|
||||
}
|
||||
if (fReaderCount == 0) {
|
||||
// The last reader needs to unlock the mutex.
|
||||
_ReleaseBenaphore(fMutex);
|
||||
}
|
||||
} // else: error: caller has no read lock
|
||||
}
|
||||
fLock.Unlock();
|
||||
} // else: we are probably going to be destroyed
|
||||
}
|
||||
|
||||
// IsReadLocked
|
||||
//
|
||||
// Returns whether or not the calling thread owns a read lock or even a
|
||||
// write lock.
|
||||
bool
|
||||
RWLocker::IsReadLocked() const
|
||||
{
|
||||
bool result = false;
|
||||
if (fLock.Lock()) {
|
||||
thread_id thread = find_thread(NULL);
|
||||
result = (thread == fWriter || _IndexOf(thread) >= 0);
|
||||
fLock.Unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// WriteLock
|
||||
bool
|
||||
RWLocker::WriteLock()
|
||||
{
|
||||
status_t error = _WriteLock(B_INFINITE_TIMEOUT);
|
||||
return (error == B_OK);
|
||||
}
|
||||
|
||||
// WriteLockWithTimeout
|
||||
status_t
|
||||
RWLocker::WriteLockWithTimeout(bigtime_t timeout)
|
||||
{
|
||||
bigtime_t absoluteTimeout = system_time() + timeout;
|
||||
// take care of overflow
|
||||
if (timeout > 0 && absoluteTimeout < 0)
|
||||
absoluteTimeout = B_INFINITE_TIMEOUT;
|
||||
return _WriteLock(absoluteTimeout);
|
||||
}
|
||||
|
||||
// WriteUnlock
|
||||
void
|
||||
RWLocker::WriteUnlock()
|
||||
{
|
||||
if (fLock.Lock()) {
|
||||
thread_id thread = find_thread(NULL);
|
||||
if (thread == fWriter) {
|
||||
fWriterCount--;
|
||||
if (--fWriterWriterCount == 0) {
|
||||
// The outer write lock bracket for the thread has been
|
||||
// reached.
|
||||
fWriter = B_ERROR;
|
||||
if (fWriterReaderCount > 0) {
|
||||
// We still own read locks.
|
||||
_NewReadLockInfo(thread, fWriterReaderCount);
|
||||
// A reader that expects to be the first reader may wait
|
||||
// at the mutex semaphore. We need to wake it up.
|
||||
if (fReaderCount > 0)
|
||||
_ReleaseBenaphore(fMutex);
|
||||
fReaderCount += fWriterReaderCount;
|
||||
fWriterReaderCount = 0;
|
||||
} else {
|
||||
// We don't own any read locks. So we have to release the
|
||||
// mutex benaphore.
|
||||
_ReleaseBenaphore(fMutex);
|
||||
}
|
||||
}
|
||||
} // else: error: unmatched WriteUnlock()
|
||||
fLock.Unlock();
|
||||
} // else: We're probably going to die.
|
||||
}
|
||||
|
||||
// IsWriteLocked
|
||||
//
|
||||
// Returns whether or not the calling thread owns a write lock.
|
||||
bool
|
||||
RWLocker::IsWriteLocked() const
|
||||
{
|
||||
return (fWriter == find_thread(NULL));
|
||||
}
|
||||
|
||||
// _Init
|
||||
void
|
||||
RWLocker::_Init(const char* name)
|
||||
{
|
||||
// init the mutex benaphore
|
||||
BString mutexName(name);
|
||||
mutexName += "_RWLocker_mutex";
|
||||
fMutex.semaphore = create_sem(0, mutexName.String());
|
||||
fMutex.counter = 0;
|
||||
// init the queueing benaphore
|
||||
BString queueName(name);
|
||||
queueName += "_RWLocker_queue";
|
||||
fQueue.semaphore = create_sem(0, queueName.String());
|
||||
fQueue.counter = 0;
|
||||
}
|
||||
|
||||
// _ReadLock
|
||||
//
|
||||
// /timeout/ -- absolute timeout
|
||||
status_t
|
||||
RWLocker::_ReadLock(bigtime_t timeout)
|
||||
{
|
||||
status_t error = B_OK;
|
||||
thread_id thread = find_thread(NULL);
|
||||
bool locked = false;
|
||||
if (fLock.Lock()) {
|
||||
// Check, if we already own a read (or write) lock. In this case we
|
||||
// can skip the usual locking procedure.
|
||||
if (thread == fWriter) {
|
||||
// We already own a write lock.
|
||||
fWriterReaderCount++;
|
||||
locked = true;
|
||||
} else if (ReadLockInfo* info = _ReadLockInfoAt(_IndexOf(thread))) {
|
||||
// We already own a read lock.
|
||||
info->count++;
|
||||
fReaderCount++;
|
||||
locked = true;
|
||||
}
|
||||
fLock.Unlock();
|
||||
} else // failed to lock the data
|
||||
error = B_ERROR;
|
||||
// Usual locking, i.e. we do not already own a read or write lock.
|
||||
if (error == B_OK && !locked) {
|
||||
error = _AcquireBenaphore(fQueue, timeout);
|
||||
if (error == B_OK) {
|
||||
if (fLock.Lock()) {
|
||||
bool firstReader = false;
|
||||
if (++fReaderCount == 1) {
|
||||
// We are the first reader.
|
||||
_NewReadLockInfo(thread);
|
||||
firstReader = true;
|
||||
} else
|
||||
_NewReadLockInfo(thread);
|
||||
fLock.Unlock();
|
||||
// The first reader needs to lock the mutex.
|
||||
if (firstReader) {
|
||||
error = _AcquireBenaphore(fMutex, timeout);
|
||||
switch (error) {
|
||||
case B_OK:
|
||||
// fine
|
||||
break;
|
||||
case B_TIMED_OUT: {
|
||||
// clean up
|
||||
if (fLock.Lock()) {
|
||||
_DeleteReadLockInfo(_IndexOf(thread));
|
||||
fReaderCount--;
|
||||
fLock.Unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Probably we are going to be destroyed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Let the next candidate enter the game.
|
||||
_ReleaseBenaphore(fQueue);
|
||||
} else {
|
||||
// We couldn't lock the data, which can only happen, if
|
||||
// we're going to be destroyed.
|
||||
error = B_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// _WriteLock
|
||||
//
|
||||
// /timeout/ -- absolute timeout
|
||||
status_t
|
||||
RWLocker::_WriteLock(bigtime_t timeout)
|
||||
{
|
||||
status_t error = B_ERROR;
|
||||
if (fLock.Lock()) {
|
||||
bool infiniteTimeout = (timeout == B_INFINITE_TIMEOUT);
|
||||
bool locked = false;
|
||||
int32 readerCount = 0;
|
||||
thread_id thread = find_thread(NULL);
|
||||
int32 index = _IndexOf(thread);
|
||||
if (ReadLockInfo* info = _ReadLockInfoAt(index)) {
|
||||
// We already own a read lock.
|
||||
if (fWriterCount > 0) {
|
||||
// There are writers before us.
|
||||
if (infiniteTimeout) {
|
||||
// Timeout is infinite and there are writers before us.
|
||||
// Unregister the read locks and lock as usual.
|
||||
readerCount = info->count;
|
||||
fWriterCount++;
|
||||
fReaderCount -= readerCount;
|
||||
_DeleteReadLockInfo(index);
|
||||
error = B_OK;
|
||||
} else {
|
||||
// The timeout is finite and there are readers before us:
|
||||
// let the write lock request fail.
|
||||
error = B_WOULD_BLOCK;
|
||||
}
|
||||
} else if (info->count == fReaderCount) {
|
||||
// No writers before us.
|
||||
// We are the only read lock owners. Just move the read lock
|
||||
// info data to the special writer fields and then we are done.
|
||||
// Note: At this point we may overtake readers that already
|
||||
// have acquired the queueing benaphore, but have not yet
|
||||
// locked the data. But that doesn't harm.
|
||||
fWriter = thread;
|
||||
fWriterCount++;
|
||||
fWriterWriterCount = 1;
|
||||
fWriterReaderCount = info->count;
|
||||
fReaderCount -= fWriterReaderCount;
|
||||
_DeleteReadLockInfo(index);
|
||||
locked = true;
|
||||
error = B_OK;
|
||||
} else {
|
||||
// No writers before us, but other readers.
|
||||
// Note, we're quite restrictive here. If there are only
|
||||
// readers before us, we could reinstall our readers, if
|
||||
// our request times out. Unfortunately it is not easy
|
||||
// to ensure, that no writer overtakes us between unlocking
|
||||
// the data and acquiring the queuing benaphore.
|
||||
if (infiniteTimeout) {
|
||||
// Unregister the readers and lock as usual.
|
||||
readerCount = info->count;
|
||||
fWriterCount++;
|
||||
fReaderCount -= readerCount;
|
||||
_DeleteReadLockInfo(index);
|
||||
error = B_OK;
|
||||
} else
|
||||
error = B_WOULD_BLOCK;
|
||||
}
|
||||
} else {
|
||||
// We don't own a read lock.
|
||||
if (fWriter == thread) {
|
||||
// ... but a write lock.
|
||||
fWriterCount++;
|
||||
fWriterWriterCount++;
|
||||
locked = true;
|
||||
error = B_OK;
|
||||
} else {
|
||||
// We own neither read nor write locks.
|
||||
// Lock as usual.
|
||||
fWriterCount++;
|
||||
error = B_OK;
|
||||
}
|
||||
}
|
||||
fLock.Unlock();
|
||||
// Usual locking...
|
||||
// First step: acquire the queueing benaphore.
|
||||
if (!locked && error == B_OK) {
|
||||
error = _AcquireBenaphore(fQueue, timeout);
|
||||
switch (error) {
|
||||
case B_OK:
|
||||
break;
|
||||
case B_TIMED_OUT: {
|
||||
// clean up
|
||||
if (fLock.Lock()) {
|
||||
fWriterCount--;
|
||||
fLock.Unlock();
|
||||
} // else: failed to lock the data: we're probably going
|
||||
// to die.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Probably we're going to die.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Second step: acquire the mutex benaphore.
|
||||
if (!locked && error == B_OK) {
|
||||
error = _AcquireBenaphore(fMutex, timeout);
|
||||
switch (error) {
|
||||
case B_OK: {
|
||||
// Yeah, we made it. Set the special writer fields.
|
||||
fWriter = thread;
|
||||
fWriterWriterCount = 1;
|
||||
fWriterReaderCount = readerCount;
|
||||
break;
|
||||
}
|
||||
case B_TIMED_OUT: {
|
||||
// clean up
|
||||
if (fLock.Lock()) {
|
||||
fWriterCount--;
|
||||
fLock.Unlock();
|
||||
} // else: failed to lock the data: we're probably going
|
||||
// to die.
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Probably we're going to die.
|
||||
break;
|
||||
}
|
||||
// Whatever happened, we have to release the queueing benaphore.
|
||||
_ReleaseBenaphore(fQueue);
|
||||
}
|
||||
} else // failed to lock the data
|
||||
error = B_ERROR;
|
||||
return error;
|
||||
}
|
||||
|
||||
// _AddReadLockInfo
|
||||
int32
|
||||
RWLocker::_AddReadLockInfo(ReadLockInfo* info)
|
||||
{
|
||||
int32 index = fReadLockInfos.CountItems();
|
||||
fReadLockInfos.AddItem(info, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
// _NewReadLockInfo
|
||||
//
|
||||
// Create a new read lock info for the supplied thread and add it to the
|
||||
// list. Returns the index of the info.
|
||||
int32
|
||||
RWLocker::_NewReadLockInfo(thread_id thread, int32 count)
|
||||
{
|
||||
ReadLockInfo* info = new ReadLockInfo;
|
||||
info->reader = thread;
|
||||
info->count = count;
|
||||
return _AddReadLockInfo(info);
|
||||
}
|
||||
|
||||
// _DeleteReadLockInfo
|
||||
void
|
||||
RWLocker::_DeleteReadLockInfo(int32 index)
|
||||
{
|
||||
if (ReadLockInfo* info = (ReadLockInfo*)fReadLockInfos.RemoveItem(index))
|
||||
delete info;
|
||||
}
|
||||
|
||||
// _ReadLockInfoAt
|
||||
RWLocker::ReadLockInfo*
|
||||
RWLocker::_ReadLockInfoAt(int32 index) const
|
||||
{
|
||||
return (ReadLockInfo*)fReadLockInfos.ItemAt(index);
|
||||
}
|
||||
|
||||
// _IndexOf
|
||||
int32
|
||||
RWLocker::_IndexOf(thread_id thread) const
|
||||
{
|
||||
int32 count = fReadLockInfos.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
if (_ReadLockInfoAt(i)->reader == thread)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// _AcquireBenaphore
|
||||
status_t
|
||||
RWLocker::_AcquireBenaphore(Benaphore& benaphore, bigtime_t timeout)
|
||||
{
|
||||
status_t error = B_OK;
|
||||
if (atomic_add(&benaphore.counter, 1) > 0) {
|
||||
error = acquire_sem_etc(benaphore.semaphore, 1, B_ABSOLUTE_TIMEOUT,
|
||||
timeout);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// _ReleaseBenaphore
|
||||
void
|
||||
RWLocker::_ReleaseBenaphore(Benaphore& benaphore)
|
||||
{
|
||||
if (atomic_add(&benaphore.counter, -1) > 1)
|
||||
release_sem(benaphore.semaphore);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* IngoWeinhold <[email protected]>
|
||||
*/
|
||||
|
||||
// This class provides a reader/writer locking mechanism:
|
||||
// * A writer needs an exclusive lock.
|
||||
// * For a reader a non-exclusive lock to be shared with other readers is
|
||||
// sufficient.
|
||||
// * The ownership of a lock is bound to the thread that requested the lock;
|
||||
// the same thread has to call Unlock() later.
|
||||
// * Nested locking is supported: a number of XXXLock() calls needs to be
|
||||
// bracketed by the same number of XXXUnlock() calls.
|
||||
// * The lock acquiration strategy is fair: a lock applicant needs to wait
|
||||
// only for those threads that already own a lock or requested one before
|
||||
// the current thread. No one can overtake. E.g. if a thread owns a read
|
||||
// lock, another one is waiting for a write lock, then a third one
|
||||
// requesting a read lock has to wait until the write locker is done.
|
||||
// This does not hold for threads that already own a lock (nested locking).
|
||||
// A read lock owner is immediately granted another read lock and a write
|
||||
// lock owner another write or a read lock.
|
||||
// * A write lock owner is allowed to request a read lock and a read lock
|
||||
// owner a write lock. While the first case is not problematic, the
|
||||
// second one needs some further explanation: A read lock owner requesting
|
||||
// a write lock temporarily looses its read lock(s) until the write lock
|
||||
// is granted. Otherwise two read lock owning threads trying to get
|
||||
// write locks at the same time would dead lock each other. The only
|
||||
// problem with this solution is, that the write lock acquiration must
|
||||
// not fail, because in that case the thread could not be given back
|
||||
// its read lock(s), since another thread may have been given a write lock
|
||||
// in the mean time. Fortunately locking can fail only either, if the
|
||||
// locker has been deleted, or, if a timeout occured. Therefore
|
||||
// WriteLockWithTimeout() immediatlely returns with a B_WOULD_BLOCK error
|
||||
// code, if the caller already owns a read lock (but no write lock) and
|
||||
// another thread already owns or has requested a read or write lock.
|
||||
// * Calls to read and write locking methods may interleave arbitrarily,
|
||||
// e.g.: ReadLock(); WriteLock(); ReadUnlock(); WriteUnlock();
|
||||
//
|
||||
// Important note: Read/WriteLock() can fail only, if the locker has been
|
||||
// deleted. However, it is NOT save to invoke any method on a deleted
|
||||
// locker object.
|
||||
//
|
||||
// Implementation details:
|
||||
// A locker needs three semaphores (a BLocker and two semaphores): one
|
||||
// to protect the lockers data, one as a reader/writer mutex (to be
|
||||
// acquired by each writer and the first reader) and one for queueing
|
||||
// waiting readers and writers. The simplified locking/unlocking
|
||||
// algorithm is the following:
|
||||
//
|
||||
// writer reader
|
||||
// queue.acquire() queue.acquire()
|
||||
// mutex.acquire() if (first reader) mutex.acquire()
|
||||
// queue.release() queue.release()
|
||||
// ... ...
|
||||
// mutex.release() if (last reader) mutex.release()
|
||||
//
|
||||
// One thread at maximum waits at the mutex, the others at the queueing
|
||||
// semaphore. Unfortunately features as nested locking and timeouts make
|
||||
// things more difficult. Therefore readers as well as writers need to check
|
||||
// whether they already own a lock before acquiring the queueing semaphore.
|
||||
// The data for the readers are stored in a list of ReadLockInfo structures;
|
||||
// the writer data are stored in some special fields. /fReaderCount/ and
|
||||
// /fWriterCount/ contain the total count of unbalanced Read/WriteLock()
|
||||
// calls, /fWriterReaderCount/ and /fWriterWriterCount/ only from those of
|
||||
// the current write lock owner (/fWriter/). To be a bit more precise:
|
||||
// /fWriterReaderCount/ is not contained in /fReaderCount/, but
|
||||
// /fWriterWriterCount/ is contained in /fWriterCount/. Therefore
|
||||
// /fReaderCount/ can be considered to be the count of true reader's read
|
||||
// locks.
|
||||
|
||||
#ifndef RW_LOCKER_H
|
||||
#define RW_LOCKER_H
|
||||
|
||||
#include <List.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include "AutoLocker.h"
|
||||
|
||||
class RWLocker {
|
||||
public:
|
||||
RWLocker();
|
||||
RWLocker(const char* name);
|
||||
virtual ~RWLocker();
|
||||
|
||||
bool ReadLock();
|
||||
status_t ReadLockWithTimeout(bigtime_t timeout);
|
||||
void ReadUnlock();
|
||||
bool IsReadLocked() const;
|
||||
|
||||
bool WriteLock();
|
||||
status_t WriteLockWithTimeout(bigtime_t timeout);
|
||||
void WriteUnlock();
|
||||
bool IsWriteLocked() const;
|
||||
|
||||
private:
|
||||
struct ReadLockInfo;
|
||||
struct Benaphore {
|
||||
sem_id semaphore;
|
||||
int32 counter;
|
||||
};
|
||||
|
||||
private:
|
||||
void _Init(const char* name);
|
||||
status_t _ReadLock(bigtime_t timeout);
|
||||
status_t _WriteLock(bigtime_t timeout);
|
||||
|
||||
int32 _AddReadLockInfo(ReadLockInfo* info);
|
||||
int32 _NewReadLockInfo(thread_id thread,
|
||||
int32 count = 1);
|
||||
void _DeleteReadLockInfo(int32 index);
|
||||
ReadLockInfo* _ReadLockInfoAt(int32 index) const;
|
||||
int32 _IndexOf(thread_id thread) const;
|
||||
|
||||
static status_t _AcquireBenaphore(Benaphore& benaphore,
|
||||
bigtime_t timeout);
|
||||
static void _ReleaseBenaphore(Benaphore& benaphore);
|
||||
|
||||
private:
|
||||
mutable BLocker fLock; // data lock
|
||||
Benaphore fMutex; // critical code mutex
|
||||
Benaphore fQueue; // queueing semaphore
|
||||
int32 fReaderCount; // total count...
|
||||
int32 fWriterCount; // total count...
|
||||
BList fReadLockInfos;
|
||||
thread_id fWriter; // current write lock owner
|
||||
int32 fWriterWriterCount; // write lock owner count
|
||||
int32 fWriterReaderCount; // writer read lock owner
|
||||
// count
|
||||
};
|
||||
|
||||
typedef AutoLocker<RWLocker, AutoLockerReadLocking<RWLocker> > AutoReadLocker;
|
||||
typedef AutoLocker<RWLocker, AutoLockerWriteLocking<RWLocker> > AutoWriteLocker;
|
||||
|
||||
#endif // RW_LOCKER_H
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <Point.h>
|
||||
#include <String.h>
|
||||
|
||||
// point_line_distance
|
||||
double
|
||||
point_line_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
return ((x - x2) * dy - (y - y2) * dx) / sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
// point_line_distance
|
||||
double
|
||||
point_line_distance(BPoint point, BPoint pa, BPoint pb)
|
||||
{
|
||||
// first figure out if point is between segment start and end points
|
||||
double a = point_point_distance(point, pb);
|
||||
double b = point_point_distance(point, pa);
|
||||
double c = point_point_distance(pa, pb);
|
||||
|
||||
float currentDist = min_c(a, b);
|
||||
|
||||
if (a > 0.0 && b > 0.0) {
|
||||
double alpha = acos((b*b + c*c - a*a) / (2*b*c));
|
||||
double beta = acos((a*a + c*c - b*b) / (2*a*c));
|
||||
|
||||
if (alpha <= PI2 && beta <= PI2) {
|
||||
currentDist = fabs(point_line_distance(pa.x, pa.y, pb.x, pb.y,
|
||||
point.x, point.y));
|
||||
}
|
||||
}
|
||||
|
||||
return currentDist;
|
||||
}
|
||||
|
||||
// calc_angle
|
||||
double
|
||||
calc_angle(BPoint origin, BPoint from, BPoint to, bool degree)
|
||||
{
|
||||
double angle = 0.0;
|
||||
|
||||
double d = point_line_distance(from.x, from.y,
|
||||
origin.x, origin.y,
|
||||
to.x, to.y);
|
||||
if (d != 0.0) {
|
||||
double a = point_point_distance(from, to);
|
||||
double b = point_point_distance(from, origin);
|
||||
double c = point_point_distance(to, origin);
|
||||
if (a > 0.0 && b > 0.0 && c > 0.0) {
|
||||
angle = acos((b*b + c*c - a*a) / (2.0*b*c));
|
||||
|
||||
if (d < 0.0)
|
||||
angle = -angle;
|
||||
|
||||
if (degree)
|
||||
angle = angle * 180.0 / PI;
|
||||
}
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
// write_string
|
||||
status_t
|
||||
write_string(BPositionIO* stream, BString& string)
|
||||
{
|
||||
if (!stream)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ssize_t written = stream->Write(string.String(), string.Length());
|
||||
if (written > B_OK && written < string.Length())
|
||||
written = B_ERROR;
|
||||
string.SetTo("");
|
||||
return written;
|
||||
}
|
||||
|
||||
// append_float
|
||||
void
|
||||
append_float(BString& string, float n, int32 maxDigits = 4)
|
||||
{
|
||||
int32 rounded = n >= 0.0 ? (int32)fabs(floorf(n)) : (int32)fabs(ceilf(n));
|
||||
|
||||
if (n < 0.0) {
|
||||
string << "-";
|
||||
n *= -1.0;
|
||||
}
|
||||
string << rounded;
|
||||
|
||||
if ((float)rounded != n) {
|
||||
// find out how many digits remain
|
||||
n = n - rounded;
|
||||
rounded = (int32)(n * pow(10, maxDigits));
|
||||
char tmp[maxDigits + 1];
|
||||
sprintf(tmp, "%0*ld", (int)maxDigits, rounded);
|
||||
tmp[maxDigits] = 0;
|
||||
int32 digits = strlen(tmp);
|
||||
for (int32 i = strlen(tmp) - 1; i >= 0; i--) {
|
||||
if (tmp[i] == '0')
|
||||
digits--;
|
||||
else
|
||||
break;
|
||||
}
|
||||
// write after decimal
|
||||
if (digits > 0) {
|
||||
string << ".";
|
||||
for (int32 i = 0; i < digits; i++) {
|
||||
string << tmp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gauss
|
||||
double
|
||||
gauss(double f)
|
||||
{
|
||||
// this aint' a real gauss function
|
||||
/* if (f >= -1.0 && f <= 1.0) {
|
||||
if (f < -0.5) {
|
||||
f = -1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}
|
||||
|
||||
if (f < 0.5)
|
||||
return (1.0 - 2.0 * f*f);
|
||||
|
||||
f = 1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}*/
|
||||
if (f > 0.0) {
|
||||
if (f < 0.5)
|
||||
return (1.0 - 2.0 * f*f);
|
||||
|
||||
f = 1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SUPPORT_H
|
||||
#define SUPPORT_H
|
||||
|
||||
#include <Rect.h>
|
||||
|
||||
class BPositionIO;
|
||||
class BString;
|
||||
|
||||
// constrain
|
||||
inline void
|
||||
constrain(float& value, float min, float max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
if (value > max)
|
||||
value = max;
|
||||
}
|
||||
|
||||
// constrain_int32_0_255_asm
|
||||
inline int32
|
||||
constrain_int32_0_255_asm(int32 value) {
|
||||
asm("movl $0, %%ecx;
|
||||
movl $255, %%edx;
|
||||
cmpl %%ecx, %%eax;
|
||||
cmovl %%ecx, %%eax;
|
||||
cmpl %%edx, %%eax;
|
||||
cmovg %%edx, %%eax"
|
||||
: "=a" (value)
|
||||
: "a" (value)
|
||||
: "%ecx", "%edx" );
|
||||
return value;
|
||||
}
|
||||
|
||||
inline int32
|
||||
constrain_int32_0_255_c(int32 value) {
|
||||
return max_c(0, min_c(255, value));
|
||||
}
|
||||
|
||||
#define constrain_int32_0_255 constrain_int32_0_255_asm
|
||||
|
||||
// rect_to_int
|
||||
inline void
|
||||
rect_to_int(BRect r,
|
||||
int32& left, int32& top, int32& right, int32& bottom)
|
||||
{
|
||||
left = (int32)floorf(r.left);
|
||||
top = (int32)floorf(r.top);
|
||||
right = (int32)ceilf(r.right);
|
||||
bottom = (int32)ceilf(r.bottom);
|
||||
}
|
||||
|
||||
// point_point_distance
|
||||
inline float
|
||||
point_point_distance(BPoint a, BPoint b)
|
||||
{
|
||||
float xDiff = b.x - a.x;
|
||||
float yDiff = b.y - a.y;
|
||||
return sqrtf(xDiff * xDiff + yDiff * yDiff);
|
||||
}
|
||||
|
||||
// point_line_distance
|
||||
double
|
||||
point_line_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y);
|
||||
|
||||
// point_line_distance
|
||||
double
|
||||
point_line_distance(BPoint point, BPoint a, BPoint b);
|
||||
|
||||
// calc_angle
|
||||
double
|
||||
calc_angle(BPoint origin, BPoint from, BPoint to, bool degree = true);
|
||||
|
||||
/*
|
||||
template <class T>
|
||||
T min4(const T a, const T b, const T c, const T d)
|
||||
{
|
||||
T e = a < b ? a : b;
|
||||
T f = c < d ? c : d;
|
||||
return e < f ? e : f;
|
||||
}
|
||||
template <class T>
|
||||
T max4(const T a, const T b, const T c, const T d)
|
||||
{
|
||||
T e = a > b ? a : b;
|
||||
T f = c > d ? c : d;
|
||||
return e > f ? e : f;
|
||||
}
|
||||
*/
|
||||
inline float
|
||||
min4(float a, float b, float c, float d)
|
||||
{
|
||||
return min_c(a, min_c(b, min_c(c, d)));
|
||||
}
|
||||
|
||||
inline float
|
||||
max4(float a, float b, float c, float d)
|
||||
{
|
||||
return max_c(a, max_c(b, max_c(c, d)));
|
||||
}
|
||||
|
||||
inline float
|
||||
min5(float v1, float v2, float v3, float v4, float v5)
|
||||
{
|
||||
return min_c(min4(v1, v2, v3, v4), v5);
|
||||
}
|
||||
|
||||
inline float
|
||||
max5(float v1, float v2, float v3, float v4, float v5)
|
||||
{
|
||||
return max_c(max4(v1, v2, v3, v4), v5);
|
||||
}
|
||||
|
||||
inline float
|
||||
roundf(float v)
|
||||
{
|
||||
if (v >= 0.0)
|
||||
return floorf(v + 0.5);
|
||||
return ceilf(v - 0.5);
|
||||
}
|
||||
|
||||
status_t write_string(BPositionIO* stream, BString& string);
|
||||
void append_float(BString& string, float n, int32 maxDigits = 4);
|
||||
|
||||
double gauss(double f);
|
||||
|
||||
|
||||
# endif // SUPPORT_H
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "support_settings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Message.h>
|
||||
#include <Path.h>
|
||||
|
||||
// load_settings
|
||||
status_t
|
||||
load_settings(BMessage* message, const char* fileName, const char* folder)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (message) {
|
||||
BPath path;
|
||||
if ((ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) == B_OK) {
|
||||
// passing folder is optional
|
||||
if (folder)
|
||||
ret = path.Append(folder);
|
||||
if (ret == B_OK && (ret = path.Append(fileName)) == B_OK) {
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
if ((ret = file.InitCheck()) == B_OK) {
|
||||
ret = message->Unflatten(&file);
|
||||
file.Unset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// save_settings
|
||||
status_t
|
||||
save_settings(BMessage* message, const char* fileName, const char* folder)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (message) {
|
||||
BPath path;
|
||||
if ((ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) == B_OK) {
|
||||
// passing folder is optional
|
||||
if (folder && (ret = path.Append(folder)) == B_OK)
|
||||
ret = create_directory(path.Path(), 0777);
|
||||
if (ret == B_OK && (ret = path.Append(fileName)) == B_OK) {
|
||||
BFile file(path.Path(),
|
||||
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||
if ((ret = file.InitCheck()) == B_OK) {
|
||||
ret = message->Flatten(&file);
|
||||
file.Unset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SUPPORT_SETTINGS_H
|
||||
#define SUPPORT_SETTINGS_H
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
class BMessage;
|
||||
|
||||
status_t load_settings(BMessage* message, const char* fileName,
|
||||
const char* folder = NULL);
|
||||
|
||||
status_t save_settings(BMessage* message, const char* fileName,
|
||||
const char* folder = NULL);
|
||||
|
||||
|
||||
# endif // SUPPORT_SETTINGS_H
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <DataIO.h>
|
||||
#include <Directory.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Screen.h>
|
||||
#include <String.h>
|
||||
#include <Path.h>
|
||||
#include <View.h>
|
||||
|
||||
#include <Space.h>
|
||||
|
||||
// stroke_frame
|
||||
void
|
||||
stroke_frame(BView* v, BRect r, rgb_color left, rgb_color top,
|
||||
rgb_color right, rgb_color bottom)
|
||||
{
|
||||
if (v && r.IsValid()) {
|
||||
v->BeginLineArray(4);
|
||||
v->AddLine(BPoint(r.left, r.bottom),
|
||||
BPoint(r.left, r.top), left);
|
||||
v->AddLine(BPoint(r.left + 1.0, r.top),
|
||||
BPoint(r.right, r.top), top);
|
||||
v->AddLine(BPoint(r.right, r.top + 1.0),
|
||||
BPoint(r.right, r.bottom), right);
|
||||
v->AddLine(BPoint(r.right - 1.0, r.bottom),
|
||||
BPoint(r.left + 1.0, r.bottom), bottom);
|
||||
v->EndLineArray();
|
||||
}
|
||||
}
|
||||
|
||||
// vertical_space
|
||||
Space*
|
||||
vertical_space()
|
||||
{
|
||||
return new Space(minimax(0.0, 3.0, 10000.0, 3.0, 1.0));
|
||||
}
|
||||
|
||||
// horizontal_space
|
||||
Space*
|
||||
horizontal_space()
|
||||
{
|
||||
return new Space(minimax(3.0, 0.0, 3.0, 10000.0, 1.0));
|
||||
}
|
||||
|
||||
// store_color_in_message
|
||||
status_t
|
||||
store_color_in_message(BMessage* message, rgb_color color)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (message) {
|
||||
ret = message->AddData("RGBColor", B_RGB_COLOR_TYPE,
|
||||
(void*)&color, sizeof(rgb_color));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// restore_color_from_message
|
||||
status_t
|
||||
restore_color_from_message(const BMessage* message, rgb_color& color, int32 index)
|
||||
{
|
||||
status_t ret = B_BAD_VALUE;
|
||||
if (message) {
|
||||
const void* colorPointer;
|
||||
ssize_t size = sizeof(rgb_color);
|
||||
ret = message->FindData("RGBColor", B_RGB_COLOR_TYPE, index,
|
||||
&colorPointer, &size);
|
||||
if (ret >= B_OK)
|
||||
color = *(const rgb_color*)colorPointer;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// make_color_drop_message
|
||||
BMessage
|
||||
make_color_drop_message(rgb_color color, BBitmap* bitmap)
|
||||
{
|
||||
// prepare message
|
||||
BMessage message(B_PASTE);
|
||||
char hexstr[7];
|
||||
sprintf(hexstr, "#%.2X%.2X%.2X", color.red, color.green, color.blue);
|
||||
message.AddData("text/plain", B_MIME_TYPE, &hexstr, sizeof(hexstr));
|
||||
message.AddData("RGBColor", B_RGB_COLOR_TYPE, &color, sizeof(color));
|
||||
// prepare bitmap
|
||||
if (bitmap && bitmap->IsValid()
|
||||
&& (bitmap->ColorSpace() == B_RGB32
|
||||
|| bitmap->ColorSpace() == B_RGBA32)) {
|
||||
uint8* bits = (uint8*)bitmap->Bits();
|
||||
uint32 bpr = bitmap->BytesPerRow();
|
||||
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
||||
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
||||
for (uint32 y = 0; y < height; y++) {
|
||||
uint8* bitsHandle = bits;
|
||||
for (uint32 x = 0; x < width; x++) {
|
||||
if (x == 0 || y == 0 ) {
|
||||
// top or left border
|
||||
bitsHandle[0] = (uint8)min_c(255, color.blue * 1.2 + 40);
|
||||
bitsHandle[1] = (uint8)min_c(255, color.green * 1.2 + 40);
|
||||
bitsHandle[2] = (uint8)min_c(255, color.red * 1.2 + 40);
|
||||
bitsHandle[3] = 180;
|
||||
} else if ((x == width - 2 || y == height - 2)
|
||||
&& !(x == width - 1 || y == height - 1)) {
|
||||
// bottom or right border
|
||||
bitsHandle[0] = (uint8)(color.blue * 0.8);
|
||||
bitsHandle[1] = (uint8)(color.green * 0.8);
|
||||
bitsHandle[2] = (uint8)(color.red * 0.8);
|
||||
bitsHandle[3] = 180;
|
||||
} else if (x == width - 1 || y == height - 1) {
|
||||
// shadow
|
||||
bitsHandle[0] = 0;
|
||||
bitsHandle[1] = 0;
|
||||
bitsHandle[2] = 0;
|
||||
bitsHandle[3] = 100;
|
||||
} else {
|
||||
// color
|
||||
bitsHandle[0] = color.blue;
|
||||
bitsHandle[1] = color.green;
|
||||
bitsHandle[2] = color.red;
|
||||
bitsHandle[3] = 180;
|
||||
}
|
||||
if ((x == 0 && y == height - 1) || (y == 0 && x == width - 1)) {
|
||||
// spare pixels of shadow
|
||||
bitsHandle[0] = 0;
|
||||
bitsHandle[1] = 0;
|
||||
bitsHandle[2] = 0;
|
||||
bitsHandle[3] = 50;
|
||||
}
|
||||
bitsHandle += 4;
|
||||
}
|
||||
bits += bpr;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
// make_sure_frame_is_on_screen
|
||||
void
|
||||
make_sure_frame_is_on_screen(BRect& frame, BWindow* window)
|
||||
{
|
||||
BScreen screen(window);
|
||||
if (frame.IsValid() && screen.IsValid()) {
|
||||
if (!screen.Frame().Contains(frame)) {
|
||||
// make sure frame fits in the screen
|
||||
if (frame.Width() > screen.Frame().Width())
|
||||
frame.right -= frame.Width() - screen.Frame().Width() + 10.0;
|
||||
if (frame.Height() > screen.Frame().Height())
|
||||
frame.bottom -= frame.Height() - screen.Frame().Height() + 30.0;
|
||||
// frame is now at the most the size of the screen
|
||||
if (frame.right > screen.Frame().right)
|
||||
frame.OffsetBy(-(frame.right - screen.Frame().right), 0.0);
|
||||
if (frame.bottom > screen.Frame().bottom)
|
||||
frame.OffsetBy(0.0, -(frame.bottom - screen.Frame().bottom));
|
||||
if (frame.left < screen.Frame().left)
|
||||
frame.OffsetBy((screen.Frame().left - frame.left), 0.0);
|
||||
if (frame.top < screen.Frame().top)
|
||||
frame.OffsetBy(0.0, (screen.Frame().top - frame.top));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print_modifiers
|
||||
void
|
||||
print_modifiers()
|
||||
{
|
||||
uint32 mods = modifiers();
|
||||
if (mods & B_SHIFT_KEY)
|
||||
printf("B_SHIFT_KEY\n");
|
||||
if (mods & B_COMMAND_KEY)
|
||||
printf("B_COMMAND_KEY\n");
|
||||
if (mods & B_CONTROL_KEY)
|
||||
printf("B_CONTROL_KEY\n");
|
||||
if (mods & B_CAPS_LOCK)
|
||||
printf("B_CAPS_LOCK\n");
|
||||
if (mods & B_SCROLL_LOCK)
|
||||
printf("B_SCROLL_LOCK\n");
|
||||
if (mods & B_NUM_LOCK)
|
||||
printf("B_NUM_LOCK\n");
|
||||
if (mods & B_OPTION_KEY)
|
||||
printf("B_OPTION_KEY\n");
|
||||
if (mods & B_MENU_KEY)
|
||||
printf("B_MENU_KEY\n");
|
||||
if (mods & B_LEFT_SHIFT_KEY)
|
||||
printf("B_LEFT_SHIFT_KEY\n");
|
||||
if (mods & B_RIGHT_SHIFT_KEY)
|
||||
printf("B_RIGHT_SHIFT_KEY\n");
|
||||
if (mods & B_LEFT_COMMAND_KEY)
|
||||
printf("B_LEFT_COMMAND_KEY\n");
|
||||
if (mods & B_RIGHT_COMMAND_KEY)
|
||||
printf("B_RIGHT_COMMAND_KEY\n");
|
||||
if (mods & B_LEFT_CONTROL_KEY)
|
||||
printf("B_LEFT_CONTROL_KEY\n");
|
||||
if (mods & B_RIGHT_CONTROL_KEY)
|
||||
printf("B_RIGHT_CONTROL_KEY\n");
|
||||
if (mods & B_LEFT_OPTION_KEY)
|
||||
printf("B_LEFT_OPTION_KEY\n");
|
||||
if (mods & B_RIGHT_OPTION_KEY)
|
||||
printf("B_RIGHT_OPTION_KEY\n");
|
||||
}
|
||||
|
||||
/*
|
||||
// convert_cap_mode
|
||||
agg::line_cap_e
|
||||
convert_cap_mode(uint32 mode)
|
||||
{
|
||||
agg::line_cap_e aggMode = agg::butt_cap;
|
||||
switch (mode) {
|
||||
case CAP_MODE_BUTT:
|
||||
aggMode = agg::butt_cap;
|
||||
break;
|
||||
case CAP_MODE_SQUARE:
|
||||
aggMode = agg::square_cap;
|
||||
break;
|
||||
case CAP_MODE_ROUND:
|
||||
aggMode = agg::round_cap;
|
||||
break;
|
||||
}
|
||||
return aggMode;
|
||||
}
|
||||
|
||||
// convert_cap_mode
|
||||
agg::line_join_e
|
||||
convert_join_mode(uint32 mode)
|
||||
{
|
||||
agg::line_join_e aggMode = agg::miter_join;
|
||||
switch (mode) {
|
||||
case JOIN_MODE_MITER:
|
||||
aggMode = agg::miter_join;
|
||||
break;
|
||||
case JOIN_MODE_ROUND:
|
||||
aggMode = agg::round_join;
|
||||
break;
|
||||
case JOIN_MODE_BEVEL:
|
||||
aggMode = agg::bevel_join;
|
||||
break;
|
||||
}
|
||||
return aggMode;
|
||||
}
|
||||
*/
|
||||
|
||||
// string_for_color_space
|
||||
const char*
|
||||
string_for_color_space(color_space format)
|
||||
{
|
||||
const char* name = "<unkown format>";
|
||||
switch (format) {
|
||||
case B_RGB32:
|
||||
name = "B_RGB32";
|
||||
break;
|
||||
case B_RGBA32:
|
||||
name = "B_RGBA32";
|
||||
break;
|
||||
case B_RGB32_BIG:
|
||||
name = "B_RGB32_BIG";
|
||||
break;
|
||||
case B_RGBA32_BIG:
|
||||
name = "B_RGBA32_BIG";
|
||||
break;
|
||||
case B_RGB24:
|
||||
name = "B_RGB24";
|
||||
break;
|
||||
case B_RGB24_BIG:
|
||||
name = "B_RGB24_BIG";
|
||||
break;
|
||||
case B_CMAP8:
|
||||
name = "B_CMAP8";
|
||||
break;
|
||||
case B_GRAY8:
|
||||
name = "B_GRAY8";
|
||||
break;
|
||||
case B_GRAY1:
|
||||
name = "B_GRAY1";
|
||||
break;
|
||||
|
||||
// YCbCr
|
||||
case B_YCbCr422:
|
||||
name = "B_YCbCr422";
|
||||
break;
|
||||
case B_YCbCr411:
|
||||
name = "B_YCbCr411";
|
||||
break;
|
||||
case B_YCbCr444:
|
||||
name = "B_YCbCr444";
|
||||
break;
|
||||
case B_YCbCr420:
|
||||
name = "B_YCbCr420";
|
||||
break;
|
||||
|
||||
// YUV
|
||||
case B_YUV422:
|
||||
name = "B_YUV422";
|
||||
break;
|
||||
case B_YUV411:
|
||||
name = "B_YUV411";
|
||||
break;
|
||||
case B_YUV444:
|
||||
name = "B_YUV444";
|
||||
break;
|
||||
case B_YUV420:
|
||||
name = "B_YUV420";
|
||||
break;
|
||||
|
||||
case B_YUV9:
|
||||
name = "B_YUV9";
|
||||
break;
|
||||
case B_YUV12:
|
||||
name = "B_YUV12";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// print_color_space
|
||||
void
|
||||
print_color_space(color_space format)
|
||||
{
|
||||
printf("%s\n", string_for_color_space(format));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#ifndef SUPPORT_UI_H
|
||||
#define SUPPORT_UI_H
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Rect.h>
|
||||
#include <agg_math_stroke.h>
|
||||
|
||||
class BBitmap;
|
||||
class BDataIO;
|
||||
class BMessage;
|
||||
class BPositionIO;
|
||||
class BString;
|
||||
class BView;
|
||||
class BWindow;
|
||||
class Space;
|
||||
|
||||
// looper of view must be locked!
|
||||
void stroke_frame(BView* view, BRect frame,
|
||||
rgb_color left, rgb_color top,
|
||||
rgb_color right, rgb_color bottom);
|
||||
|
||||
|
||||
Space* vertical_space();
|
||||
Space* horizontal_space();
|
||||
|
||||
status_t store_color_in_message(BMessage* message, rgb_color color);
|
||||
|
||||
status_t restore_color_from_message(const BMessage* message, rgb_color& color, int32 index = 0);
|
||||
|
||||
BMessage make_color_drop_message(rgb_color color, BBitmap* bitmap);
|
||||
|
||||
void make_sure_frame_is_on_screen(BRect& frame, BWindow* window);
|
||||
|
||||
void print_modifiers();
|
||||
|
||||
//agg::line_cap_e convert_cap_mode(uint32 mode);
|
||||
//agg::line_join_e convert_join_mode(uint32 mode);
|
||||
|
||||
const char* string_for_color_space(color_space format);
|
||||
void print_color_space(color_space format);
|
||||
|
||||
|
||||
// Those are already defined in newer versions of BeOS
|
||||
#if !defined(B_BEOS_VERSION_DANO) && !defined(__HAIKU__)
|
||||
|
||||
// rgb_color == rgb_color
|
||||
static inline bool
|
||||
operator==(const rgb_color& a, const rgb_color& b)
|
||||
{
|
||||
return a.red == b.red
|
||||
&& a.green == b.green
|
||||
&& a.blue == b.blue
|
||||
&& a.alpha == b.alpha;
|
||||
}
|
||||
|
||||
// rgb_color != rgb_color
|
||||
static inline bool
|
||||
operator!=(const rgb_color& a, const rgb_color& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
#endif // B_BEOS_VERSION <= ...
|
||||
|
||||
#endif // SUPPORT_UI_H
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <[email protected]>
|
||||
*/
|
||||
|
||||
#include "IconEditorApp.h"
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
IconEditorApp* app = new IconEditorApp();
|
||||
app->Run();
|
||||
|
||||
delete app;
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef PATH_MANIPULATOR_H
|
||||
#define PATH_MANIPULATOR_H
|
||||
|
||||
#include "Manipulator.h"
|
||||
|
||||
class AddPointCommand;
|
||||
class ChangePointCommand;
|
||||
class UndoStack;
|
||||
class InsertPointCommand;
|
||||
class Selection;
|
||||
class StateView;
|
||||
class VectorPath;
|
||||
|
||||
//class PathSelection {
|
||||
// public:
|
||||
// PathSelection();
|
||||
// virtual ~PathSelection();
|
||||
//
|
||||
// virtual PathSelection* Clone() const;
|
||||
// virtual bool SetTo(const PathSelection* other);
|
||||
//
|
||||
// virtual Command* Delete();
|
||||
//};
|
||||
|
||||
class PathManipulator : public Manipulator {
|
||||
public:
|
||||
PathManipulator(VectorPath* path);
|
||||
virtual ~PathManipulator();
|
||||
|
||||
// Manipulator interface
|
||||
virtual void Draw(BView* into, BRect updateRect);
|
||||
|
||||
virtual bool MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where);
|
||||
virtual Command* MouseUp();
|
||||
virtual bool MouseOver(BPoint where);
|
||||
virtual bool DoubleClicked(BPoint where);
|
||||
|
||||
virtual BRect Bounds();
|
||||
virtual BRect TrackingBounds(BView* withinView);
|
||||
|
||||
virtual bool MessageReceived(BMessage* message,
|
||||
Command** _command);
|
||||
|
||||
virtual void ModifiersChanged(uint32 modifiers);
|
||||
virtual bool HandleKeyDown(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
virtual bool HandleKeyUp(uint32 key, uint32 modifiers,
|
||||
Command** _command);
|
||||
|
||||
virtual void UpdateCursor();
|
||||
|
||||
virtual void AttachedToView(BView* view);
|
||||
virtual void DetachedFromView(BView* view);
|
||||
|
||||
// Observer interface (Manipulator)
|
||||
virtual void ObjectChanged(const Observable* object);
|
||||
|
||||
// PathManipulator
|
||||
uint32 ControlFlags() const;
|
||||
|
||||
// PathSelection* Selection() const;
|
||||
//
|
||||
// path manipulation
|
||||
void ReversePath();
|
||||
|
||||
private:
|
||||
friend class PathCommand;
|
||||
friend class PointSelection;
|
||||
friend class EnterTransformPointsCommand;
|
||||
friend class ExitTransformPointsCommand;
|
||||
friend class TransformPointsCommand;
|
||||
// friend class NewPathCommand;
|
||||
friend class NudgePointsCommand;
|
||||
// friend class RemovePathCommand;
|
||||
friend class ReversePathCommand;
|
||||
// friend class SelectPathCommand;
|
||||
|
||||
void _SetMode(uint32 mode);
|
||||
|
||||
// BEGIN functions that need to be undoable
|
||||
void _AddPoint(BPoint where);
|
||||
void _InsertPoint(BPoint where, int32 index);
|
||||
void _SetInOutConnected(int32 index, bool connected);
|
||||
void _SetSharp(int32 index);
|
||||
|
||||
void _RemoveSelection();
|
||||
void _RemovePoint(int32 index);
|
||||
void _RemovePointIn(int32 index);
|
||||
void _RemovePointOut(int32 index);
|
||||
|
||||
Command* _Delete();
|
||||
|
||||
void _Select(BRect canvasRect);
|
||||
void _Select(int32 index, bool extend = false);
|
||||
void _Select(const int32* indices, int32 count, bool extend = false);
|
||||
void _Deselect(int32 index);
|
||||
void _ShiftSelection(int32 startIndex, int32 direction);
|
||||
bool _IsSelected(int32 index) const;
|
||||
// END functions that need to be undoable
|
||||
|
||||
void _InvalidateCanvas(BRect rect) const;
|
||||
void _InvalidateHighlightPoints(int32 newIndex, uint32 newMode);
|
||||
|
||||
void _UpdateSelection() const;
|
||||
|
||||
BRect _ControlPointRect() const;
|
||||
BRect _ControlPointRect(int32 index, uint32 mode) const;
|
||||
void _GetChangableAreas(BRect* pathArea,
|
||||
BRect* controlPointArea) const;
|
||||
|
||||
void _SetModeForMousePos(BPoint canvasWhere);
|
||||
|
||||
void _Nudge(BPoint direction);
|
||||
void _FinishNudging();
|
||||
|
||||
StateView* fCanvasView;
|
||||
|
||||
bool fCommandDown;
|
||||
bool fOptionDown;
|
||||
bool fShiftDown;
|
||||
bool fAltDown;
|
||||
|
||||
bool fClickToClose;
|
||||
|
||||
uint32 fMode;
|
||||
uint32 fFallBackMode;
|
||||
|
||||
bool fMouseDown;
|
||||
BPoint fTrackingStart;
|
||||
BPoint fLastCanvasPos;
|
||||
|
||||
VectorPath* fPath;
|
||||
int32 fCurrentPathPoint;
|
||||
BRect fPreviousBounds;
|
||||
|
||||
ChangePointCommand* fChangePointCommand;
|
||||
InsertPointCommand* fInsertPointCommand;
|
||||
AddPointCommand* fAddPointCommand;
|
||||
|
||||
Selection* fSelection;
|
||||
Selection* fOldSelection;
|
||||
|
||||
// stuff needed for nudging
|
||||
BPoint fNudgeOffset;
|
||||
bigtime_t fLastNudgeTime;
|
||||
// NudgePointsCommand* fNudgeCommand;
|
||||
};
|
||||
|
||||
#endif // SHAPE_STATE_H
|
||||
@@ -0,0 +1,855 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "VectorPath.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Message.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
#include <agg_basics.h>
|
||||
#include <agg_bounding_rect.h>
|
||||
#include <agg_conv_curve.h>
|
||||
#include <agg_curves.h>
|
||||
#include <agg_math.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
#define obj_new(type, n) ((type *)malloc ((n) * sizeof(type)))
|
||||
#define obj_renew(p, type, n) ((type *)realloc (p, (n) * sizeof(type)))
|
||||
#define obj_free free
|
||||
|
||||
#define ALLOC_CHUNKS 20
|
||||
|
||||
// get_path_storage
|
||||
bool
|
||||
get_path_storage(agg::path_storage& path,
|
||||
const control_point* points, int32 count, bool closed)
|
||||
{
|
||||
if (count > 1) {
|
||||
path.move_to(points[0].point.x,
|
||||
points[0].point.y);
|
||||
|
||||
for (int32 i = 1; i < count; i++) {
|
||||
path.curve4(points[i - 1].point_out.x,
|
||||
points[i - 1].point_out.y,
|
||||
points[i].point_in.x,
|
||||
points[i].point_in.y,
|
||||
points[i].point.x,
|
||||
points[i].point.y);
|
||||
}
|
||||
if (closed) {
|
||||
// curve from last to first control point
|
||||
path.curve4(points[count - 1].point_out.x,
|
||||
points[count - 1].point_out.y,
|
||||
points[0].point_in.x,
|
||||
points[0].point_in.y,
|
||||
points[0].point.x,
|
||||
points[0].point.y);
|
||||
path.close_polygon();
|
||||
} else {
|
||||
// straight line from last to first control point
|
||||
path.line_to(points[0].point.x,
|
||||
points[0].point.y);
|
||||
path.close_polygon();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// constructor
|
||||
VectorPath::VectorPath()
|
||||
: BArchivable(),
|
||||
fPath(NULL),
|
||||
fClosed(false),
|
||||
fPointCount(0),
|
||||
fAllocCount(0),
|
||||
fCachedBounds(0.0, 0.0, -1.0, -1.0)
|
||||
{
|
||||
}
|
||||
|
||||
// constructor
|
||||
VectorPath::VectorPath(const VectorPath& from)
|
||||
: BArchivable(),
|
||||
Observable(),
|
||||
fPath(NULL),
|
||||
fPointCount(0),
|
||||
fAllocCount(0),
|
||||
fCachedBounds(0.0, 0.0, -1.0, -1.0)
|
||||
{
|
||||
*this = from;
|
||||
}
|
||||
|
||||
// constructor
|
||||
VectorPath::VectorPath(const BMessage* archive)
|
||||
: BArchivable(),
|
||||
Observable(),
|
||||
fPath(NULL),
|
||||
fClosed(false),
|
||||
fPointCount(0),
|
||||
fAllocCount(0),
|
||||
fCachedBounds(0.0, 0.0, -1.0, -1.0)
|
||||
{
|
||||
if (archive) {
|
||||
type_code typeFound;
|
||||
int32 countFound;
|
||||
if (archive->GetInfo("point", &typeFound, &countFound) >= B_OK
|
||||
&& typeFound == B_POINT_TYPE && _SetPointCount(countFound)) {
|
||||
memset(fPath, 0, fAllocCount * sizeof(control_point));
|
||||
BPoint point;
|
||||
BPoint pointIn;
|
||||
BPoint pointOut;
|
||||
bool connected;
|
||||
for (int32 i = 0; i < fPointCount
|
||||
&& archive->FindPoint("point", i, &point) >= B_OK
|
||||
&& archive->FindPoint("point in", i, &pointIn) >= B_OK
|
||||
&& archive->FindPoint("point out", i, &pointOut) >= B_OK
|
||||
&& archive->FindBool("connected", i, &connected) >= B_OK; i++) {
|
||||
fPath[i].point = point;
|
||||
fPath[i].point_in = pointIn;
|
||||
fPath[i].point_out = pointOut;
|
||||
fPath[i].connected = connected;
|
||||
}
|
||||
}
|
||||
if (archive->FindBool("path closed", &fClosed) < B_OK) {
|
||||
fClosed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
VectorPath::~VectorPath()
|
||||
{
|
||||
if (fPath)
|
||||
obj_free(fPath);
|
||||
}
|
||||
|
||||
// operator=
|
||||
VectorPath&
|
||||
VectorPath::operator=(const VectorPath& from)
|
||||
{
|
||||
_SetPointCount(from.fPointCount);
|
||||
fClosed = from.fClosed;
|
||||
if (fPath) {
|
||||
memcpy(fPath, from.fPath, fPointCount * sizeof(control_point));
|
||||
fCachedBounds = from.fCachedBounds;
|
||||
} else {
|
||||
fprintf(stderr, "VectorPath() -> allocation failed in operator=!\n");
|
||||
fAllocCount = 0;
|
||||
fPointCount = 0;
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// MakeEmpty
|
||||
void
|
||||
VectorPath::MakeEmpty()
|
||||
{
|
||||
_SetPointCount(0);
|
||||
}
|
||||
|
||||
// Archive
|
||||
status_t
|
||||
VectorPath::Archive(BMessage* into, bool deep) const
|
||||
{
|
||||
status_t ret = BArchivable::Archive(into, deep);
|
||||
if (ret >= B_OK) {
|
||||
if (fPointCount > 0) {
|
||||
// improve BMessage efficency by preallocating storage for all points
|
||||
// with the first call
|
||||
ret = into->AddData("point", B_POINT_TYPE, &fPath[0].point,
|
||||
sizeof(BPoint), true, fPointCount);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("point in", B_POINT_TYPE, &fPath[0].point_in,
|
||||
sizeof(BPoint), true, fPointCount);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("point out", B_POINT_TYPE, &fPath[0].point_out,
|
||||
sizeof(BPoint), true, fPointCount);
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("connected", B_BOOL_TYPE, &fPath[0].connected,
|
||||
sizeof(bool), true, fPointCount);
|
||||
// add the rest of the points
|
||||
for (int32 i = 1; i < fPointCount && ret >= B_OK; i++) {
|
||||
ret = into->AddData("point", B_POINT_TYPE, &fPath[i].point, sizeof(BPoint));
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("point in", B_POINT_TYPE, &fPath[i].point_in, sizeof(BPoint));
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("point out", B_POINT_TYPE, &fPath[i].point_out, sizeof(BPoint));
|
||||
if (ret >= B_OK)
|
||||
ret = into->AddData("connected", B_BOOL_TYPE, &fPath[i].connected, sizeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret >= B_OK) {
|
||||
ret = into->AddBool("path closed", fClosed);
|
||||
} else {
|
||||
fprintf(stderr, "failed adding points!\n");
|
||||
}
|
||||
if (ret < B_OK) {
|
||||
fprintf(stderr, "failed adding closed!\n");
|
||||
}
|
||||
// finish off
|
||||
if (ret < B_OK) {
|
||||
ret = into->AddString("class", "VectorPath");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// AddPoint
|
||||
bool
|
||||
VectorPath::AddPoint(BPoint point)
|
||||
{
|
||||
int32 index = fPointCount;
|
||||
|
||||
if (_SetPointCount(fPointCount + 1)) {
|
||||
_SetPoint(index, point);
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// AddPoint
|
||||
bool
|
||||
VectorPath::AddPoint(BPoint point, int32 index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index > fPointCount)
|
||||
index = fPointCount;
|
||||
|
||||
if (_SetPointCount(fPointCount + 1)) {
|
||||
// handle insert
|
||||
if (index < fPointCount - 1) {
|
||||
for (int32 i = fPointCount; i > index; i--) {
|
||||
fPath[i].point = fPath[i - 1].point;
|
||||
fPath[i].point_in = fPath[i - 1].point_in;
|
||||
fPath[i].point_out = fPath[i - 1].point_out;
|
||||
fPath[i].connected = fPath[i - 1].connected;
|
||||
}
|
||||
}
|
||||
_SetPoint(index, point);
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// RemovePoint
|
||||
bool
|
||||
VectorPath::RemovePoint(int32 index)
|
||||
{
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
|
||||
if (index < fPointCount - 1) {
|
||||
// move points
|
||||
for (int32 i = index; i < fPointCount - 1; i++) {
|
||||
fPath[i].point = fPath[i + 1].point;
|
||||
fPath[i].point_in = fPath[i + 1].point_in;
|
||||
fPath[i].point_out = fPath[i + 1].point_out;
|
||||
fPath[i].connected = fPath[i + 1].connected;
|
||||
}
|
||||
}
|
||||
fPointCount -= 1;
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetPoint
|
||||
bool
|
||||
VectorPath::SetPoint(int32 index, BPoint point)
|
||||
{
|
||||
if (index == fPointCount)
|
||||
index = 0;
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
BPoint offset = point - fPath[index].point;
|
||||
fPath[index].point = point;
|
||||
fPath[index].point_in += offset;
|
||||
fPath[index].point_out += offset;
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetPoint
|
||||
bool
|
||||
VectorPath::SetPoint(int32 index, BPoint point,
|
||||
BPoint pointIn, BPoint pointOut,
|
||||
bool connected)
|
||||
{
|
||||
if (index == fPointCount)
|
||||
index = 0;
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
fPath[index].point = point;
|
||||
fPath[index].point_in = pointIn;
|
||||
fPath[index].point_out = pointOut;
|
||||
fPath[index].connected = connected;
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetPointIn
|
||||
bool
|
||||
VectorPath::SetPointIn(int32 i, BPoint point)
|
||||
{
|
||||
if (i == fPointCount)
|
||||
i = 0;
|
||||
if (i >= 0 && i < fPointCount) {
|
||||
// first, set the "in" point
|
||||
fPath[i].point_in = point;
|
||||
// now see what to do about the "out" point
|
||||
if (fPath[i].connected) {
|
||||
// keep all three points in one line
|
||||
BPoint v = fPath[i].point - fPath[i].point_in;
|
||||
float distIn = sqrtf(v.x * v.x + v.y * v.y);
|
||||
if (distIn > 0.0) {
|
||||
float distOut = point_point_distance(fPath[i].point, fPath[i].point_out);
|
||||
float scale = (distIn + distOut) / distIn;
|
||||
v.x *= scale;
|
||||
v.y *= scale;
|
||||
fPath[i].point_out = fPath[i].point_in + v;
|
||||
}
|
||||
}
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetPointOut
|
||||
bool
|
||||
VectorPath::SetPointOut(int32 i, BPoint point, bool mirrorDist)
|
||||
{
|
||||
if (i == fPointCount)
|
||||
i = 0;
|
||||
if (i >= 0 && i < fPointCount) {
|
||||
// first, set the "out" point
|
||||
fPath[i].point_out = point;
|
||||
// now see what to do about the "out" point
|
||||
if (mirrorDist) {
|
||||
// mirror "in" point around main control point
|
||||
BPoint v = fPath[i].point - fPath[i].point_out;
|
||||
fPath[i].point_in = fPath[i].point + v;
|
||||
} else if (fPath[i].connected) {
|
||||
// keep all three points in one line
|
||||
BPoint v = fPath[i].point - fPath[i].point_out;
|
||||
float distOut = sqrtf(v.x * v.x + v.y * v.y);
|
||||
if (distOut > 0.0) {
|
||||
float distIn = point_point_distance(fPath[i].point, fPath[i].point_in);
|
||||
float scale = (distIn + distOut) / distOut;
|
||||
v.x *= scale;
|
||||
v.y *= scale;
|
||||
fPath[i].point_in = fPath[i].point_out + v;
|
||||
}
|
||||
}
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetInOutConnected
|
||||
bool
|
||||
VectorPath::SetInOutConnected(int32 index, bool connected)
|
||||
{
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
fPath[index].connected = connected;
|
||||
Notify();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetPointAt
|
||||
bool
|
||||
VectorPath::GetPointAt(int32 index, BPoint& point) const
|
||||
{
|
||||
if (index == fPointCount)
|
||||
index = 0;
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
point = fPath[index].point;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetPointInAt
|
||||
bool
|
||||
VectorPath::GetPointInAt(int32 index, BPoint& point) const
|
||||
{
|
||||
if (index == fPointCount)
|
||||
index = 0;
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
point = fPath[index].point_in;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetPointOutAt
|
||||
bool
|
||||
VectorPath::GetPointOutAt(int32 index, BPoint& point) const
|
||||
{
|
||||
if (index == fPointCount)
|
||||
index = 0;
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
point = fPath[index].point_out;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetPointsAt
|
||||
bool
|
||||
VectorPath::GetPointsAt(int32 index, BPoint& point,
|
||||
BPoint& pointIn, BPoint& pointOut, bool* connected) const
|
||||
{
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
point = fPath[index].point;
|
||||
pointIn = fPath[index].point_in;
|
||||
pointOut = fPath[index].point_out;
|
||||
|
||||
if (connected)
|
||||
*connected = fPath[index].connected;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// CountPoints
|
||||
int32
|
||||
VectorPath::CountPoints() const
|
||||
{
|
||||
return fPointCount;
|
||||
}
|
||||
|
||||
// distance_to_curve
|
||||
static float
|
||||
distance_to_curve(const BPoint& p, const BPoint& a, const BPoint& aOut, const BPoint& bIn, const BPoint& b)
|
||||
{
|
||||
agg::curve4 curve(a.x, a.y, aOut.x, aOut.y,
|
||||
bIn.x, bIn.y, b.x, b.y);
|
||||
|
||||
float segDist = FLT_MAX;
|
||||
double x1, y1, x2, y2;
|
||||
unsigned cmd = curve.vertex(&x1, &y1);
|
||||
while (!agg::is_stop(cmd)) {
|
||||
cmd = curve.vertex(&x2, &y2);
|
||||
// first figure out if point is between segment start and end points
|
||||
double a = agg::calc_distance(p.x, p.y, x2, y2);
|
||||
double b = agg::calc_distance(p.x, p.y, x1, y1);
|
||||
|
||||
float currentDist = min_c(a, b);
|
||||
|
||||
if (a > 0.0 && b > 0.0) {
|
||||
double c = agg::calc_distance(x1, y1, x2, y2);
|
||||
|
||||
double alpha = acos((b*b + c*c - a*a) / (2*b*c));
|
||||
double beta = acos((a*a + c*c - b*b) / (2*a*c));
|
||||
|
||||
if (alpha <= PI2 && beta <= PI2) {
|
||||
currentDist = fabs(point_line_distance(x1, y1, x2, y2, p.x, p.y));
|
||||
}
|
||||
}
|
||||
|
||||
if (currentDist < segDist) {
|
||||
segDist = currentDist;
|
||||
}
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
return segDist;
|
||||
}
|
||||
|
||||
// GetDistance
|
||||
bool
|
||||
VectorPath::GetDistance(BPoint p, float* distance, int32* index) const
|
||||
{
|
||||
if (fPointCount > 1) {
|
||||
// generate a curve for each segment of the path
|
||||
// then iterate over the segments of the curve measuring the distance
|
||||
*distance = FLT_MAX;
|
||||
|
||||
for (int32 i = 0; i < fPointCount - 1; i++) {
|
||||
float segDist = distance_to_curve(p,
|
||||
fPath[i].point,
|
||||
fPath[i].point_out,
|
||||
fPath[i + 1].point_in,
|
||||
fPath[i + 1].point);
|
||||
if (segDist < *distance) {
|
||||
*distance = segDist;
|
||||
*index = i + 1;
|
||||
}
|
||||
}
|
||||
if (fClosed) {
|
||||
float segDist = distance_to_curve(p,
|
||||
fPath[fPointCount - 1].point,
|
||||
fPath[fPointCount - 1].point_out,
|
||||
fPath[0].point_in,
|
||||
fPath[0].point);
|
||||
if (segDist < *distance) {
|
||||
*distance = segDist;
|
||||
*index = fPointCount;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// FindBezierScale
|
||||
bool
|
||||
VectorPath::FindBezierScale(int32 index, BPoint point, double* scale) const
|
||||
{
|
||||
if (index >= 0 && index < fPointCount && scale) {
|
||||
|
||||
int maxStep = 1000;
|
||||
|
||||
double t = 0.0;
|
||||
double dt = 1.0 / maxStep;
|
||||
|
||||
*scale = 0.0;
|
||||
double min = FLT_MAX;
|
||||
|
||||
BPoint curvePoint;
|
||||
for (int step = 1; step < maxStep; step++) {
|
||||
t += dt;
|
||||
|
||||
GetPoint(index, t, curvePoint);
|
||||
double d = point_point_distance(curvePoint, point);
|
||||
|
||||
if (d < min) {
|
||||
min = d;
|
||||
*scale = t;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetPoint
|
||||
bool
|
||||
VectorPath::GetPoint(int32 index, double t, BPoint& point) const
|
||||
{
|
||||
if (index >= 0 && index < fPointCount) {
|
||||
|
||||
double t1 = (1 - t) * (1 - t) * (1 - t);
|
||||
double t2 = (1 - t) * (1 - t) * t * 3;
|
||||
double t3 = (1 - t) * t * t * 3;
|
||||
double t4 = t * t * t;
|
||||
|
||||
if (index < fPointCount - 1) {
|
||||
point.x = fPath[index].point.x * t1 +
|
||||
fPath[index].point_out.x * t2 +
|
||||
fPath[index + 1].point_in.x * t3 +
|
||||
fPath[index + 1].point.x * t4;
|
||||
|
||||
point.y = fPath[index].point.y * t1 +
|
||||
fPath[index].point_out.y * t2 +
|
||||
fPath[index + 1].point_in.y * t3 +
|
||||
fPath[index + 1].point.y * t4;
|
||||
} else if (fClosed) {
|
||||
point.x = fPath[fPointCount - 1].point.x * t1 +
|
||||
fPath[fPointCount - 1].point_out.x * t2 +
|
||||
fPath[0].point_in.x * t3 +
|
||||
fPath[0].point.x * t4;
|
||||
|
||||
point.y = fPath[fPointCount - 1].point.y * t1 +
|
||||
fPath[fPointCount - 1].point_out.y * t2 +
|
||||
fPath[0].point_in.y * t3 +
|
||||
fPath[0].point.y * t4;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// SetClosed
|
||||
void
|
||||
VectorPath::SetClosed(bool closed)
|
||||
{
|
||||
if (fClosed != closed) {
|
||||
fClosed = closed;
|
||||
Notify();
|
||||
}
|
||||
}
|
||||
|
||||
// Bounds
|
||||
BRect
|
||||
VectorPath::Bounds() const
|
||||
{
|
||||
// the bounds of the actual curves, not the control points!
|
||||
if (!fCachedBounds.IsValid())
|
||||
fCachedBounds = _Bounds();
|
||||
return fCachedBounds;
|
||||
}
|
||||
|
||||
// Bounds
|
||||
BRect
|
||||
VectorPath::_Bounds() const
|
||||
{
|
||||
agg::path_storage path;
|
||||
|
||||
BRect b;
|
||||
if (get_path_storage(path, fPath, fPointCount, fClosed)) {
|
||||
|
||||
agg::conv_curve<agg::path_storage> curve(path);
|
||||
|
||||
uint32 pathID[1];
|
||||
pathID[0] = 0;
|
||||
double left, top, right, bottom;
|
||||
|
||||
agg::bounding_rect(curve, pathID, 0, 1, &left, &top, &right, &bottom);
|
||||
|
||||
b.Set(left, top, right, bottom);
|
||||
} else if (fPointCount == 1) {
|
||||
b.Set(fPath[0].point.x, fPath[0].point.y, fPath[0].point.x, fPath[0].point.y);
|
||||
} else {
|
||||
b.Set(0.0, 0.0, -1.0, -1.0);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// ControlPointBounds
|
||||
BRect
|
||||
VectorPath::ControlPointBounds() const
|
||||
{
|
||||
if (fPointCount > 0) {
|
||||
BRect r(fPath[0].point, fPath[0].point);
|
||||
for (int32 i = 0; i < fPointCount; i++) {
|
||||
// include point
|
||||
r.left = min_c(r.left, fPath[i].point.x);
|
||||
r.top = min_c(r.top, fPath[i].point.y);
|
||||
r.right = max_c(r.right, fPath[i].point.x);
|
||||
r.bottom = max_c(r.bottom, fPath[i].point.y);
|
||||
// include "in" point
|
||||
r.left = min_c(r.left, fPath[i].point_in.x);
|
||||
r.top = min_c(r.top, fPath[i].point_in.y);
|
||||
r.right = max_c(r.right, fPath[i].point_in.x);
|
||||
r.bottom = max_c(r.bottom, fPath[i].point_in.y);
|
||||
// include "out" point
|
||||
r.left = min_c(r.left, fPath[i].point_out.x);
|
||||
r.top = min_c(r.top, fPath[i].point_out.y);
|
||||
r.right = max_c(r.right, fPath[i].point_out.x);
|
||||
r.bottom = max_c(r.bottom, fPath[i].point_out.y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return BRect(0.0, 0.0, -1.0, -1.0);
|
||||
}
|
||||
|
||||
// Iterate
|
||||
void
|
||||
VectorPath::Iterate(Iterator* iterator, float smoothScale) const
|
||||
{
|
||||
if (fPointCount > 1) {
|
||||
// generate a curve for each segment of the path
|
||||
// then iterate over the segments of the curve
|
||||
// agg::curve4_inc curve;
|
||||
agg::curve4 curve;
|
||||
|
||||
for (int32 i = 0; i < fPointCount - 1; i++) {
|
||||
iterator->MoveTo(fPath[i].point);
|
||||
curve.init(fPath[i].point.x, fPath[i].point.y,
|
||||
fPath[i].point_out.x, fPath[i].point_out.y,
|
||||
fPath[i + 1].point_in.x, fPath[i + 1].point_in.y,
|
||||
fPath[i + 1].point.x, fPath[i + 1].point.y);
|
||||
|
||||
double x, y;
|
||||
unsigned cmd = curve.vertex(&x, &y);
|
||||
while (!agg::is_stop(cmd)) {
|
||||
BPoint p(x, y);
|
||||
iterator->LineTo(p);
|
||||
cmd = curve.vertex(&x, &y);
|
||||
}
|
||||
}
|
||||
if (fClosed) {
|
||||
iterator->MoveTo(fPath[fPointCount - 1].point);
|
||||
curve.init(fPath[fPointCount - 1].point.x, fPath[fPointCount - 1].point.y,
|
||||
fPath[fPointCount - 1].point_out.x, fPath[fPointCount - 1].point_out.y,
|
||||
fPath[0].point_in.x, fPath[0].point_in.y,
|
||||
fPath[0].point.x, fPath[0].point.y);
|
||||
|
||||
double x, y;
|
||||
unsigned cmd = curve.vertex(&x, &y);
|
||||
while (!agg::is_stop(cmd)) {
|
||||
BPoint p(x, y);
|
||||
iterator->LineTo(p);
|
||||
cmd = curve.vertex(&x, &y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CleanUp
|
||||
void
|
||||
VectorPath::CleanUp()
|
||||
{
|
||||
if (fPointCount == 0)
|
||||
return;
|
||||
|
||||
bool notify = false;
|
||||
|
||||
// remove last point if it is coincident with the first
|
||||
if (fClosed && fPointCount >= 1) {
|
||||
if (fPath[0].point == fPath[fPointCount - 1].point) {
|
||||
fPath[0].point_in = fPath[fPointCount - 1].point_in;
|
||||
_SetPointCount(fPointCount - 1);
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < fPointCount; i++) {
|
||||
// check for unnecessary, duplicate points
|
||||
if (i > 0) {
|
||||
if (fPath[i - 1].point == fPath[i].point &&
|
||||
fPath[i - 1].point == fPath[i - 1].point_out &&
|
||||
fPath[i].point == fPath[i].point_in) {
|
||||
// the previous point can be removed
|
||||
BPoint in = fPath[i - 1].point_in;
|
||||
if (RemovePoint(i - 1)) {
|
||||
i--;
|
||||
fPath[i].point_in = in;
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// re-establish connections of in-out control points if
|
||||
// they line up with the main control point
|
||||
if (fPath[i].point_in == fPath[i].point_out ||
|
||||
fPath[i].point == fPath[i].point_out ||
|
||||
fPath[i].point == fPath[i].point_in ||
|
||||
(fabs(point_line_distance(fPath[i].point_in.x, fPath[i].point_in.y,
|
||||
fPath[i].point.x, fPath[i].point.y,
|
||||
fPath[i].point_out.x, fPath[i].point_out.y)) < 0.01 &&
|
||||
fabs(point_line_distance(fPath[i].point_out.x, fPath[i].point_out.y,
|
||||
fPath[i].point.x, fPath[i].point.y,
|
||||
fPath[i].point_in.x, fPath[i].point_in.y)) < 0.01)) {
|
||||
|
||||
fPath[i].connected = true;
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
Notify();
|
||||
}
|
||||
|
||||
// Reverse
|
||||
void
|
||||
VectorPath::Reverse()
|
||||
{
|
||||
VectorPath temp(*this);
|
||||
int32 index = 0;
|
||||
for (int32 i = fPointCount - 1; i >= 0; i--) {
|
||||
temp.SetPoint(index, fPath[i].point,
|
||||
fPath[i].point_out,
|
||||
fPath[i].point_in,
|
||||
fPath[i].connected);
|
||||
index++;
|
||||
}
|
||||
*this = temp;
|
||||
|
||||
Notify();
|
||||
}
|
||||
|
||||
// PrintToStream
|
||||
void
|
||||
VectorPath::PrintToStream() const
|
||||
{
|
||||
for (int32 i = 0; i < fPointCount; i++) {
|
||||
printf("point %ld: (%f, %f) -> (%f, %f) -> (%f, %f) (%d)\n", i,
|
||||
fPath[i].point_in.x, fPath[i].point_in.y,
|
||||
fPath[i].point.x, fPath[i].point.y,
|
||||
fPath[i].point_out.x, fPath[i].point_out.y,
|
||||
fPath[i].connected);
|
||||
}
|
||||
}
|
||||
|
||||
// GetAGGPathStorage
|
||||
bool
|
||||
VectorPath::GetAGGPathStorage(agg::path_storage& path) const
|
||||
{
|
||||
return get_path_storage(path, fPath, fPointCount, fClosed);
|
||||
}
|
||||
|
||||
// _SetPoint
|
||||
void
|
||||
VectorPath::_SetPoint(int32 index, BPoint point)
|
||||
{
|
||||
fPath[index].point = point;
|
||||
fPath[index].point_in = point;
|
||||
fPath[index].point_out = point;
|
||||
|
||||
fPath[index].connected = true;
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
}
|
||||
|
||||
// _SetPointCount
|
||||
bool
|
||||
VectorPath::_SetPointCount(int32 count)
|
||||
{
|
||||
// handle reallocation if we run out of room
|
||||
if (count >= fAllocCount) {
|
||||
fAllocCount = ((count) / ALLOC_CHUNKS + 1) * ALLOC_CHUNKS;
|
||||
if (fPath) {
|
||||
fPath = obj_renew(fPath, control_point, fAllocCount);
|
||||
} else {
|
||||
fPath = obj_new(control_point, fAllocCount);
|
||||
}
|
||||
memset(fPath + fPointCount, 0, (fAllocCount - fPointCount) * sizeof(control_point));
|
||||
}
|
||||
// update point count
|
||||
if (fPath) {
|
||||
fPointCount = count;
|
||||
} else {
|
||||
// reallocation might have failed
|
||||
fPointCount = 0;
|
||||
fAllocCount = 0;
|
||||
fprintf(stderr, "VectorPath::_SetPointCount(%ld) - allocation failed!\n", count);
|
||||
}
|
||||
|
||||
fCachedBounds.Set(0.0, 0.0, -1.0, -1.0);
|
||||
|
||||
return fPath != NULL;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef VECTOR_PATH_H
|
||||
#define VECTOR_PATH_H
|
||||
|
||||
#include <Archivable.h>
|
||||
#include <Rect.h>
|
||||
|
||||
#include <agg_path_storage.h>
|
||||
|
||||
#include "Observable.h"
|
||||
|
||||
class BBitmap;
|
||||
class BMessage;
|
||||
class BView;
|
||||
|
||||
struct control_point {
|
||||
BPoint point; // actual point on path
|
||||
BPoint point_in; // control point for incomming curve
|
||||
BPoint point_out; // control point for outgoing curve
|
||||
bool connected; // if all 3 points should be on one line
|
||||
};
|
||||
|
||||
class VectorPath : public BArchivable,
|
||||
public Observable {
|
||||
public:
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator() {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual void MoveTo(BPoint point) = 0;
|
||||
virtual void LineTo(BPoint point) = 0;
|
||||
};
|
||||
|
||||
VectorPath();
|
||||
VectorPath(const VectorPath& from);
|
||||
VectorPath(const BMessage* archive);
|
||||
virtual ~VectorPath();
|
||||
|
||||
VectorPath& operator=(const VectorPath& from);
|
||||
// bool operator==(const VectorPath& frrom) const;
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
// the BArchivable protocoll
|
||||
status_t Archive(BMessage* into, bool deep = true) const;
|
||||
|
||||
bool AddPoint(BPoint point);
|
||||
bool AddPoint(BPoint point, int32 index);
|
||||
|
||||
bool RemovePoint(int32 index);
|
||||
|
||||
// modify existing points position
|
||||
bool SetPoint(int32 index, BPoint point);
|
||||
bool SetPoint(int32 index, BPoint point,
|
||||
BPoint pointIn,
|
||||
BPoint pointOut,
|
||||
bool connected);
|
||||
bool SetPointIn(int32 index, BPoint point);
|
||||
bool SetPointOut(int32 index, BPoint point,
|
||||
bool mirrorDist = false);
|
||||
|
||||
bool SetInOutConnected(int32 index, bool connected);
|
||||
|
||||
// query existing points position
|
||||
bool GetPointAt(int32 index, BPoint& point) const;
|
||||
bool GetPointInAt(int32 index, BPoint& point) const;
|
||||
bool GetPointOutAt(int32 index, BPoint& point) const;
|
||||
bool GetPointsAt(int32 index,
|
||||
BPoint& point,
|
||||
BPoint& pointIn,
|
||||
BPoint& pointOut,
|
||||
bool* connected = NULL) const;
|
||||
|
||||
int32 CountPoints() const;
|
||||
|
||||
// iterates over curve segments and returns
|
||||
// the distance and index of the point that
|
||||
// started the segment that is closest
|
||||
bool GetDistance(BPoint point,
|
||||
float* distance, int32* index) const;
|
||||
|
||||
// at curve segment indicated by "index", this
|
||||
// function looks for the closest point
|
||||
// directly on the curve and returns a "scale"
|
||||
// that indicates the distance on the curve
|
||||
// between [0..1]
|
||||
bool FindBezierScale(int32 index, BPoint point,
|
||||
double* scale) const;
|
||||
// this function can be used to get a point
|
||||
// directly on the segment indicated by "index"
|
||||
// "scale" is on [0..1] indicating the distance
|
||||
// from the start of the segment to the end
|
||||
bool GetPoint(int32 index, double scale,
|
||||
BPoint& point) const;
|
||||
|
||||
void SetClosed(bool closed);
|
||||
bool IsClosed() const
|
||||
{ return fClosed; }
|
||||
|
||||
BRect Bounds() const;
|
||||
BRect ControlPointBounds() const;
|
||||
|
||||
void Iterate(Iterator* iterator,
|
||||
float smoothScale = 1.0) const;
|
||||
|
||||
void CleanUp();
|
||||
void Reverse();
|
||||
|
||||
void PrintToStream() const;
|
||||
|
||||
bool GetAGGPathStorage(agg::path_storage& path) const;
|
||||
|
||||
private:
|
||||
BRect _Bounds() const;
|
||||
void _SetPoint(int32 index, BPoint point);
|
||||
bool _SetPointCount(int32 count);
|
||||
|
||||
control_point* fPath;
|
||||
|
||||
bool fClosed;
|
||||
|
||||
int32 fPointCount;
|
||||
int32 fAllocCount;
|
||||
|
||||
mutable BRect fCachedBounds;
|
||||
};
|
||||
|
||||
#endif // VECTOR_PATH_H
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "AddPointCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "VectorPath.h"
|
||||
|
||||
// constructor
|
||||
AddPointCommand::AddPointCommand(VectorPath* path,
|
||||
int32 index,
|
||||
const int32* selected,
|
||||
int32 count)
|
||||
: PathCommand(path),
|
||||
fIndex(index),
|
||||
fOldSelection(NULL),
|
||||
fOldSelectionCount(count)
|
||||
{
|
||||
if (fOldSelectionCount > 0 && selected) {
|
||||
fOldSelection = new int32[fOldSelectionCount];
|
||||
memcpy(fOldSelection, selected, fOldSelectionCount * sizeof(int32));
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
AddPointCommand::~AddPointCommand()
|
||||
{
|
||||
delete[] fOldSelection;
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
AddPointCommand::Perform()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// path point is already added,
|
||||
// but we don't know the parameters yet
|
||||
if (!fPath->GetPointsAt(fIndex, fPoint, fPointIn, fPointOut))
|
||||
status = B_NO_INIT;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
AddPointCommand::Undo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// remove point
|
||||
if (fPath->RemovePoint(fIndex)) {
|
||||
// restore selection before adding point
|
||||
_Select(fOldSelection, fOldSelectionCount);
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
AddPointCommand::Redo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
AutoNotificationSuspender _(fPath);
|
||||
|
||||
// add point again
|
||||
if (fPath->AddPoint(fPoint, fIndex)) {
|
||||
fPath->SetPoint(fIndex, fPoint, fPointIn, fPointOut, true);
|
||||
// select added point
|
||||
_Select(&fIndex, 1);
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// GetName
|
||||
void
|
||||
AddPointCommand::GetName(BString& name)
|
||||
{
|
||||
// name << _GetString(ADD_CONTROL_POINT, "Add Control Point");
|
||||
name << "Add Control Point";
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef ADD_POINT_COMMAND_H
|
||||
#define ADD_POINT_COMMAND_H
|
||||
|
||||
#include <Point.h>
|
||||
|
||||
#include "PathCommand.h"
|
||||
|
||||
class AddPointCommand : public PathCommand {
|
||||
public:
|
||||
AddPointCommand(VectorPath* path,
|
||||
int32 index,
|
||||
const int32* selected,
|
||||
int32 count);
|
||||
virtual ~AddPointCommand();
|
||||
|
||||
virtual status_t Perform();
|
||||
virtual status_t Undo();
|
||||
virtual status_t Redo();
|
||||
|
||||
virtual void GetName(BString& name);
|
||||
|
||||
private:
|
||||
int32 fIndex;
|
||||
BPoint fPoint;
|
||||
BPoint fPointIn;
|
||||
BPoint fPointOut;
|
||||
|
||||
int32* fOldSelection;
|
||||
int32 fOldSelectionCount;
|
||||
};
|
||||
|
||||
#endif // ADD_POINT_COMMAND_H
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "ChangePointCommand.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "VectorPath.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
ChangePointCommand::ChangePointCommand(VectorPath* path,
|
||||
int32 index,
|
||||
const int32* selected,
|
||||
int32 count)
|
||||
: PathCommand(path),
|
||||
fIndex(index),
|
||||
fOldSelection(NULL),
|
||||
fOldSelectionCount(count)
|
||||
{
|
||||
if (fPath && !fPath->GetPointsAt(fIndex, fPoint, fPointIn, fPointOut, &fConnected))
|
||||
fPath = NULL;
|
||||
if (fOldSelectionCount > 0 && selected) {
|
||||
fOldSelection = new (nothrow) int32[fOldSelectionCount];
|
||||
memcpy(fOldSelection, selected, fOldSelectionCount * sizeof(int32));
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
ChangePointCommand::~ChangePointCommand()
|
||||
{
|
||||
delete[] fOldSelection;
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
ChangePointCommand::Perform()
|
||||
{
|
||||
// path point is already changed
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
ChangePointCommand::Undo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// set the point to the remembered state and
|
||||
// save the previous state of the point
|
||||
BPoint point;
|
||||
BPoint pointIn;
|
||||
BPoint pointOut;
|
||||
bool connected;
|
||||
if (fPath->GetPointsAt(fIndex, point, pointIn, pointOut, &connected)
|
||||
&& fPath->SetPoint(fIndex, fPoint, fPointIn, fPointOut, fConnected)) {
|
||||
// toggle the remembered settings
|
||||
fPoint = point;
|
||||
fPointIn = pointIn;
|
||||
fPointOut = pointOut;
|
||||
fConnected = connected;
|
||||
// restore old selection
|
||||
_Select(fOldSelection, fOldSelectionCount);
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
ChangePointCommand::Redo()
|
||||
{
|
||||
status_t status = Undo();
|
||||
if (status >= B_OK)
|
||||
_Select(&fIndex, 1);
|
||||
return status;
|
||||
}
|
||||
|
||||
// GetName
|
||||
void
|
||||
ChangePointCommand::GetName(BString& name)
|
||||
{
|
||||
// name << _GetString(MODIFY_CONTROL_POINT, "Modify Control Point");
|
||||
name << "Modify Control Point";
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef CHANGE_POINT_COMMAND_H
|
||||
#define CHANGE_POINT_COMMAND_H
|
||||
|
||||
#include <Point.h>
|
||||
|
||||
#include "PathCommand.h"
|
||||
|
||||
class ChangePointCommand : public PathCommand {
|
||||
public:
|
||||
ChangePointCommand(VectorPath* path,
|
||||
int32 index,
|
||||
const int32* selected,
|
||||
int32 count);
|
||||
virtual ~ChangePointCommand();
|
||||
|
||||
virtual status_t Perform();
|
||||
virtual status_t Undo();
|
||||
virtual status_t Redo();
|
||||
|
||||
virtual void GetName(BString& name);
|
||||
|
||||
private:
|
||||
int32 fIndex;
|
||||
|
||||
BPoint fPoint;
|
||||
BPoint fPointIn;
|
||||
BPoint fPointOut;
|
||||
bool fConnected;
|
||||
|
||||
int32* fOldSelection;
|
||||
int32 fOldSelectionCount;
|
||||
};
|
||||
|
||||
#endif // CHANGE_POINT_COMMAND_H
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#include "InsertPointCommand.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "VectorPath.h"
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
// constructor
|
||||
InsertPointCommand::InsertPointCommand(VectorPath* path,
|
||||
int32 index,
|
||||
const int32* selected,
|
||||
int32 count)
|
||||
: PathCommand(path),
|
||||
fIndex(index),
|
||||
fOldSelection(NULL),
|
||||
fOldSelectionCount(count)
|
||||
{
|
||||
if (fPath && (!fPath->GetPointsAt(fIndex, fPoint, fPointIn, fPointOut)
|
||||
|| !fPath->GetPointOutAt(fIndex - 1, fPreviousOut)
|
||||
|| !fPath->GetPointInAt(fIndex + 1, fNextIn))) {
|
||||
fPath = NULL;
|
||||
}
|
||||
if (fOldSelectionCount > 0 && selected) {
|
||||
fOldSelection = new (nothrow) int32[count];
|
||||
memcpy(fOldSelection, selected, count * sizeof(int32));
|
||||
}
|
||||
}
|
||||
|
||||
// destructor
|
||||
InsertPointCommand::~InsertPointCommand()
|
||||
{
|
||||
delete[] fOldSelection;
|
||||
}
|
||||
|
||||
// Perform
|
||||
status_t
|
||||
InsertPointCommand::Perform()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// path point is already added
|
||||
// but in/out points might still have changed
|
||||
fPath->GetPointInAt(fIndex, fPointIn);
|
||||
fPath->GetPointOutAt(fIndex, fPointOut);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Undo
|
||||
status_t
|
||||
InsertPointCommand::Undo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
AutoNotificationSuspender _(fPath);
|
||||
|
||||
// remove the inserted point
|
||||
if (fPath->RemovePoint(fIndex)) {
|
||||
// remember current previous "out" and restore it
|
||||
BPoint previousOut = fPreviousOut;
|
||||
fPath->GetPointOutAt(fIndex - 1, fPreviousOut);
|
||||
fPath->SetPointOut(fIndex - 1, previousOut);
|
||||
// remember current next "in" and restore it
|
||||
BPoint nextIn = fNextIn;
|
||||
fPath->GetPointInAt(fIndex, fNextIn);
|
||||
fPath->SetPointIn(fIndex, nextIn);
|
||||
// restore previous selection
|
||||
_Select(fOldSelection, fOldSelectionCount);
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Redo
|
||||
status_t
|
||||
InsertPointCommand::Redo()
|
||||
{
|
||||
status_t status = InitCheck();
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
|
||||
AutoNotificationSuspender _(fPath);
|
||||
|
||||
// insert point again
|
||||
if (fPath->AddPoint(fPoint, fIndex)) {
|
||||
fPath->SetPoint(fIndex, fPoint, fPointIn, fPointOut, true);
|
||||
// remember current previous "out" and restore it
|
||||
BPoint previousOut = fPreviousOut;
|
||||
fPath->GetPointOutAt(fIndex - 1, fPreviousOut);
|
||||
fPath->SetPointOut(fIndex - 1, previousOut);
|
||||
// remember current next "in" and restore it
|
||||
BPoint nextIn = fNextIn;
|
||||
fPath->GetPointInAt(fIndex + 1, fNextIn);
|
||||
fPath->SetPointIn(fIndex + 1, nextIn);
|
||||
// select inserted point
|
||||
_Select(&fIndex, 1);
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// GetName
|
||||
void
|
||||
InsertPointCommand::GetName(BString& name)
|
||||
{
|
||||
// name << _GetString(INSERT_CONTROL_POINT, "Insert Control Point");
|
||||
name << "Insert Control Point";
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user