1 /**
2  * File name: preset_browser_view.h
3  * Project: Geonkick (A percussion synthesizer)
4  *
5  * Copyright (C) 2020 Iurie Nistor <http://iuriepage.wordpress.com>
6  *
7  * This file is part of Geonkick.
8  *
9  * GeonKick is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 
24 #include "preset_browser_view.h"
25 #include "preset_browser_model.h"
26 
27 #include <RkPainter.h>
28 #include <RkImage.h>
29 #include <RkEvent.h>
30 #include <RkButton.h>
31 #include <RkContainer.h>
32 
33 RK_DECLARE_IMAGE_RC(next_page);
34 RK_DECLARE_IMAGE_RC(next_page_hover);
35 RK_DECLARE_IMAGE_RC(next_page_on);
36 RK_DECLARE_IMAGE_RC(prev_page);
37 RK_DECLARE_IMAGE_RC(prev_page_hover);
38 RK_DECLARE_IMAGE_RC(prev_page_on);
39 
PresetBrowserView(GeonkickWidget * parent,PresetBrowserModel * model)40 PresetBrowserView::PresetBrowserView(GeonkickWidget *parent,
41                                      PresetBrowserModel* model)
42         : GeonkickWidget(parent)
43         , browserModel{model}
44         , topPadding{15}
45         , leftPadding{5}
46         , columnWidth{150}
47         , rowHeight{20}
48         , overRow{-1}
49         , overColumn{-1}
50         , nextPresetPageButton{nullptr}
51         , prevPresetPageButton{nullptr}
52         , nextFolderPageButton{nullptr}
53         , prevFolderPageButton{nullptr}
54         , bottomContainer{nullptr}
55 {
56         setSize(620, 290);
57         RK_ACT_BIND(browserModel, folderSelected, RK_ACT_ARGS(PresetFolder*), this, update());
58         RK_ACT_BIND(browserModel, presetSelected, RK_ACT_ARGS(Preset*), this, update());
59         RK_ACT_BIND(browserModel, presetPageChanged, RK_ACT_ARGS(), this, updatePageButtons());
60         RK_ACT_BIND(browserModel, folderPageChanged, RK_ACT_ARGS(), this, updatePageButtons());
61         RK_ACT_BIND(browserModel, folderSelected, RK_ACT_ARGS(PresetFolder*), this, updatePageButtons());
62         RK_ACT_BIND(browserModel, presetSelected, RK_ACT_ARGS(Preset*), this, updatePageButtons());
63 
64         bottomContainer = new RkContainer(this);
65         bottomContainer->setSize({width(), 24});
66         bottomContainer->setPosition({0, height() - 24  - 5});
67         bottomContainer->setHiddenTakesPlace();
68 
69         bottomContainer->addSpace((leftPadding + columnWidth) - 2 * 24 - 10);
70         nextFolderPageButton = new RkButton(this);
71         nextFolderPageButton->setType(RkButton::ButtonType::ButtonPush);
72         nextFolderPageButton->setSize(24, 24);
73         nextFolderPageButton->setImage(RkImage(nextFolderPageButton->size(), RK_IMAGE_RC(next_page)),
74                            RkButton::State::Unpressed);
75         nextFolderPageButton->setImage(RkImage(nextFolderPageButton->size(), RK_IMAGE_RC(next_page_hover)),
76                            RkButton::State::UnpressedHover);
77         nextFolderPageButton->setImage(RkImage(nextFolderPageButton->size(), RK_IMAGE_RC(next_page_on)),
78                            RkButton::State::Pressed);
79         RK_ACT_BIND(nextFolderPageButton, pressed, RK_ACT_ARGS(), browserModel, folderNextPage());
80 
81         prevFolderPageButton = new RkButton(this);
82         prevFolderPageButton->setType(RkButton::ButtonType::ButtonPush);
83         prevFolderPageButton->setSize(24, 24);
84         prevFolderPageButton->setImage(RkImage(prevFolderPageButton->size(), RK_IMAGE_RC(prev_page)),
85                            RkButton::State::Unpressed);
86         prevFolderPageButton->setImage(RkImage(prevFolderPageButton->size(), RK_IMAGE_RC(prev_page_hover)),
87                            RkButton::State::UnpressedHover);
88         prevFolderPageButton->setImage(RkImage(prevFolderPageButton->size(), RK_IMAGE_RC(prev_page_on)),
89                            RkButton::State::Pressed);
90         RK_ACT_BIND(prevFolderPageButton, pressed, RK_ACT_ARGS(), browserModel, folderPreviousPage());
91         bottomContainer->addWidget(prevFolderPageButton);
92         bottomContainer->addSpace(5);
93         bottomContainer->addWidget(nextFolderPageButton);
94 
95         bottomContainer->addSpace(10, Rk::Alignment::AlignRight);
96         nextPresetPageButton = new RkButton(this);
97         nextPresetPageButton->setType(RkButton::ButtonType::ButtonPush);
98         nextPresetPageButton->setSize(24, 24);
99         nextPresetPageButton->setImage(RkImage(nextPresetPageButton->size(), RK_IMAGE_RC(next_page)),
100                            RkButton::State::Unpressed);
101         nextPresetPageButton->setImage(RkImage(nextPresetPageButton->size(), RK_IMAGE_RC(next_page_hover)),
102                            RkButton::State::UnpressedHover);
103         nextPresetPageButton->setImage(RkImage(nextPresetPageButton->size(), RK_IMAGE_RC(next_page_on)),
104                            RkButton::State::Pressed);
105         RK_ACT_BIND(nextPresetPageButton, pressed, RK_ACT_ARGS(), browserModel, nextPresetPage());
106         bottomContainer->addWidget(nextPresetPageButton, Rk::Alignment::AlignRight);
107         bottomContainer->addSpace(5, Rk::Alignment::AlignRight);
108 
109         prevPresetPageButton = new RkButton(this);
110         prevPresetPageButton->setType(RkButton::ButtonType::ButtonPush);
111         prevPresetPageButton->setSize(24, 24);
112         prevPresetPageButton->setImage(RkImage(prevPresetPageButton->size(), RK_IMAGE_RC(prev_page)),
113                            RkButton::State::Unpressed);
114         prevPresetPageButton->setImage(RkImage(prevPresetPageButton->size(), RK_IMAGE_RC(prev_page_hover)),
115                            RkButton::State::UnpressedHover);
116         prevPresetPageButton->setImage(RkImage(prevPresetPageButton->size(), RK_IMAGE_RC(prev_page_on)),
117                            RkButton::State::Pressed);
118         RK_ACT_BIND(prevPresetPageButton, pressed, RK_ACT_ARGS(), browserModel, previousPresetPage());
119         bottomContainer->addWidget(prevPresetPageButton, Rk::Alignment::AlignRight);
120         updatePageButtons();
121         setBackgroundColor({60, 60, 60});
122 }
123 
paintWidget(RkPaintEvent * event)124 void PresetBrowserView::paintWidget(RkPaintEvent *event)
125 {
126         RkImage img(size());
127         RkPainter painter(&img);
128         painter.fillRect(rect(), background());
129         painter.fillRect({0, 0, leftPadding + columnWidth, height()}, {40, 40, 40, 70});
130         painter.setPen(RkColor(50, 50, 50));
131         painter.drawLine({leftPadding + columnWidth, 0}, {leftPadding + columnWidth, height()});
132         auto font = painter.font();
133         font.setSize(12);
134         painter.setFont(font);
135         if (browserModel->columns()) {
136                 int xColumn = leftPadding;
137                 int yRow = topPadding;
138                 for (size_t col = 0; col < browserModel->columns(); col++) {
139                         for (size_t row = 0; row < browserModel->rows(); row++) {
140                                 auto presetName = browserModel->presetName(row, col);
141                                 if (browserModel->isKit(row, col))
142                                         presetName = "KIT: " + presetName;
143                                 auto font = painter.font();
144                                 RkRect textRect(xColumn + 15, yRow, columnWidth, rowHeight);
145                                 painter.setPen(RkColor(60, 60, 60));
146                                 if (browserModel->isSelected(row, col)) {
147                                         font.setWeight(RkFont::Weight::Bold);
148                                         painter.setFont(font);
149                                         painter.setPen(RkColor(230, 230, 230));
150                                 } else {
151                                         font.setWeight(RkFont::Weight::Normal);
152                                         painter.setFont(font);
153                                         painter.setPen(RkColor(180, 180, 180));
154                                 }
155 
156                                 if (static_cast<decltype(row)>(overRow) == row
157                                     && static_cast<decltype(col)>(overColumn) == col) {
158                                         painter.setPen(RkColor(255, 255, 255));
159                                 }
160                                 painter.drawText(textRect, presetName, Rk::Alignment::AlignLeft);
161                                 yRow += rowHeight;
162                         }
163                         xColumn += columnWidth;
164                         yRow = topPadding;
165                 }
166         }
167         RkPainter paint(this);
168         paint.drawImage(img, 0, 0);
169 }
170 
mouseButtonPressEvent(RkMouseEvent * event)171 void PresetBrowserView::mouseButtonPressEvent(RkMouseEvent *event)
172 {
173         browserModel->select((event->y() - topPadding) / rowHeight,
174                              (event->x() - leftPadding) / columnWidth);
175 }
176 
mouseMoveEvent(RkMouseEvent * event)177 void PresetBrowserView::mouseMoveEvent(RkMouseEvent *event)
178 {
179         auto overColumnTmp = (event->x() - leftPadding) / columnWidth;
180         bool toUpdate = false;
181         if (overColumnTmp != overColumn) {
182                 overColumn = overColumnTmp;
183                 toUpdate = true;
184         }
185 
186         auto overRowTmp = (event->y() - topPadding) / rowHeight;
187         if (overRowTmp != overRow) {
188                 overRow = overRowTmp;
189                 toUpdate = true;
190         }
191 
192         if (toUpdate)
193                 update();
194 }
195 
updatePageButtons()196 void PresetBrowserView::updatePageButtons()
197 {
198         prevFolderPageButton->show(browserModel->folderPages() > 1);
199         nextFolderPageButton->show(browserModel->folderPages() > 1);
200         prevPresetPageButton->show(browserModel->presetPages() > 1);
201         nextPresetPageButton->show(browserModel->presetPages() > 1);
202         bottomContainer->update();
203         update();
204 }
205 
206