Abstract common features into ReplicantView

This should make it easier to make consistent replicants of the same
style. Also adds APP_SIGNATURE and APP_NAME defines.
This commit is contained in:
Jaidyn Ann 2022-05-27 01:21:01 -05:00
parent a1b5bf42db
commit c91b665253
10 changed files with 301 additions and 205 deletions

View File

@ -36,6 +36,7 @@ SRCS = src/App.cpp \
src/LyricsView.cpp \
src/MainWindow.cpp \
src/MediaPlayer.cpp \
src/ReplicantView.cpp \
src/Song.cpp
# Specify the resource definition files to use. Full or relative paths can be
@ -97,7 +98,9 @@ LOCALES =
# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
# "-DDEBUG" on the compiler's command line.
DEFINES =
DEFINES = BUILD_DATE="\"$(shell date +"%Y-%m-%d %H:%M")\"" \
APP_NAME="\"$(NAME)"\" \
APP_SIGNATURE="\"$(APP_MIME_SIG)"\"
# Specify the warning level. Either NONE (suppress all warnings),
# ALL (enable all warnings), or leave blank (enable default warnings).

View File

@ -5,32 +5,15 @@
#include "App.h"
#include <iostream>
#include "MainWindow.h"
BString
get_string_mediaplayer(const char* attribute)
{
BMessage message, reply;
message.what = B_GET_PROPERTY;
message.AddSpecifier(attribute);
message.AddSpecifier("Window", 0);
BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(&message, &reply);
BString result;
reply.FindString("result", &result);
return result;
}
App::App()
:
BApplication("application/x-vnd.mediamonitor")
BApplication(APP_SIGNATURE)
{
MainWindow* win = new MainWindow();
win->SetPulseRate(5000000);
win->SetPulseRate(2500000);
win->Show();
}

View File

@ -14,32 +14,20 @@
CoverView::CoverView(BRect frame)
:
BView(frame, "Cover", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_PULSE_NEEDED)
ReplicantView(frame, "Cover", B_FOLLOW_LEFT)
{
BRect dragRect(0, 0, 10, frame.Height());
fDragger = new BDragger(dragRect, this,
B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW);
fDragger->SetViewColor(B_TRANSPARENT_COLOR);
AddChild(fDragger);
fMediaPlayer = new MediaPlayer(0);
fCover = NULL;
SetViewColor(B_TRANSPARENT_COLOR);
fCover = NULL;
Pulse();
}
CoverView::CoverView(BMessage* data)
:
BView(data)
ReplicantView(data)
{
BMessage mediaplayer;
data->FindMessage("mediaplayer", &mediaplayer);
fMediaPlayer = new MediaPlayer(&mediaplayer);
fCover = NULL;
SetViewColor(B_TRANSPARENT_COLOR);
fCover = NULL;
Pulse();
}
@ -47,13 +35,10 @@ CoverView::CoverView(BMessage* data)
status_t
CoverView::Archive(BMessage* data, bool deep) const
{
status_t status = BView::Archive(data, deep);
status_t status = ReplicantView::Archive(data, deep);
BMessage mediaPlayer;
fMediaPlayer->Archive(&mediaPlayer);
data->AddMessage("mediaplayer", &mediaPlayer);
data->AddString("class", "CoverView");
data->AddString("add_on", "application/x-vnd.mediamonitor");
data->AddString("add_on", APP_SIGNATURE);
return status;
}
@ -71,19 +56,23 @@ void
CoverView::Pulse()
{
Song song;
// No song playing
if (fMediaPlayer->CurrentItem(&song, false) == false) {
if (fCurrentSong.InitCheck()) {
fCurrentSong = song;
delete fCover;
fCover = NULL;
Invalidate();
SetInactive(true);
}
// New song
} else if (song != fCurrentSong) {
fCurrentSong = song;
if (fCover != NULL)
delete fCover;
fCover = song.Cover();
Invalidate();
SetInactive(false);
}
}
@ -92,7 +81,6 @@ void
CoverView::Draw(BRect updateRect)
{
BView::Draw(updateRect);
if (fCover != NULL && fCover->IsValid())
DrawBitmap(fCover, Bounds());
}

View File

@ -5,15 +5,14 @@
#ifndef COVERVIEW_H
#define COVERVIEW_H
#include <View.h>
#include "ReplicantView.h"
#include "Song.h"
class BDragger;
class MediaPlayer;
class CoverView : public BView {
class CoverView : public ReplicantView {
public:
CoverView(BRect frame);
CoverView(BMessage* archive);
@ -28,10 +27,7 @@ public:
private:
void _Init(BRect frame);
MediaPlayer* fMediaPlayer;
Song fCurrentSong;
BDragger* fDragger;
BBitmap* fCover;
};

View File

@ -5,9 +5,7 @@
#include "LyricsView.h"
#include <Dragger.h>
#include <MenuItem.h>
#include <Messenger.h>
#include <PopUpMenu.h>
#include <ScrollView.h>
#include <Window.h>
@ -35,7 +33,7 @@ LyricsTextView::Archive(BMessage* data, bool deep) const
{
status_t status = BTextView::Archive(data, deep);
data->AddString("class", "LyricsTextView");
data->AddString("add_on", "application/x-vnd.mediamonitor");
data->AddString("add_on", APP_SIGNATURE);
return status;
}
@ -65,14 +63,8 @@ LyricsTextView::MouseDown(BPoint where)
LyricsView::LyricsView(BRect frame)
:
BView(frame, "Lyrics", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_PULSE_NEEDED)
ReplicantView(frame, "Lyrics", B_FOLLOW_LEFT)
{
BRect dragRect(0, 0, 10, frame.Height());
fDragger = new BDragger(dragRect, this,
B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_WILL_DRAW);
fDragger->SetViewColor(B_TRANSPARENT_COLOR);
AddChild(fDragger);
BRect textRect(0, 0, Bounds().Width(), Bounds().Height() - 10);
fTextView = new LyricsTextView(textRect, "lyricsText", textRect,
B_FOLLOW_ALL, B_WILL_DRAW);
@ -85,41 +77,28 @@ LyricsView::LyricsView(BRect frame)
AddChild(fScrollView);
fAutoScroll = false;
fTransparentInactivity = true;
fTransparentDragger = false;
fFgColor = ui_color(B_PANEL_TEXT_COLOR);
fBgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
fMediaPlayer = new MediaPlayer(0);
_Init(frame);
}
LyricsView::LyricsView(BMessage* data)
:
BView(data)
ReplicantView(data)
{
fAutoScroll = false;
fTransparentInactivity = true;
fTransparentDragger = false;
fFgColor = ui_color(B_PANEL_TEXT_COLOR);
fBgColor = ui_color(B_PANEL_BACKGROUND_COLOR);
fTextView = dynamic_cast<LyricsTextView*>(FindView("lyricsText"));
fScrollView = dynamic_cast<BScrollView*>(FindView("scrollView"));
fDragger = dynamic_cast<BDragger*>(FindView("_dragger_"));
data->FindColor("background_color", &fBgColor);
data->FindColor("foreground_color", &fFgColor);
data->FindBool("autoscroll", &fAutoScroll);
data->FindBool("transparent_inactivity", &fTransparentInactivity);
data->FindBool("transparent_dragger", &fTransparentDragger);
BMessage mediaplayer;
data->FindMessage("mediaplayer", &mediaplayer);
fMediaPlayer = new MediaPlayer(&mediaplayer);
_Init(Frame());
}
@ -128,20 +107,14 @@ LyricsView::LyricsView(BMessage* data)
status_t
LyricsView::Archive(BMessage* data, bool deep) const
{
status_t status = BView::Archive(data, deep);
status_t status = ReplicantView::Archive(data, deep);
BMessage mediaPlayer;
fMediaPlayer->Archive(&mediaPlayer);
data->AddMessage("mediaplayer", &mediaPlayer);
data->AddColor("background_color", fBgColor);
data->AddColor("foreground_color", fFgColor);
data->AddBool("autoscroll", fAutoScroll);
data->AddBool("transparent_inactivity", fTransparentInactivity);
data->AddBool("transparent_dragger", fTransparentDragger);
data->AddString("class", "LyricsView");
data->AddString("add_on", "application/x-vnd.mediamonitor");
data->AddString("add_on", APP_SIGNATURE);
return status;
}
@ -179,19 +152,8 @@ LyricsView::MessageReceived(BMessage* msg)
case LYRICS_AUTO_SCROLL:
fAutoScroll = !fAutoScroll;
break;
case LYRICS_TRANSPARENTLY_INACTIVE:
case LYRICS_TRANSPARENTLY_DRAG: {
if (msg->what == LYRICS_TRANSPARENTLY_INACTIVE)
fTransparentInactivity = !fTransparentInactivity;
if (msg->what == LYRICS_TRANSPARENTLY_DRAG)
fTransparentDragger = !fTransparentDragger;
if (fCurrentSong.InitCheck() == false)
_ClearText();
break;
}
default:
BView::MessageReceived(msg);
ReplicantView::MessageReceived(msg);
break;
}
}
@ -201,19 +163,22 @@ void
LyricsView::Pulse()
{
Song song;
// No song
if (fMediaPlayer->CurrentItem(&song, fAutoScroll) == false) {
if (fCurrentSong.InitCheck()) {
fCurrentSong = song;
_ClearText();
SetInactive(true);
}
return;
}
// New song
if (song != fCurrentSong) {
fCurrentSong = song;
BString lyrics;
song.Lyrics(&lyrics);
_SetText(lyrics.String());
fTextView->SetText(lyrics.String());
SetInactive(false);
}
if (fAutoScroll) {
@ -224,59 +189,66 @@ LyricsView::Pulse()
}
void
LyricsView::MouseDown(BPoint where)
BPopUpMenu*
LyricsView::RightClickPopUp(BPopUpMenu* menu)
{
uint32 buttons = 0;
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
if (menu == NULL)
menu = new BPopUpMenu("rightClickPopUp");
if (buttons & B_SECONDARY_MOUSE_BUTTON)
_RightClickPopUp()->Go(ConvertToScreen(where), true, false, true);
BMenuItem* copy =
new BMenuItem("Copy", new BMessage(B_COPY), 'C', B_COMMAND_KEY);
int32 start = -1, end = -1;
fTextView->GetSelection(&start, &end);
copy->SetEnabled(start >= 0 && end > 0);
copy->SetTarget(fTextView);
menu->AddItem(copy);
BMenuItem* selectAll = new BMenuItem("Select all",
new BMessage(B_SELECT_ALL), 'A', B_COMMAND_KEY);
selectAll->SetTarget(fTextView);
menu->AddItem(selectAll);
menu->AddSeparatorItem();
BMenuItem* autoScroll = new BMenuItem("Auto-scroll",
new BMessage(LYRICS_AUTO_SCROLL));
autoScroll->SetMarked(fAutoScroll);
autoScroll->SetTarget(this);
menu->AddItem(autoScroll);
return ReplicantView::RightClickPopUp(menu);
}
void
LyricsView::SetInactive(bool inactive)
{
if (inactive && fTransparentInactivity && !fScrollView->IsHidden())
fScrollView->Hide();
else if (!inactive && fScrollView->IsHidden())
fScrollView->Show();
if (inactive) {
fTextView->SetText("No lyrics to display!");
fTextView->SetAlignment(B_ALIGN_CENTER);
} else
fTextView->SetAlignment(B_ALIGN_LEFT);
ReplicantView::SetInactive(inactive);
}
void
LyricsView::_Init(BRect frame)
{
_ClearText();
SetInactive(true);
_UpdateColors();
Pulse();
}
void
LyricsView::_SetText(const char* text)
{
if (fScrollView->IsHidden())
fScrollView->Show();
if (fDragger->IsHidden())
fDragger->Show();
fTextView->SetText(text);
fTextView->SetAlignment(B_ALIGN_LEFT);
}
void
LyricsView::_ClearText()
{
if (fTransparentInactivity) {
if (fScrollView->IsHidden())
fScrollView->Hide();
if (fDragger->IsHidden() && fTransparentDragger)
fDragger->Hide();
} else {
if (fScrollView->IsHidden())
fScrollView->Show();
if (fDragger->IsHidden())
fDragger->Show();
}
fTextView->SetText("No lyrics to display!");
fTextView->SetAlignment(B_ALIGN_CENTER);
}
void
LyricsView::_UpdateColors()
{
@ -299,53 +271,6 @@ LyricsView::_UpdateColors()
}
BPopUpMenu*
LyricsView::_RightClickPopUp()
{
BPopUpMenu* menu = new BPopUpMenu("rightClickPopUp");
menu->SetRadioMode(false);
BMenuItem* copy =
new BMenuItem("Copy", new BMessage(B_COPY), 'C', B_COMMAND_KEY);
int32 start = -1, end = -1;
fTextView->GetSelection(&start, &end);
copy->SetEnabled(start >= 0 && end > 0);
copy->SetTarget(fTextView);
menu->AddItem(copy);
BMenuItem* selectAll = new BMenuItem("Select all",
new BMessage(B_SELECT_ALL), 'A', B_COMMAND_KEY);
selectAll->SetTarget(fTextView);
menu->AddItem(selectAll);
menu->AddSeparatorItem();
BMenuItem* autoScroll = new BMenuItem("Auto-scroll",
new BMessage(LYRICS_AUTO_SCROLL));
autoScroll->SetMarked(fAutoScroll);
autoScroll->SetTarget(this);
menu->AddItem(autoScroll);
BMenu* hideMenu = new BMenu("Hide when inactive");
menu->AddItem(hideMenu);
BMenuItem* hideInactive = hideMenu->Superitem();
hideInactive->SetMessage(new BMessage(LYRICS_TRANSPARENTLY_INACTIVE));
hideInactive->SetMarked(fTransparentInactivity);
hideInactive->SetTarget(this);
BMenuItem* hideDragger = new BMenuItem("… including the dragger",
new BMessage(LYRICS_TRANSPARENTLY_DRAG));
hideDragger->SetMarked(fTransparentDragger);
hideDragger->SetTarget(this);
hideMenu->AddItem(hideDragger);
return menu;
}
float
LyricsView::_GetPositionProportion()
{

View File

@ -7,6 +7,7 @@
#include <TextView.h>
#include "ReplicantView.h"
#include "Song.h"
class BDragger;
@ -35,41 +36,34 @@ public:
};
class LyricsView : public BView {
class LyricsView : public ReplicantView {
public:
LyricsView(BRect frame);
LyricsView(BMessage* archive);
LyricsView(BRect frame);
LyricsView(BMessage* archive);
virtual status_t Archive(BMessage* data, bool deep = true) const;
static LyricsView* Instantiate(BMessage* data);
virtual status_t Archive(BMessage* data, bool deep = true) const;
static LyricsView* Instantiate(BMessage* data);
virtual void MessageReceived(BMessage* msg);
virtual void Pulse();
virtual void MessageReceived(BMessage* msg);
virtual void Pulse();
virtual void MouseDown(BPoint where);
virtual BPopUpMenu* RightClickPopUp(BPopUpMenu* menu = NULL);
virtual void SetInactive(bool inactive);
private:
void _Init(BRect frame);
void _Init(BRect frame);
void _SetText(const char* text);
void _ClearText();
void _UpdateColors();
void _UpdateColors();
float _GetPositionProportion();
BPopUpMenu* _RightClickPopUp();
float _GetPositionProportion();
MediaPlayer* fMediaPlayer;
Song fCurrentSong;
LyricsTextView* fTextView;
BScrollView* fScrollView;
BDragger* fDragger;
bool fAutoScroll;
bool fTransparentInactivity;
bool fTransparentDragger;
rgb_color fBgColor;
rgb_color fFgColor;

View File

@ -14,7 +14,7 @@
MainWindow::MainWindow()
:
BWindow(BRect(BPoint(0,0),BSize(500.0, 500.0)), "MediaMonitor",
BWindow(BRect(BPoint(0,0),BSize(500.0, 500.0)), APP_NAME,
B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_QUIT_ON_WINDOW_CLOSE)
{
SetPulseRate(0);

View File

@ -31,7 +31,7 @@ MediaPlayer::Archive(BMessage* data, bool deep) const
status_t status = BArchivable::Archive(data, deep);
data->AddInt32("_window", fWindowIndex);
data->AddString("class", "MediaPlayer");
data->AddString("add_on", "application/x-vnd.mediamonitor");
data->AddString("add_on", APP_SIGNATURE);
return status;
}

148
src/ReplicantView.cpp Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "ReplicantView.h"
#include <Dragger.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <Window.h>
#include "MediaPlayer.h"
ReplicantView::ReplicantView(BRect frame, const char* name, uint32 draggerPlacement)
:
BView(frame, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_PULSE_NEEDED)
{
BRect dragRect(frame.Width() - 10, 0, frame.Width(), frame.Height());
uint32 dragFollow = B_FOLLOW_RIGHT;
if (draggerPlacement & _VIEW_LEFT_) {
dragRect = BRect(0, 0, 10, frame.Height());
dragFollow = B_FOLLOW_LEFT;
}
fDragger = new BDragger(dragRect, this, dragFollow | B_FOLLOW_BOTTOM, B_WILL_DRAW);
fDragger->SetViewColor(B_TRANSPARENT_COLOR);
AddChild(fDragger);
fTransparentInactivity = true;
fTransparentDragger = false;
fInactive = true;
fMediaPlayer = new MediaPlayer(0);
}
ReplicantView::ReplicantView(BMessage* data)
:
BView(data)
{
BMessage mediaplayer;
data->FindMessage("mediaplayer", &mediaplayer);
fMediaPlayer = new MediaPlayer(&mediaplayer);
fDragger = dynamic_cast<BDragger*>(FindView("_dragger_"));
fTransparentInactivity = data->GetBool("transparent_inactivity", true);
fTransparentDragger = data->GetBool("transparent_dragger", false);
fInactive = true;
}
status_t
ReplicantView::Archive(BMessage* data, bool deep) const
{
status_t status = BView::Archive(data, deep);
BMessage mediaPlayer;
fMediaPlayer->Archive(&mediaPlayer);
data->AddMessage("mediaplayer", &mediaPlayer);
data->AddBool("transparent_inactivity", fTransparentInactivity);
data->AddBool("transparent_dragger", fTransparentDragger);
data->AddString("class", "ReplicantView");
data->AddString("add_on", APP_SIGNATURE);
return status;
}
ReplicantView*
ReplicantView::Instantiate(BMessage* data)
{
if (!validate_instantiation(data, "ReplicantView"))
return NULL;
return new ReplicantView(data);
}
void
ReplicantView::MessageReceived(BMessage* msg)
{
switch (msg->what)
{
case REPL_TRANSPARENTLY_INACTIVE:
case REPL_TRANSPARENTLY_DRAG: {
if (msg->what == REPL_TRANSPARENTLY_INACTIVE)
fTransparentInactivity = !fTransparentInactivity;
if (msg->what == REPL_TRANSPARENTLY_DRAG)
fTransparentDragger = !fTransparentDragger;
SetInactive(fInactive);
break;
}
default:
BView::MessageReceived(msg);
break;
}
}
void
ReplicantView::MouseDown(BPoint where)
{
uint32 buttons = 0;
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
if (buttons & B_SECONDARY_MOUSE_BUTTON)
RightClickPopUp()->Go(ConvertToScreen(where), true, false, true);
}
BPopUpMenu*
ReplicantView::RightClickPopUp(BPopUpMenu* menu)
{
if (menu == NULL)
menu = new BPopUpMenu("rightClickPopUp");
menu->SetRadioMode(false);
BMenu* hideMenu = new BMenu("Hide when inactive");
menu->AddItem(hideMenu);
BMenuItem* hideInactive = hideMenu->Superitem();
hideInactive->SetMessage(new BMessage(REPL_TRANSPARENTLY_INACTIVE));
hideInactive->SetMarked(fTransparentInactivity);
hideInactive->SetTarget(this);
BMenuItem* hideDragger = new BMenuItem("… including the dragger",
new BMessage(REPL_TRANSPARENTLY_DRAG));
hideDragger->SetMarked(fTransparentDragger);
hideDragger->SetTarget(this);
hideMenu->AddItem(hideDragger);
return menu;
}
void
ReplicantView::SetInactive(bool inactive)
{
fInactive = inactive;
if (inactive && fTransparentInactivity)
if (!fDragger->IsHidden() && fTransparentDragger)
fDragger->Hide();
if (fDragger->IsHidden() && (!fTransparentDragger || !fTransparentInactivity))
fDragger->Show();
Invalidate();
}

59
src/ReplicantView.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright 2022, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef REPLICANTVIEW_H
#define REPLICANTVIEW_H
#include <View.h>
class BDragger;
class BPopUpMenu;
class MediaPlayer;
enum {
MP_AUDIO_WINDOW = 'mpaw',
MP_VIDEO_WINDOW = 'mpvw',
MP_NEWEST_WINDOW = 'mpnw'
};
enum {
REPL_TRANSPARENTLY_INACTIVE = 'rtti',
REPL_TRANSPARENTLY_DRAG = 'rttd'
};
/* Base class for each replicant, containing features need for (most) of them:
- Dragger where you'd expect it
- Transparency/hiding during inactivity
- Right-click menu with common options
- Setting custom background color (by drag)
- MediaPlayer object */
class ReplicantView : public BView {
public:
ReplicantView(BRect frame, const char* name, uint32 draggerPlacement);
ReplicantView(BMessage* archive);
virtual status_t Archive(BMessage* data, bool deep = true) const;
static ReplicantView* Instantiate(BMessage* data);
virtual void MessageReceived(BMessage* msg);
virtual void MouseDown(BPoint where);
// Populates the given menu with default items
virtual BPopUpMenu* RightClickPopUp(BPopUpMenu* menu = NULL);
// Set inactivity state, re-render accordingly
virtual void SetInactive(bool inactive);
MediaPlayer* fMediaPlayer;
BDragger* fDragger;
bool fInactive;
bool fTransparentInactivity;
bool fTransparentDragger;
};
#endif // REPLICANTVIEW_H