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 expander ;
|
||||||
SubInclude HAIKU_TOP src apps fontdemo ;
|
SubInclude HAIKU_TOP src apps fontdemo ;
|
||||||
SubInclude HAIKU_TOP src apps glteapot ;
|
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 installer ;
|
||||||
SubInclude HAIKU_TOP src apps magnify ;
|
SubInclude HAIKU_TOP src apps magnify ;
|
||||||
SubInclude HAIKU_TOP src apps mediaplayer ;
|
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 <superstippi@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <superstippi@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <superstippi@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <superstippi@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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