A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 269 lines 9.0 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * This file has been copied from Nokia's Qt Examples, with minor modifications 11 * made available under the LGPL version 2.1, as the original file was licensed 12 * 13 **************************************************************************** 14 **************************************************************************** 15** 16** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 17** All rights reserved. 18** Contact: Nokia Corporation (qt-info@nokia.com) 19** 20** This file is part of the examples of the Qt Toolkit. 21** 22** GNU Lesser General Public License Usage 23** Alternatively, this file may be used under the terms of the GNU Lesser 24** General Public License version 2.1 as published by the Free Software 25** Foundation and appearing in the file LICENSE.LGPL included in the 26** packaging of this file. Please review the following information to 27** ensure the GNU Lesser General Public License version 2.1 requirements 28** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 29** 30** In addition, as a special exception, Nokia gives you certain additional 31** rights. These rights are described in the Nokia Qt LGPL Exception 32** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 33** 34****************************************************************************/ 35 36#include <QtGui> 37#include <QApplication> 38 39#include "codeeditor.h" 40 41CodeEditor::CodeEditor(QWidget *parent) 42 : QPlainTextEdit(parent), completer(this) 43{ 44 lineNumberArea = new LineNumberArea(this); 45 46 connect(this, SIGNAL(blockCountChanged(int)), 47 this, SLOT(updateLineNumberAreaWidth(int))); 48 connect(this, SIGNAL(updateRequest(QRect,int)), 49 this, SLOT(updateLineNumberArea(QRect,int))); 50 51 updateLineNumberAreaWidth(0); 52 53 QObject::connect(this, SIGNAL(cursorPositionChanged()), 54 this, SLOT(cursorMoved())); 55 completer.hide(); 56 settings.beginGroup("CodeEditor"); 57} 58 59int CodeEditor::lineNumberAreaWidth() 60{ 61 int digits = 1; 62 int max = qMax(1, blockCount()); 63 while (max >= 10) { 64 max /= 10; 65 ++digits; 66 } 67 68 int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; 69 70 return space; 71} 72 73 74void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) 75{ 76 setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); 77} 78 79void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) 80{ 81 if (dy) 82 lineNumberArea->scroll(0, dy); 83 else 84 lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); 85 86 if (rect.contains(viewport()->rect())) 87 updateLineNumberAreaWidth(0); 88} 89 90void CodeEditor::cursorMoved() 91{ 92 /* Closing the completer if the cursor has moved out of its bounds */ 93 if(completer.isVisible()) 94 { 95 if(document()->toPlainText().length() > docLength) 96 tagEnd++; 97 else if(document()->toPlainText().length() < docLength) 98 tagEnd--; 99 100 if(textCursor().position() < tagBegin 101 || textCursor().position() > tagEnd) 102 { 103 completer.hide(); 104 } 105 } 106} 107 108void CodeEditor::insertTag() 109{ 110 /* Clearing the typed tag and inserting one from the completer */ 111 QTextCursor at(document()); 112 at.setPosition(tagBegin, QTextCursor::MoveAnchor); 113 while(document()->characterAt(at.position()) == QChar('%') 114 || document()->characterAt(at.position()) == '?') 115 at.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 1); 116 117 at.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 118 tagEnd - at.position()); 119 at.removeSelectedText(); 120 121 at.insertText(completer.currentItem()->text(0)); 122 123 completer.hide(); 124} 125 126void CodeEditor::resizeEvent(QResizeEvent *e) 127{ 128 QPlainTextEdit::resizeEvent(e); 129 130 QRect cr = contentsRect(); 131 lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), 132 lineNumberAreaWidth(), cr.height())); 133} 134 135void CodeEditor::keyPressEvent(QKeyEvent *event) 136{ 137 138 if(!settings.value("completeSyntax", true).toBool()) 139 { 140 QPlainTextEdit::keyPressEvent(event); 141 return; 142 } 143 144 if(completer.isVisible()) 145 { 146 /* Handling the completer */ 147 if(event->key() == Qt::Key_Up) 148 { 149 /* Up/down arrow presses get sent right along to the completer 150 * to navigate through the list 151 */ 152 if(completer.currentIndex().row() > 0) 153 QApplication::sendEvent(&completer, event); 154 } 155 else if(event->key() == Qt::Key_Down) 156 { 157 if(completer.currentIndex().row() 158 < completer.topLevelItemCount() - 1) 159 QApplication::sendEvent(&completer, event); 160 } 161 else if(event->key() == Qt::Key_Backspace 162 || event->key() == Qt::Key_Delete) 163 { 164 docLength = document()->toPlainText().length(); 165 QPlainTextEdit::keyPressEvent(event); 166 167 QString filterText; 168 169 for(int i = tagBegin; i < tagEnd; i++) 170 { 171 QChar c = document()->characterAt(i); 172 if(c != '%' && c != '?') 173 filterText.append(c); 174 } 175 176 completer.filter(filterText); 177 } 178 else if(event->key() == Qt::Key_Escape) 179 { 180 /* Escape hides the completer */ 181 completer.hide(); 182 QPlainTextEdit::keyPressEvent(event); 183 } 184 else if(event->key() == Qt::Key_Return) 185 { 186 /* The enter key inserts the currently selected tag */ 187 insertTag(); 188 } 189 else if(event->key() == Qt::Key_Question) 190 { 191 /* The question mark doesn't filter the list */ 192 docLength = document()->toPlainText().length(); 193 QPlainTextEdit::keyPressEvent(event); 194 } 195 else if(event->key() == Qt::Key_Left 196 || event->key() == Qt::Key_Right) 197 { 198 /* Left and right keys shouldn't affect tagEnd */ 199 QPlainTextEdit::keyPressEvent(event); 200 } 201 else 202 { 203 /* Otherwise, we have to filter the list */ 204 docLength = document()->toPlainText().length(); 205 QPlainTextEdit::keyPressEvent(event); 206 207 QString filterText; 208 209 for(int i = tagBegin; i < tagEnd; i++) 210 { 211 QChar c = document()->characterAt(i); 212 if(c != '%' && c != '?') 213 filterText.append(c); 214 } 215 216 completer.filter(filterText); 217 } 218 } 219 else 220 { 221 /* Deciding whether to show the completer */ 222 QPlainTextEdit::keyPressEvent(event); 223 if(event->key() == Qt::Key_Percent) 224 { 225 tagBegin = textCursor().position(); 226 tagEnd = textCursor().position(); 227 completer.filter(""); 228 completer.move(cursorRect().left(), cursorRect().bottom()); 229 if(completer.frameGeometry().right() > width()) 230 completer.move(width() - completer.width(), completer.y()); 231 if(completer.frameGeometry().bottom() > height()) 232 completer.move(completer.x(), 233 cursorRect().top() - completer.height()); 234 completer.show(); 235 } 236 } 237 238} 239 240void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) 241{ 242 QPainter painter(lineNumberArea); 243 painter.fillRect(event->rect(), Qt::lightGray); 244 245 QTextBlock block = firstVisibleBlock(); 246 int blockNumber = block.blockNumber(); 247 int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); 248 int bottom = top + (int) blockBoundingRect(block).height(); 249 250 while (block.isValid() && top <= event->rect().bottom()) { 251 if (block.isVisible() && bottom >= event->rect().top()) { 252 QString number = QString::number(blockNumber + 1); 253 /* Drawing an error circle if necessary */ 254 if(errors.contains(blockNumber + 1)) 255 { 256 painter.fillRect(QRect(0, top, lineNumberArea->width(), 257 fontMetrics().height()), errorColor); 258 } 259 painter.setPen(Qt::black); 260 painter.drawText(0, top, lineNumberArea->width(), 261 fontMetrics().height(), Qt::AlignRight, number); 262 } 263 264 block = block.next(); 265 top = bottom; 266 bottom = top + (int) blockBoundingRect(block).height(); 267 ++blockNumber; 268 } 269}