⛏️ index : haiku.git

/*
 * Copyright (c) 1999-2000, Eric Moon.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions, and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


// ValControl.h
// +++++ cortex integration 23aug99:
//       - way too many protected members
//       - config'able font
//       - implement GetPreferredSize() (should work before the view is attached
//         to a window -- doable?)
//       - keyboard entry (pop-up text field)
//       - 'spin' mode: value changes based on vertical distance of pointer
//         (configurable; set buttons/modifiers to activate either mode?)
//
//       - should parameter binding happen at this level?
//       +++++ how about a ValControlFactory?  give it a BParameter, get back a
//             ValControl subclass... +++++
//
// e.moon 16jan99
//
// ABSTRACT CLASS: ValControl
// An abstract base class for 'value controls' -- interface
// components that display a value that may be modified via
// click-drag.  Other editing methods (such as 'click, then
// type') may be supported by subclasses.
//
// IMPLEMENT
//   getValue() and setValue(), for raw (BParameter-style) value access
//   MessageReceived(), to handle:
//     M_SET_VALUE
//     M_GET_VALUE
//     M_OFFSET_VALUE		(May be sent by segments during mouse action,
//                       +++++ is a faster method needed?)
//
// NOTES
// The control view consists of:
//
// - One or more segments.  Each segment is individually
//   draggable.  Subclasses may mix segment types, or Add
//   and remove segments dynamically.
//
// - A manipulator region, to which subcontrols (such as 'spin
//   arrows') may be added.
//
// Views/segments may be aligned flush left or flush right.  The
// side towards which views are aligned may be referred to as
// the 'anchor' side.
//
// Quickie interface guidelines:
//
// - Value controls are always underlined, indicating that the
//   value is editable.  (+++++ possible extension: dotted-underline
//   for continuous variation, and solid for discrete/step variation)
//
// - When a value control's 'click action' is to pop down a menu of
//   available choices (or pop up any sort of non-typable display)
//   this should be indicated by a small right triangle in the
//   manipulator area.
//   +++++ this may need some clarification; pop-down sliders, for example?
//
// * HISTORY
//   e.moon		19sep99		Cleanup
//   e.moon		23aug99		begun Cortex integration
//   e.moon		17jan99		started
#ifndef VAL_CONTROL_H
#define VAL_CONTROL_H


#include "cortex_defs.h"

#include "ValCtrlLayoutEntry.h"

#include <Bitmap.h>
#include <Control.h>
#include <Font.h>
#include <Message.h>
#include <View.h>

#include <vector>

__BEGIN_CORTEX_NAMESPACE

class ValControlSegment;


/* abstract */
class ValControl : public BControl {
	public:
		typedef BControl _Inherited;

	public:													// types & constants
		// child-view alignment options:
		enum align_mode {
			ALIGN_FLUSH_LEFT,
			ALIGN_FLUSH_RIGHT
		};
	
		// alignment flags +++++ 23aug99: not implemented -- should they be?
		enum align_flags {
			ALIGN_NONE = 0,
			ALIGN_GROW = 1
		};
	
		// should value update messages be sent asynchronously (during
		// a mouse operation) or synchronously (after the mouse is
		// released)?
		enum update_mode {
			UPDATE_ASYNC,
			UPDATE_SYNC
		};
	
		enum entry_location {
			LEFT_MOST = 0,
			FROM_LEFT = 0,
			RIGHT_MOST = 1,
			FROM_RIGHT = 1
		};

		// layout system state +++++

	public:													// types

	public:	// messages (all ValControl-related messages go here!)
		enum message_t {

			// Set value of a control or segment:
			// [your value field(s)] or "_value" (string)
			M_SET_VALUE					= ValControl_message_base,

			// Request for value of control/segment:		
			// [your value field(s)]
			M_GET_VALUE,

			// ... reply to M_GET_VALUE with this:
			// [your value field(s)]
			M_VALUE
		};

	public: // hooks
	
		// * parameter-mode value access

		// called to set the control's value from raw BParameter data
		virtual void setValue(const void* data, size_t size) = 0;

		// called to request the control's value in raw form
		virtual void getValue(void* data, size_t* ioSize) = 0;

		// * string value access

		virtual status_t setValueFrom(const char* text) = 0;

		virtual status_t getString(BString& buffer) = 0;

		// called when a child view's preferred size has changed;
		// it's up to the ValControl to grant the resize request.
		// Return true to notify the child that the request has
		// been granted, or false if denied (the default.)

		virtual bool childResizeRequest(BView* child) { return false; }

	public:													// ctor/dtor/accessors
		virtual ~ValControl();
	
		// value-access methods are left up to the subclasses,
		//   since they'll take varying types of arguments.
		//  (M_SET_VALUE and M_GET_VALUE should always behave
		//   as you'd expect, with a 'value' field of the appropriate
		//   type replacing or returning the current value.) +++++ decrepit
		//
		// Note that all implementations offering pop-up keyboard entry
		// must accept an M_SET_VALUE with a value of B_STRING_TYPE.

		// get/set update mode (determines whether value updates are
		// sent to the target during mouse operations, or only on
		// mouse-up)
		update_mode updateMode() const;
		void setUpdateMode(update_mode mode);

		// +++++ get/set font used by segments
		// (would separate 'value' and 'label' fonts be a good move?)
		//	const BFont* font() const;

		const BFont* labelFont() const; //nyi
		void setLabelFont(const BFont* labelFont); //nyi

		const BFont* valueFont() const; //nyi
		void setValueFont(const BFont* valueFont); //nyi

		// get baseline y offset: this is measured relative to the top of the
		// view
		float baselineOffset() const;

		// segment padding: this amount of padding is added to the
		// right of each segment bounds-rectangle
		float segmentPadding() const;

		// fast drag rate: returns ratio of pixels:units for fast
		// (left-button) dragging
		float fastDragRate() const; //nyi

		// slow drag rate: returns ratio for precise (both/middle-button)
		// dragging
		float slowDragRate() const; //nyi

		// fetch back-buffer
		BView* backBufferView() const; //nyi
		BBitmap* backBuffer() const; //nyi

		// pop up keyboard input field
		// +++++ should this turn into a message?
		virtual void showEditField();

	public: // debugging [23aug99]
		virtual void dump();

	public: // BControl impl.
		// SetValue(), Value() aren't defined, since they only support
		//   32-bit integer values.  TextControl provides a precedent for
		//   this kind of naughtiness.

		// empty implementation (hands off to BControl)
		virtual void SetEnabled(bool enabled);

	public: // BView impl.

		// handle initial layout stuff:
		virtual void AttachedToWindow();
		virtual void AllAttached();

		// paint decorations (& decimal point)
		virtual void Draw(BRect updateRect);

		virtual void drawDecimalPoint(ValCtrlLayoutEntry& entry);

		// handle frame resize (grow backbuffer if need be)
		virtual void FrameResized(float width, float height);

		// calculate minimum size
		virtual void GetPreferredSize(float* outWidth, float* outHeight);
		
		virtual void MakeFocus(bool focused = true);
		
		virtual void MouseDown(BPoint where);

	public:
		virtual void MessageReceived(BMessage* message);

	public:						// archiving/instantiation
		ValControl(BMessage* archive);

		status_t Archive(BMessage* archive, bool deep = true) const;

	protected: // internal ctor/operations
		ValControl(BRect frame, const char* name, const char* label, 
			BMessage* message, align_mode alignMode, align_flags alignFlags,
			update_mode updateMode = UPDATE_ASYNC, bool backBuffer = true);

		// Add segment view (which is responsible for generating its
		// own ValCtrlLayoutEntry)
		void _Add(ValControlSegment* segment, entry_location from,
			uint16 distance = 0);

		// Add general view (manipulator, label, etc.)
		// (the entry's frame rectangle will be filled in)
		// covers ValCtrlLayoutEntry ctor:
		void _Add(ValCtrlLayoutEntry& entry, entry_location from);

		// access child-view ValCtrlLayoutEntry
		// (_IndexOf returns index from left)
		const ValCtrlLayoutEntry& _EntryAt(uint16 offset) const;

		const ValCtrlLayoutEntry& _EntryAt(entry_location from,
			uint16 distance = 0) const;

		uint16 _IndexOf(BView* child) const;

		uint16 CountEntries() const;

	private: // steaming entrails
		// (re-)initialize the backbuffer
		void _AllocBackBuffer(float width, float height);

		// insert a layout entry in ordered position (doesn't call
		// AddChild())
		void _InsertEntry(ValCtrlLayoutEntry& entry, uint16 index);

		// move given entry horizontally (update child view's position
		// and size as well, if any)
		void _SlideEntry(int index, float delta);
	
		// turn entry_location/offset into an index:
		uint16 _LocationToIndex(entry_location from, uint16 distance = 0) const;

		void _GetDefaultEntrySize(ValCtrlLayoutEntry::entry_type type,
			float* outWidth, float* outHeight);

		void _InvalidateAll();
	
	private:
		// the set of visible segments and other child views,
		// in left-to-right. top-to-bottom order
		typedef std::vector<ValCtrlLayoutEntry>		layout_set;
		layout_set			fLayoutSet;

		// true if value has been changed since last request
		// (allows caching of value)
		bool				fDirty;

		// when should messages be sent to the target?
		update_mode			fUpdateMode;

		BFont				fLabelFont;
		BFont				fValueFont;

		align_mode			fAlignMode;
		align_flags			fAlignFlags;

		// the bounds rectangle requested upon construction.
		// if the ALIGN_GROW flag is set, the real bounds
		// rectangle may be wider
		BRect				fOrigBounds;

		// backbuffer (made available to segments for flicker-free
		// drawing)
		bool				fHaveBackBuffer;
		BBitmap*			fBackBuffer;
		BView*				fBackBufferView;

		static const float	fSegmentPadding;

		static const float	fDecimalPointWidth;
		static const float	fDecimalPointHeight;

	private:
		class fnInitChild;
};

__END_CORTEX_NAMESPACE
#endif	// VAL_CONTROL_H