Skip to content

Commit

Permalink
Adding Category selection button
Browse files Browse the repository at this point in the history
* Add a button besides the category text box that opens
  a popup menu showing all categories in "Income" and "Spending"
  submenus.
  Choosing a category puts it in the text box.
  Choosing "Edit categories..." opens the same Categories window also
  available from the MainWindow.

* Introduce a category_type enum to distinguish SPENDING and INCOME.
  Test explicitely against those and don't assume INCOME if it's not
  SPENDING. In future we may have other category types, e.g. TRANSFER
  which only gets set by CapitalBe, not the user.

* To make the connection between category box and its button a tiny bit
  more visible "merge" their widgets borders by having a -2 spacing.

* Do the same for the date box + button everywhere.
  This entails using a separate BStringView for their labels, because
  putting box and button in one BView with the negative spacing prevents
  adding the label in the grid layout via CreateLabelLayoutItem().
  "The BView already has a parent."
  • Loading branch information
humdingerb committed Jun 23, 2024
1 parent 50a3d4f commit e5513c7
Show file tree
Hide file tree
Showing 12 changed files with 367 additions and 64 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SRCS = \
src/CashFlowReport.cpp \
src/Category.cpp \
src/CategoryBox.cpp \
src/CategoryButton.cpp\
src/CategoryWindow.cpp \
src/CheckNumBox.cpp \
src/CheckView.cpp \
Expand Down
183 changes: 183 additions & 0 deletions src/CategoryButton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include "CategoryButton.h"
#include "Database.h"
#include "MainWindow.h"

#include <Bitmap.h>
#include <Catalog.h>
#include <MenuItem.h>
#include <Picture.h>


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "MainWindow"


enum {
M_SHOW_POPUP,
M_CLOSE_POPUP,
M_CATEGORY_CHOSEN
};


CategoryButton::CategoryButton(CategoryBox* categorybox)
: BButton("calenderbutton", "", new BMessage(M_SHOW_POPUP)),
fCategoryBox(categorybox)
{
float height;
fCategoryBox->GetPreferredSize(NULL, &height);
BSize size(height - 2, height);
SetExplicitSize(size);

SetIcon(DrawIcon());
}


void
CategoryButton::AttachedToWindow(void)
{
SetTarget(this);
}


void
CategoryButton::MessageReceived(BMessage* msg)
{
switch (msg->what) {
case M_SHOW_POPUP:
{
ShowPopUpMenu();
break;
}
case M_CLOSE_POPUP:
{
fShowingPopUpMenu = false;
break;
}
case M_CATEGORY_CHOSEN:
{
BString category;
msg->FindString("category", &category);
fCategoryBox->SetText(category);
fCategoryBox->Validate();

break;
}
default:
{
BButton::MessageReceived(msg);
}
}
}


BBitmap*
CategoryButton::DrawIcon()
{
font_height fh;
GetFontHeight(&fh);
float fontHeight = floorf(fh.ascent + fh.descent + fh.leading);
BRect rect(0, 0, fontHeight - 2, fontHeight);

BView* view = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
BBitmap* bitmap = new BBitmap(rect, B_RGBA32, true);
bitmap->Lock();
bitmap->AddChild(view);

view->SetDrawingMode(B_OP_COPY);
view->SetHighUIColor(B_PANEL_BACKGROUND_COLOR);
view->SetLowUIColor(B_PANEL_BACKGROUND_COLOR);

view->FillRect(rect);
view->SetHighUIColor(B_CONTROL_TEXT_COLOR);
view->SetPenSize(1.0);
view->StrokeRect(rect);
view->FillTriangle(rect.LeftBottom(), rect.RightTop(), rect.LeftTop());

BFont font;
view->GetFont(&font);
font.SetFace(B_BOLD_FACE);
font.SetFlags(B_DISABLE_ANTIALIASING);
view->SetFont(&font, B_FONT_FACE | B_FONT_FLAGS);

view->DrawString("̵",
BPoint(
ceilf((rect.Width() * 0.75) - view->StringWidth("̵") / 2 - 1),
ceilf(rect.Height() * 0.75 + fontHeight / 5)
));

view->SetHighUIColor(B_PANEL_BACKGROUND_COLOR);
view->DrawString("+",
BPoint(
ceilf((rect.Width() / 4) - view->StringWidth("+") / 2 + 1),
ceilf(rect.Height() / 5 + fontHeight / 3)
));

view->RemoveSelf();
bitmap->Unlock();
delete view;

return bitmap;
}


void
CategoryButton::ShowPopUpMenu()
{
if (fShowingPopUpMenu)
return;

CategoryPopUp* menu = new CategoryPopUp("PopUpMenu", this);
BMenu* incomeMenu = new BMenu(B_TRANSLATE_CONTEXT("Income", "CommonTerms"));
BMenu* spendingMenu = new BMenu(B_TRANSLATE_CONTEXT("Spending", "CommonTerms"));
BMenuItem* editCategories = new BMenuItem(B_TRANSLATE("Edit categories" B_UTF8_ELLIPSIS),
new BMessage(M_SHOW_CATEGORY_WINDOW));

CppSQLite3Query query = gDatabase.DBQuery(
"SELECT * FROM categorylist ORDER BY name ASC", "CategoryView::CategoryView");
while (!query.eof()) {
int expense = query.getIntField(1);
BString name = DeescapeIllegalCharacters(query.getStringField(0));

BMessage* msg = new BMessage(M_CATEGORY_CHOSEN);
msg->AddString("category", name);

if (expense == SPENDING)
spendingMenu->AddItem(new BMenuItem(name, msg));
else if (expense == INCOME)
incomeMenu->AddItem(new BMenuItem(name, msg));

query.nextRow();
}

menu->AddItem(incomeMenu);
menu->AddItem(spendingMenu);
menu->AddItem(new BSeparatorItem());
menu->AddItem(editCategories);

incomeMenu->SetTargetForItems(this);
spendingMenu->SetTargetForItems(this);
editCategories->SetTarget(Window());

BPoint where = Bounds().LeftTop();
where.x += 10;
where.y += 10;
ConvertToScreen(&where);
menu->Go(where, true, true, true);

fShowingPopUpMenu = true;
}


CategoryPopUp::CategoryPopUp(const char* name, BMessenger target)
:
BPopUpMenu(name, false, false),
fTarget(target)
{
SetAsyncAutoDestruct(true);
}


CategoryPopUp::~CategoryPopUp()
{
fTarget.SendMessage(M_CLOSE_POPUP);
}
37 changes: 37 additions & 0 deletions src/CategoryButton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef CATEGORYBUTTON_H
#define CATEGORYBUTTON_H


#include <Button.h>
#include <PopUpMenu.h>
#include <SupportDefs.h>

#include "CategoryBox.h"


class CategoryButton : public BButton {
public:
CategoryButton(CategoryBox* box);

void AttachedToWindow(void);
virtual void MessageReceived(BMessage* message);

private:
BBitmap* DrawIcon();
void ShowPopUpMenu();

CategoryBox* fCategoryBox;
bool fShowingPopUpMenu;
};


class CategoryPopUp : public BPopUpMenu {
public:
CategoryPopUp(const char* name, BMessenger target);
virtual ~CategoryPopUp();

private:
BMessenger fTarget;
};

#endif // CATEGORYBUTTON_H
8 changes: 4 additions & 4 deletions src/CategoryWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,10 @@ CategoryView::RefreshCategoryList(void)
int expense = query.getIntField(1);
BString name = query.getStringField(0);

if (expense == 0)
if (expense == SPENDING)
fListView->AddUnder(
new CategoryItem(DeescapeIllegalCharacters(name.String())), fSpendingItem);
else
else if (expense == INCOME)
fListView->AddUnder(
new CategoryItem(DeescapeIllegalCharacters(name.String())), fIncomeItem);

Expand Down Expand Up @@ -498,9 +498,9 @@ CategoryRemoveWindow::CategoryRemoveWindow(const char* from, BView* target)
continue;
}

if (expense == 0)
if (expense == SPENDING)
fListView->AddUnder(new CategoryItem(name.String()), fSpendingItem);
else
else if (expense == INCOME)
fListView->AddUnder(new CategoryItem(name.String()), fIncomeItem);

if (name.CountChars() > maxchars) {
Expand Down
43 changes: 29 additions & 14 deletions src/CheckView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Account.h"
#include "CalendarButton.h"
#include "CategoryBox.h"
#include "CategoryButton.h"
#include "CheckNumBox.h"
#include "CheckView.h"
#include "CurrencyBox.h"
Expand Down Expand Up @@ -62,6 +63,8 @@ CheckView::CheckView(const char* name, int32 flags)
categoryLabel->SetExplicitSize(BSize(StringWidth("aVeryLongCategoryName"), B_SIZE_UNSET));
fCategory = new CategoryBox("categoryentry", "", NULL, new BMessage(M_CATEGORY_CHANGED));

CategoryButton* categoryButton = new CategoryButton(fCategory);

BStringView* memoLabel
= new BStringView("memolabel", B_TRANSLATE_CONTEXT("Memo", "CommonTerms"));
memoLabel->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
Expand All @@ -81,30 +84,42 @@ CheckView::CheckView(const char* name, int32 flags)
// #endif

gDatabase.AddObserver(this);

// clang-format off
BView* calendarWidget = new BView("calendarwidget", B_WILL_DRAW);
BLayoutBuilder::Group<>(calendarWidget, B_HORIZONTAL, -2)
.Add(fDate)
.Add(calendarButton)
.End();

BView* categoryWidget = new BView("categorywidget", B_WILL_DRAW);
BLayoutBuilder::Group<>(categoryWidget, B_HORIZONTAL, -2)
.Add(fCategory)
.Add(categoryButton)
.End();

BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(0)
.AddGrid(1.0f, 0.0f)
.SetColumnWeight(2, 2.0f)
.SetColumnWeight(3, 1.0f)
.Add(dateLabel, 0, 0)
.Add(fDate, 0, 1)
.Add(calendarButton, 1, 1)
.Add(typeLabel, 2, 0)
.Add(fType, 2, 1)
.Add(payeeLabel, 3, 0)
.Add(fPayee, 3, 1)
.Add(amountLabel, 4, 0)
.Add(fAmount, 4, 1)
.Add(categoryLabel, 0, 2, 2, 1)
.Add(fCategory, 0, 3, 2, 1)
.Add(memoLabel, 2, 2, 3)
.Add(fMemo, 2, 3, 3)
.Add(fEnter, 5, 1, 1, 3)
.Add(calendarWidget, 0, 1)
.Add(typeLabel, 1, 0)
.Add(fType, 1, 1)
.Add(payeeLabel, 2, 0)
.Add(fPayee, 2, 1)
.Add(amountLabel, 3, 0)
.Add(fAmount, 3, 1)
.Add(categoryLabel, 0, 2)
.Add(categoryWidget, 0, 3)
.Add(memoLabel, 1, 2, 3)
.Add(fMemo, 1, 3, 3)
.Add(fEnter, 4, 1, 1, 3)
.End()
.End();
// clang-format on
}
// clang-format on

CheckView::~CheckView(void) {}

Expand Down
5 changes: 5 additions & 0 deletions src/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class TransactionType;
class TransactionData;
class ScheduledTransData;

enum category_type {
SPENDING = 0,
INCOME
};

BString AccountTypeToString(const AccountType& type);

class Database : public Notifier {
Expand Down
17 changes: 11 additions & 6 deletions src/ReconcileWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,21 @@ ReconcileWindow::ReconcileWindow(const BRect frame, Account* account)
fDate->MakeFocus(true);

// clang-format off
BView* calendarWidget = new BView("calendarwidget", B_WILL_DRAW);
BLayoutBuilder::Group<>(calendarWidget, B_HORIZONTAL, -2)
.Add(fDate)
.Add(calendarButton)
.End();

BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING)
.AddGrid(1.0f, 1.0f)
.Add(dateLabel, 0, 0, 2, 1)
.Add(fDate, 0, 1)
.Add(calendarButton, 1, 1)
.Add(openingLabel, 2, 0)
.Add(fOpening, 2, 1)
.Add(closingLabel, 3, 0)
.Add(fClosing, 3, 1)
.Add(calendarWidget, 0, 1)
.Add(openingLabel, 1, 0)
.Add(fOpening, 1, 1)
.Add(closingLabel, 2, 0)
.Add(fClosing, 2, 1)
.End()
.AddGrid(1.0f, 1.0f)
.Add(chargesLabel, 2, 0)
Expand Down
Loading

0 comments on commit e5513c7

Please sign in to comment.